From 75433a670e0880c4d23d5178b073836de3628547 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 12 Nov 2017 14:17:05 +1000 Subject: [PATCH 001/139] Initial work on adding support for mini_al. --- src/audio.c | 412 +- src/external/mini_al.c | 2 + src/external/mini_al.h | 10437 +++++++++++++++++++++++++++++++++++++++ src/raylib.h | 2 + 4 files changed, 10842 insertions(+), 11 deletions(-) create mode 100644 src/external/mini_al.c create mode 100644 src/external/mini_al.h diff --git a/src/audio.c b/src/audio.c index 06af8ed4..a5f117b5 100644 --- a/src/audio.c +++ b/src/audio.c @@ -72,6 +72,8 @@ #define SUPPORT_FILEFORMAT_MOD //------------------------------------------------- +#define USE_MINI_AL 1 // Set to 1 to use mini_al; 0 to use OpenAL. + #if defined(AUDIO_STANDALONE) #include "audio.h" #include // Required for: va_list, va_start(), vfprintf(), va_end() @@ -80,17 +82,21 @@ #include "utils.h" // Required for: fopen() Android mapping #endif -#if defined(__APPLE__) - #include "OpenAL/al.h" // OpenAL basic header - #include "OpenAL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) -#else - #include "AL/al.h" // OpenAL basic header - #include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) - //#include "AL/alext.h" // OpenAL extensions header, required for AL_EXT_FLOAT32 and AL_EXT_MCFORMATS -#endif +//#if USE_MINI_AL + #include "external/mini_al.h" // Implemented in mini_al.c. Cannot implement this here because it conflicts with Win32 APIs such as CloseWindow(), etc. +//#else + #if defined(__APPLE__) + #include "OpenAL/al.h" // OpenAL basic header + #include "OpenAL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) + #else + #include "AL/al.h" // OpenAL basic header + #include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) + //#include "AL/alext.h" // OpenAL extensions header, required for AL_EXT_FLOAT32 and AL_EXT_MCFORMATS + #endif -// OpenAL extension: AL_EXT_FLOAT32 - Support for 32bit float samples -// OpenAL extension: AL_EXT_MCFORMATS - Support for multi-channel formats (Quad, 5.1, 6.1, 7.1) + // OpenAL extension: AL_EXT_FLOAT32 - Support for 32bit float samples + // OpenAL extension: AL_EXT_MCFORMATS - Support for multi-channel formats (Quad, 5.1, 6.1, 7.1) +//#endif #include // Required for: malloc(), free() #include // Required for: strcmp(), strncmp() @@ -200,10 +206,195 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo //---------------------------------------------------------------------------------- // Module Functions Definition - Audio Device initialization and Closing //---------------------------------------------------------------------------------- +#if USE_MINI_AL +#define DEVICE_FORMAT mal_format_f32 +#define DEVICE_CHANNELS 2 +#define DEVICE_SAMPLE_RATE 44100 + +typedef struct SoundInternal SoundInternal; +struct SoundInternal +{ + mal_format format; + mal_uint32 channels; + mal_uint32 sampleRate; + mal_uint32 frameCount; + mal_uint32 frameCursorPos; // Keeps track of the next frame to read when mixing + float volume; + float pitch; + bool playing; + bool paused; + bool looping; + SoundInternal* next; + SoundInternal* prev; + mal_uint8 data[1]; // Raw audio data. +}; + +static mal_context context; +static mal_device device; +static mal_bool32 isAudioInitialized = MAL_FALSE; +static float masterVolume = 1; +static mal_mutex soundLock; +static SoundInternal* firstSound; // Sounds are tracked in a linked list. +static SoundInternal* lastSound; + +static void AppendSound(SoundInternal* internalSound) +{ + mal_mutex_lock(&context, &soundLock); + { + if (firstSound == NULL) { + firstSound = internalSound; + } else { + lastSound->next = internalSound; + internalSound->prev = lastSound; + } + + lastSound = internalSound; + } + mal_mutex_unlock(&context, &soundLock); +} + +static void RemoveSound(SoundInternal* internalSound) +{ + mal_mutex_lock(&context, &soundLock); + { + if (internalSound->prev == NULL) { + firstSound = internalSound->next; + } else { + internalSound->prev->next = internalSound->next; + } + + if (internalSound->next == NULL) { + lastSound = internalSound->prev; + } else { + internalSound->next->prev = internalSound->prev; + } + } + mal_mutex_unlock(&context, &soundLock); +} + +static void OnLog_MAL(mal_context* pContext, mal_device* pDevice, const char* message) +{ + (void)pContext; + (void)pDevice; + TraceLog(LOG_ERROR, message); // All log messages from mini_al are errors. +} + +static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameCount, void* pFramesOut) +{ + // This is where all of the mixing takes place. + (void)pDevice; + + // Mixing is basically just an accumulation. We need to initialize the output buffer to 0. + memset(pFramesOut, 0, frameCount*pDevice->channels*mal_get_sample_size_in_bytes(pDevice->format)); + + // Using a mutex here for thread-safety which makes things not real-time. This is unlikely to be necessary for this project, but may + // want to consider how you might want to avoid this. + mal_mutex_lock(&context, &soundLock); + { + float* pFramesOutF = (float*)pFramesOut; // <-- Just for convenience. + + // Sounds. + for (SoundInternal* internalSound = firstSound; internalSound != NULL; internalSound = internalSound->next) + { + // Ignore stopped or paused sounds. + if (!internalSound->playing || internalSound->paused) { + continue; + } + + mal_uint32 framesRead = 0; + for (;;) { + if (framesRead > frameCount) { + TraceLog(LOG_DEBUG, "Mixed too many frames from sound"); + break; + } + if (framesRead == frameCount) { + break; + } + + // Keep reading until the end of the buffer, or we've already read as much as is allowed. + mal_uint32 framesToRead = (frameCount - framesRead); + mal_uint32 framesRemaining = (internalSound->frameCount - internalSound->frameCursorPos); + if (framesToRead > framesRemaining) { + framesToRead = framesRemaining; + } + + // This is where the real mixing takes place. This can be optimized. This assumes the device and sound are of the same format. + // + // TODO: Implement pitching. + for (mal_uint32 iFrame = 0; iFrame < framesToRead; ++iFrame) { + float* pFrameOut = pFramesOutF + ((framesRead+iFrame) * device.channels); + float* pFrameIn = ((float*)internalSound->data) + ((internalSound->frameCursorPos+iFrame) * device.channels); + + for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel) { + pFrameOut[iChannel] += pFrameIn[iChannel] * masterVolume * internalSound->volume; + } + } + + framesRead += framesToRead; + internalSound->frameCursorPos += framesToRead; + + // If we've reached the end of the sound's internal buffer we do one of two things: loop back to the start, or just stop. + if (framesToRead == framesRemaining) { + if (!internalSound->looping) { + break; + } + } + } + } + + // Music. + // TODO: Implement me. + } + mal_mutex_unlock(&context, &soundLock); + + return frameCount; // We always output the same number of frames that were originally requested. +} +#endif // Initialize audio device void InitAudioDevice(void) { +#if USE_MINI_AL + // Context. + mal_context_config contextConfig = mal_context_config_init(OnLog_MAL); + mal_result result = mal_context_init(NULL, 0, &contextConfig, &context); + if (result != MAL_SUCCESS) + { + return; + } + + // Device. Using the default device. Format is floating point because it simplifies mixing. + mal_device_config deviceConfig = mal_device_config_init(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, OnSendAudioDataToDevice); + result = mal_device_init(&context, mal_device_type_playback, NULL, &deviceConfig, NULL, &device); + if (result != MAL_SUCCESS) + { + mal_context_uninit(&context); + return; + } + + // Keep the device running the whole time. May want to consider doing something a bit smarter and only have the device running + // while there's at least one sound being played. + result = mal_device_start(&device); + if (result != MAL_SUCCESS) + { + mal_device_uninit(&device); + mal_context_uninit(&context); + return; + } + + // Mixing happens on a seperate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may + // want to look at something a bit smarter later on to keep everything real-time, if that's necessary. + if (!mal_mutex_create(&context, &soundLock)) + { + TraceLog(LOG_ERROR, "Failed to create mutex for audio mixing"); + mal_device_uninit(&device); + mal_context_uninit(&context); + return; + } + + + isAudioInitialized = MAL_TRUE; +#else // Open and initialize a device with default settings ALCdevice *device = alcOpenDevice(NULL); @@ -230,13 +421,30 @@ void InitAudioDevice(void) alListener3f(AL_ORIENTATION, 0.0f, 0.0f, -1.0f); alListenerf(AL_GAIN, 1.0f); + + if (alIsExtensionPresent("AL_EXT_float32")) { + TraceLog(LOG_INFO, "AL_EXT_float32 supported"); + } else { + TraceLog(LOG_INFO, "AL_EXT_float32 not supported"); + } } } +#endif } // Close the audio device for all contexts void CloseAudioDevice(void) { +#if USE_MINI_AL + if (!isAudioInitialized) { + TraceLog(LOG_WARNING, "Could not close audio device because it is not currently initialized"); + return; + } + + mal_mutex_delete(&context, &soundLock); + mal_device_uninit(&device); + mal_context_uninit(&context); +#else ALCdevice *device; ALCcontext *context = alcGetCurrentContext(); @@ -247,6 +455,7 @@ void CloseAudioDevice(void) alcMakeContextCurrent(NULL); alcDestroyContext(context); alcCloseDevice(device); +#endif TraceLog(LOG_INFO, "Audio device closed successfully"); } @@ -254,6 +463,9 @@ void CloseAudioDevice(void) // Check if device has been initialized successfully bool IsAudioDeviceReady(void) { +#if USE_MINI_AL + return isAudioInitialized; +#else ALCcontext *context = alcGetCurrentContext(); if (context == NULL) return false; @@ -264,6 +476,7 @@ bool IsAudioDeviceReady(void) if (device == NULL) return false; else return true; } +#endif } // Set master volume (listener) @@ -271,8 +484,12 @@ void SetMasterVolume(float volume) { if (volume < 0.0f) volume = 0.0f; else if (volume > 1.0f) volume = 1.0f; - + +#if USE_MINI_AL + masterVolume = 1; +#else alListenerf(AL_GAIN, volume); +#endif } //---------------------------------------------------------------------------------- @@ -349,6 +566,47 @@ Sound LoadSoundFromWave(Wave wave) if (wave.data != NULL) { +#if USE_MINI_AL + // When using mini_al we need to do our own mixing. To simplify this we need convert the format of each sound to be consistent with + // the format used to open the playback device. We can do this two ways: + // + // 1) Convert the whole sound in one go at load time (here). + // 2) Convert the audio data in chunks at mixing time. + // + // I have decided on the first option because it offloads work required for the format conversion to the to the loading stage. The + // downside to this is that it uses more memory if the original sound is u8 or s16. + mal_format formatIn = ((wave.sampleSize == 8) ? mal_format_u8 : ((wave.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); + mal_uint32 frameCountIn = wave.sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so. + + mal_uint32 frameCount = mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn); + if (frameCount == 0) { + TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to get frame count for format conversion."); + } + + SoundInternal* internalSound = (SoundInternal*)calloc(sizeof(*internalSound) + (frameCount*DEVICE_CHANNELS*4), 1); // <-- Make sure this is initialized to zero for safety. + if (internalSound == NULL) { + TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to allocate memory for internal buffer"); + } + + frameCount = mal_convert_frames(internalSound->data, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, wave.data, formatIn, wave.channels, wave.sampleRate, frameCountIn); + if (frameCount == 0) { + TraceLog(LOG_ERROR, "LoadSoundFromWave() : Format conversion failed."); + } + + internalSound->format = DEVICE_FORMAT; + internalSound->channels = DEVICE_CHANNELS; + internalSound->sampleRate = DEVICE_SAMPLE_RATE; + internalSound->frameCount = frameCount; + internalSound->frameCursorPos = 0; + internalSound->volume = 1; + internalSound->pitch = 1; + internalSound->playing = 0; + internalSound->paused = 0; + internalSound->looping = 0; + AppendSound(internalSound); + + sound.handle = (void*)internalSound; +#else ALenum format = 0; // The OpenAL format is worked out by looking at the number of channels and the sample size (bits per sample) @@ -402,6 +660,7 @@ Sound LoadSoundFromWave(Wave wave) sound.source = source; sound.buffer = buffer; sound.format = format; +#endif } return sound; @@ -418,10 +677,16 @@ void UnloadWave(Wave wave) // Unload sound void UnloadSound(Sound sound) { +#if USE_MINI_AL + SoundInternal* internalSound = (SoundInternal*)sound.handle; + RemoveSound(internalSound); + free(internalSound); +#else alSourceStop(sound.source); alDeleteSources(1, &sound.source); alDeleteBuffers(1, &sound.buffer); +#endif TraceLog(LOG_INFO, "[SND ID %i][BUFR ID %i] Unloaded sound data from RAM", sound.source, sound.buffer); } @@ -430,6 +695,22 @@ void UnloadSound(Sound sound) // NOTE: data must match sound.format void UpdateSound(Sound sound, const void *data, int samplesCount) { +#if USE_MINI_AL + SoundInternal* internalSound = (SoundInternal*)sound.handle; + if (internalSound == NULL) + { + TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound"); + return; + } + + internalSound->playing = false; + internalSound->paused = false; + internalSound->frameCursorPos = 0; + + // TODO: May want to lock/unlock this since this data buffer is read at mixing time. However, this puts a mutex in + // in the mixing code which makes it no longer real-time. This is likely not a critical issue for this project, though. + memcpy(internalSound->data, data, samplesCount*internalSound->channels*mal_get_sample_size_in_bytes(internalSound->format)); +#else ALint sampleRate, sampleSize, channels; alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); alGetBufferi(sound.buffer, AL_BITS, &sampleSize); // It could also be retrieved from sound.format @@ -451,12 +732,26 @@ void UpdateSound(Sound sound, const void *data, int samplesCount) // Attach sound buffer to source again alSourcei(sound.source, AL_BUFFER, sound.buffer); +#endif } // Play a sound void PlaySound(Sound sound) { +#if USE_MINI_AL + SoundInternal* internalSound = (SoundInternal*)sound.handle; + if (internalSound == NULL) + { + TraceLog(LOG_ERROR, "PlaySound() : Invalid sound"); + return; + } + + internalSound->playing = 1; + internalSound->paused = 0; + internalSound->frameCursorPos = 0; +#else alSourcePlay(sound.source); // Play the sound +#endif //TraceLog(LOG_INFO, "Playing sound"); @@ -477,28 +772,72 @@ void PlaySound(Sound sound) // Pause a sound void PauseSound(Sound sound) { +#if USE_MINI_AL + SoundInternal* internalSound = (SoundInternal*)sound.handle; + if (internalSound == NULL) + { + TraceLog(LOG_ERROR, "PauseSound() : Invalid sound"); + return; + } + + internalSound->paused = true; +#else alSourcePause(sound.source); +#endif } // Resume a paused sound void ResumeSound(Sound sound) { +#if USE_MINI_AL + SoundInternal* internalSound = (SoundInternal*)sound.handle; + if (internalSound == NULL) + { + TraceLog(LOG_ERROR, "ResumeSound() : Invalid sound"); + return; + } + + internalSound->paused = false; +#else ALenum state; alGetSourcei(sound.source, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) alSourcePlay(sound.source); +#endif } // Stop reproducing a sound void StopSound(Sound sound) { +#if USE_MINI_AL + SoundInternal* internalSound = (SoundInternal*)sound.handle; + if (internalSound == NULL) + { + TraceLog(LOG_ERROR, "StopSound() : Invalid sound"); + return; + } + + internalSound->playing = false; + internalSound->paused = false; +#else alSourceStop(sound.source); +#endif } // Check if a sound is playing bool IsSoundPlaying(Sound sound) { +#if USE_MINI_AL + SoundInternal* internalSound = (SoundInternal*)sound.handle; + if (internalSound == NULL) + { + TraceLog(LOG_ERROR, "IsSoundPlaying() : Invalid sound"); + return false; + } + + return internalSound->playing && !internalSound->paused; +#else bool playing = false; ALint state; @@ -506,23 +845,73 @@ bool IsSoundPlaying(Sound sound) if (state == AL_PLAYING) playing = true; return playing; +#endif } // Set volume for a sound void SetSoundVolume(Sound sound, float volume) { +#if USE_MINI_AL + SoundInternal* internalSound = (SoundInternal*)sound.handle; + if (internalSound == NULL) + { + TraceLog(LOG_ERROR, "SetSoundVolume() : Invalid sound"); + return; + } + + internalSound->volume = volume; +#else alSourcef(sound.source, AL_GAIN, volume); +#endif } // Set pitch for a sound void SetSoundPitch(Sound sound, float pitch) { +#if USE_MINI_AL + SoundInternal* internalSound = (SoundInternal*)sound.handle; + if (internalSound == NULL) + { + TraceLog(LOG_ERROR, "SetSoundPitch() : Invalid sound"); + return; + } + + internalSound->pitch = pitch; +#else alSourcef(sound.source, AL_PITCH, pitch); +#endif } // Convert wave data to desired format void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) { + mal_format formatIn = ((wave->sampleSize == 8) ? mal_format_u8 : ((wave->sampleSize == 16) ? mal_format_s16 : mal_format_f32)); + mal_format formatOut = (( sampleSize == 8) ? mal_format_u8 : (( sampleSize == 16) ? mal_format_s16 : mal_format_f32)); + + mal_uint32 frameCountIn = wave->sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so. + + mal_uint32 frameCount = mal_convert_frames(NULL, formatOut, channels, sampleRate, NULL, formatIn, wave->channels, wave->sampleRate, frameCountIn); + if (frameCount == 0) { + TraceLog(LOG_ERROR, "WaveFormat() : Failed to get frame count for format conversion."); + return; + } + + void* data = malloc(frameCount * channels * (sampleSize/8)); + + frameCount = mal_convert_frames(data, formatOut, channels, sampleRate, wave->data, formatIn, wave->channels, wave->sampleRate, frameCountIn); + if (frameCount == 0) { + TraceLog(LOG_ERROR, "WaveFormat() : Format conversion failed."); + return; + } + + wave->sampleCount = frameCount; + wave->sampleSize = sampleSize; + wave->sampleRate = sampleRate; + wave->channels = channels; + free(wave->data); + wave->data = data; + +#if 0 // Format sample rate // NOTE: Only supported 22050 <--> 44100 if (wave->sampleRate != sampleRate) @@ -601,6 +990,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) free(wave->data); wave->data = data; } +#endif } // Copy a wave to a new wave diff --git a/src/external/mini_al.c b/src/external/mini_al.c new file mode 100644 index 00000000..2ea2cc6b --- /dev/null +++ b/src/external/mini_al.c @@ -0,0 +1,2 @@ +#define MAL_IMPLEMENTATION +#include "mini_al.h" // <-- The implementation of mini_al.h #includes windows.h, so need to #undef some stuff. \ No newline at end of file diff --git a/src/external/mini_al.h b/src/external/mini_al.h new file mode 100644 index 00000000..49347e42 --- /dev/null +++ b/src/external/mini_al.h @@ -0,0 +1,10437 @@ +// Mini audio library. Public domain. See "unlicense" statement at the end of this file. +// mini_al - v0.x - 2017-xx-xx +// +// David Reid - davidreidsoftware@gmail.com + +// ABOUT +// ===== +// mini_al is a small library for making it easy to connect to a playback or capture device and send +// or receive data from that device. +// +// mini_al uses an asynchronous API. Every device is created with it's own thread, with audio data +// being delivered to or from the device via a callback. Synchronous APIs are not supported in the +// interest of keeping the library as simple and light-weight as possible. +// +// Supported Backends: +// - WASAPI +// - DirectSound +// - WinMM +// - ALSA +// - OSS +// - OpenSL|ES / Android +// - OpenAL +// - Null (Silence) +// - ... and more in the future. +// - Core Audio (OSX, iOS) +// +// Supported Formats: +// - Unsigned 8-bit PCM +// - Signed 16-bit PCM +// - Signed 24-bit PCM (tightly packed) +// - Signed 32-bit PCM +// - IEEE 32-bit floating point PCM +// +// +// USAGE +// ===== +// mini_al is a single-file library. To use it, do something like the following in one .c file. +// #define MAL_IMPLEMENTATION +// #include "mini_al.h" +// +// You can then #include this file in other parts of the program as you would with any other header file. +// +// The implementation of this library will try #include-ing necessary headers for each backend. If you do not have +// the development packages for any particular backend you can disable it by #define-ing the appropriate MAL_NO_* +// option before the implementation. +// +// +// Building (Windows) +// ------------------ +// The Windows build should compile clean on all modern versions of MSVC without the need to configure any include +// paths nor link to any libraries. The same applies to MinGW/GCC and Clang. +// +// Building (Linux) +// ---------------- +// The Linux build uses ALSA for it's backend so you will need to install the relevant ALSA development packages +// for your preferred distro. It also uses pthreads. Dependencies are dynamically linked at runtime so you do not +// need to link to -lasound nor -lpthread. You will need to link to -ldl. +// +// Building (BSD) +// -------------- +// The BSD build uses OSS and should Just Work without any linking nor include path configuration. +// +// +// Playback Example +// ---------------- +// mal_uint32 on_send_samples(mal_device* pDevice, mal_uint32 frameCount, void* pSamples) +// { +// // This callback is set at initialization time and will be called when a playback device needs more +// // data. You need to write as many frames as you can to pSamples (but no more than frameCount) and +// // then return the number of frames you wrote. +// // +// // The user data (pDevice->pUserData) is set by mal_device_init(). +// return (mal_uint32)drwav_read_f32((drwav*)pDevice->pUserData, frameCount * pDevice->channels, (float*)pSamples) / pDevice->channels; +// } +// +// ... +// +// mal_context context; +// if (mal_context_init(NULL, 0, NULL, &context) != MAL_SUCCESS) { +// printf("Failed to initialize context."); +// return -3; +// } +// +// mal_device_config config = mal_device_config_init_playback(mal_format_s16, wav.channels, wav.sampleRate, on_send_frames_to_device); +// +// mal_device device; +// mal_result result = mal_device_init(&context, mal_device_type_playback, NULL, &config, pMyData, &device); +// if (result != MAL_SUCCESS) { +// return -1; +// } +// +// mal_device_start(&device); // The device is sleeping by default so you'll need to start it manually. +// +// ... +// +// mal_device_uninit(&device); // This will stop the device so no need to do that manually. +// +// +// +// NOTES +// ===== +// - This library uses an asynchronous API for delivering and requesting audio data. Each device will have +// it's own worker thread which is managed by the library. +// - If mal_device_init() is called with a device that's not aligned to the platform's natural alignment +// boundary (4 bytes on 32-bit, 8 bytes on 64-bit), it will _not_ be thread-safe. The reason for this +// is that it depends on members of mal_device being correctly aligned for atomic assignments. +// - Sample data is always little-endian and interleaved. For example, mal_format_s16 means signed 16-bit +// integer samples, interleaved. Let me know if you need non-interleaved and I'll look into it. +// +// +// +// BACKEND NUANCES +// =============== +// - The absolute best latency I am able to get on DirectSound is about 10 milliseconds. This seems very +// consistent so I'm suspecting there's some kind of hard coded limit there or something. +// - DirectSound currently supports a maximum of 4 periods. +// - To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: +// +// - UWP is only supported when compiling as C++. +// - UWP only supports default playback and capture devices. +// - UWP requires the Microphone capability to be enabled in the application's manifest (Package.appxmanifest): +// +// ... +// +// +// +// +// +// +// OPTIONS +// ======= +// #define these options before including this file. +// +// #define MAL_NO_WASAPI +// Disables the WASAPI backend. +// +// #define MAL_NO_DSOUND +// Disables the DirectSound backend. +// +// #define MAL_NO_WINMM +// Disables the WinMM backend. +// +// #define MAL_NO_ALSA +// Disables the ALSA backend. +// +// #define MAL_NO_OSS +// Disables the OSS backend. +// +// #define MAL_NO_OPENSL +// Disables the OpenSL|ES backend. +// +// #define MAL_NO_OPENAL +// Disables the OpenAL backend. +// +// #define MAL_NO_NULL +// Disables the null backend. +// +// #define MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS +// When a buffer size of 0 is specified when a device is initialized, it will default to a size with +// this number of milliseconds worth of data. Note that some backends may adjust this setting if that +// particular backend has unusual latency characteristics. +// +// #define MAL_DEFAULT_PERIODS +// When a period count of 0 is specified when a device is initialized, it will default to this. + +#ifndef mini_al_h +#define mini_al_h + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable:4201) // nonstandard extension used: nameless struct/union +#endif + +// Platform/backend detection. +#ifdef _WIN32 + #define MAL_WIN32 + #if (!defined(WINAPI_FAMILY) || WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) + #define MAL_WIN32_DESKTOP + #endif +#else + #define MAL_POSIX + #include // Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. + + #define MAL_UNIX + #ifdef __linux__ + #define MAL_LINUX + #endif + #ifdef __APPLE__ + #define MAL_APPLE + #endif + #ifdef __ANDROID__ + #define MAL_ANDROID + #endif +#endif + +// Some backends are only supported on certain platforms. +#if defined(MAL_WIN32) + #define MAL_SUPPORT_WASAPI + #if defined(MAL_WIN32_DESKTOP) // DirectSound and WinMM backends are only supported on desktop's. + #define MAL_SUPPORT_DSOUND + #define MAL_SUPPORT_WINMM + #endif + + // Don't support WASAPI on older versions of MSVC for now. + #if defined(_MSC_VER) + #if _MSC_VER < 1600 + #if !defined(__audioclient_h__) + #undef MAL_SUPPORT_WASAPI + #endif + #endif + #endif +#endif +#if defined(MAL_UNIX) + #if defined(MAL_LINUX) + #if !defined(MAL_ANDROID) // ALSA is not supported on Android. + #define MAL_SUPPORT_ALSA + #endif + #endif + #if defined(MAL_APPLE) + #define MAL_SUPPORT_COREAUDIO + #endif + #if defined(MAL_ANDROID) + #define MAL_SUPPORT_OPENSL + #endif + #if !defined(MAL_LINUX) && !defined(MAL_APPLE) && !defined(MAL_ANDROID) + #define MAL_SUPPORT_OSS + #endif +#endif +#define MAL_SUPPORT_OPENAL // All platforms support OpenAL (at least for now). +#define MAL_SUPPORT_NULL // All platforms support the null device. + + +#if !defined(MAL_NO_WASAPI) && defined(MAL_SUPPORT_WASAPI) + #define MAL_ENABLE_WASAPI +#endif +#if !defined(MAL_NO_DSOUND) && defined(MAL_SUPPORT_DSOUND) + #define MAL_ENABLE_DSOUND +#endif +#if !defined(MAL_NO_WINMM) && defined(MAL_SUPPORT_WINMM) + #define MAL_ENABLE_WINMM +#endif +#if !defined(MAL_NO_ALSA) && defined(MAL_SUPPORT_ALSA) + #define MAL_ENABLE_ALSA +#endif +#if !defined(MAL_NO_COREAUDIO) && defined(MAL_SUPPORT_COREAUDIO) + #define MAL_ENABLE_COREAUDIO +#endif +#if !defined(MAL_NO_OSS) && defined(MAL_SUPPORT_OSS) + #define MAL_ENABLE_OSS +#endif +#if !defined(MAL_NO_OPENSL) && defined(MAL_SUPPORT_OPENSL) + #define MAL_ENABLE_OPENSL +#endif +#if !defined(MAL_NO_OPENAL) && defined(MAL_SUPPORT_OPENAL) + #define MAL_ENABLE_OPENAL +#endif +#if !defined(MAL_NO_NULL) && defined(MAL_SUPPORT_NULL) + #define MAL_ENABLE_NULL +#endif + + +#if defined(_MSC_VER) && _MSC_VER < 1600 +typedef signed char mal_int8; +typedef unsigned char mal_uint8; +typedef signed short mal_int16; +typedef unsigned short mal_uint16; +typedef signed int mal_int32; +typedef unsigned int mal_uint32; +typedef signed __int64 mal_int64; +typedef unsigned __int64 mal_uint64; +#else +#include +typedef int8_t mal_int8; +typedef uint8_t mal_uint8; +typedef int16_t mal_int16; +typedef uint16_t mal_uint16; +typedef int32_t mal_int32; +typedef uint32_t mal_uint32; +typedef int64_t mal_int64; +typedef uint64_t mal_uint64; +#endif +typedef mal_uint8 mal_bool8; +typedef mal_uint32 mal_bool32; +#define MAL_TRUE 1 +#define MAL_FALSE 0 + +typedef void* mal_handle; +typedef void* mal_ptr; +typedef void (* mal_proc)(); + +#ifdef MAL_WIN32 + typedef mal_handle mal_thread; + typedef mal_handle mal_mutex; + typedef mal_handle mal_event; +#else + typedef pthread_t mal_thread; + typedef pthread_mutex_t mal_mutex; + typedef struct + { + pthread_mutex_t mutex; + pthread_cond_t condition; + mal_uint32 value; + } mal_event; +#endif + +#if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) +typedef mal_uint16 wchar_t; +#endif + +// Define NULL for some compilers. +#ifndef NULL +#define NULL 0 +#endif + +#define MAL_MAX_PERIODS_DSOUND 4 +#define MAL_MAX_PERIODS_OPENAL 4 + +typedef mal_uint8 mal_channel; +#define MAL_CHANNEL_NONE 0 +#define MAL_CHANNEL_FRONT_LEFT 1 +#define MAL_CHANNEL_FRONT_RIGHT 2 +#define MAL_CHANNEL_FRONT_CENTER 3 +#define MAL_CHANNEL_LFE 4 +#define MAL_CHANNEL_BACK_LEFT 5 +#define MAL_CHANNEL_BACK_RIGHT 6 +#define MAL_CHANNEL_FRONT_LEFT_CENTER 7 +#define MAL_CHANNEL_FRONT_RIGHT_CENTER 8 +#define MAL_CHANNEL_BACK_CENTER 9 +#define MAL_CHANNEL_SIDE_LEFT 10 +#define MAL_CHANNEL_SIDE_RIGHT 11 +#define MAL_CHANNEL_TOP_CENTER 12 +#define MAL_CHANNEL_TOP_FRONT_LEFT 13 +#define MAL_CHANNEL_TOP_FRONT_CENTER 14 +#define MAL_CHANNEL_TOP_FRONT_RIGHT 15 +#define MAL_CHANNEL_TOP_BACK_LEFT 16 +#define MAL_CHANNEL_TOP_BACK_CENTER 17 +#define MAL_CHANNEL_TOP_BACK_RIGHT 18 +#define MAL_CHANNEL_MONO MAL_CHANNEL_FRONT_CENTER +#define MAL_MAX_CHANNELS 18 + +#define MAL_MAX_SAMPLE_SIZE_IN_BYTES 8 + +typedef int mal_result; +#define MAL_SUCCESS 0 +#define MAL_ERROR -1 // A generic error. +#define MAL_INVALID_ARGS -2 +#define MAL_OUT_OF_MEMORY -3 +#define MAL_FORMAT_NOT_SUPPORTED -4 +#define MAL_NO_BACKEND -5 +#define MAL_NO_DEVICE -6 +#define MAL_API_NOT_FOUND -7 +#define MAL_DEVICE_BUSY -8 +#define MAL_DEVICE_NOT_INITIALIZED -9 +#define MAL_DEVICE_ALREADY_STARTED -10 +#define MAL_DEVICE_ALREADY_STARTING -11 +#define MAL_DEVICE_ALREADY_STOPPED -12 +#define MAL_DEVICE_ALREADY_STOPPING -13 +#define MAL_FAILED_TO_MAP_DEVICE_BUFFER -14 +#define MAL_FAILED_TO_INIT_BACKEND -15 +#define MAL_FAILED_TO_READ_DATA_FROM_CLIENT -16 +#define MAL_FAILED_TO_READ_DATA_FROM_DEVICE -17 +#define MAL_FAILED_TO_SEND_DATA_TO_CLIENT -18 +#define MAL_FAILED_TO_SEND_DATA_TO_DEVICE -19 +#define MAL_FAILED_TO_OPEN_BACKEND_DEVICE -20 +#define MAL_FAILED_TO_START_BACKEND_DEVICE -21 +#define MAL_FAILED_TO_STOP_BACKEND_DEVICE -22 +#define MAL_FAILED_TO_CREATE_MUTEX -23 +#define MAL_FAILED_TO_CREATE_EVENT -24 +#define MAL_FAILED_TO_CREATE_THREAD -25 +#define MAL_INVALID_DEVICE_CONFIG -26 +#define MAL_ACCESS_DENIED -27 +#define MAL_DSOUND_FAILED_TO_CREATE_DEVICE -1024 +#define MAL_DSOUND_FAILED_TO_SET_COOP_LEVEL -1025 +#define MAL_DSOUND_FAILED_TO_CREATE_BUFFER -1026 +#define MAL_DSOUND_FAILED_TO_QUERY_INTERFACE -1027 +#define MAL_DSOUND_FAILED_TO_SET_NOTIFICATIONS -1028 +#define MAL_ALSA_FAILED_TO_OPEN_DEVICE -2048 +#define MAL_ALSA_FAILED_TO_SET_HW_PARAMS -2049 +#define MAL_ALSA_FAILED_TO_SET_SW_PARAMS -2050 +#define MAL_ALSA_FAILED_TO_PREPARE_DEVICE -2051 +#define MAL_ALSA_FAILED_TO_RECOVER_DEVICE -2052 +#define MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR -3072 +#define MAL_WASAPI_FAILED_TO_CREATE_DEVICE -3073 +#define MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE -3074 +#define MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE -3075 +#define MAL_WASAPI_FAILED_TO_FIND_BEST_FORMAT -3076 +#define MAL_WASAPI_FAILED_TO_GET_INTERNAL_BUFFER -3077 +#define MAL_WASAPI_FAILED_TO_RELEASE_INTERNAL_BUFFER -3078 +#define MAL_WINMM_FAILED_TO_GET_DEVICE_CAPS -4096 +#define MAL_WINMM_FAILED_TO_GET_SUPPORTED_FORMATS -4097 + +typedef struct mal_context mal_context; +typedef struct mal_device mal_device; + +typedef void (* mal_log_proc) (mal_context* pContext, mal_device* pDevice, const char* message); +typedef void (* mal_recv_proc)(mal_device* pDevice, mal_uint32 frameCount, const void* pSamples); +typedef mal_uint32 (* mal_send_proc)(mal_device* pDevice, mal_uint32 frameCount, void* pSamples); +typedef void (* mal_stop_proc)(mal_device* pDevice); + +typedef enum +{ + mal_backend_null, + mal_backend_wasapi, + mal_backend_dsound, + mal_backend_winmm, + mal_backend_alsa, + mal_backend_oss, + mal_backend_opensl, + mal_backend_openal +} mal_backend; + +typedef enum +{ + mal_device_type_playback, + mal_device_type_capture +} mal_device_type; + +typedef enum +{ + // I like to keep these explicitly defined because they're used as a key into a lookup table. When items are + // added to this, make sure there are no gaps and that they're added to the lookup table in mal_get_sample_size_in_bytes(). + mal_format_unknown = 0, // Mainly used for indicating an error. + mal_format_u8 = 1, + mal_format_s16 = 2, // Seems to be the most widely supported format. + mal_format_s24 = 3, // Tightly packed. 3 bytes per sample. + mal_format_s32 = 4, + mal_format_f32 = 5, +} mal_format; + +typedef enum +{ + mal_channel_mix_mode_basic, // Drop excess channels; zeroed out extra channels. + mal_channel_mix_mode_blend, // Blend channels based on locality. +} mal_channel_mix_mode; + +typedef union +{ +#ifdef MAL_SUPPORT_WASAPI + wchar_t wasapi[64]; // WASAPI uses a wchar_t string for identification. +#endif +#ifdef MAL_SUPPORT_DSOUND + mal_uint8 dsound[16]; // DirectSound uses a GUID for identification. +#endif +#ifdef MAL_SUPPORT_WINMM + /*UINT_PTR*/ mal_uint32 winmm; // When creating a device, WinMM expects a Win32 UINT_PTR for device identification. In practice it's actually just a UINT. +#endif +#ifdef MAL_SUPPORT_ALSA + char alsa[256]; // ALSA uses a name string for identification. +#endif +#ifdef MAL_SUPPORT_COREAUDIO + // TODO: Implement me. +#endif +#ifdef MAL_SUPPORT_OSS + char oss[64]; // "dev/dsp0", etc. "dev/dsp" for the default device. +#endif +#ifdef MAL_SUPPORT_OPENSL + mal_uint32 opensl; // OpenSL|ES uses a 32-bit unsigned integer for identification. +#endif +#ifdef MAL_SUPPORT_OPENAL + char openal[256]; // OpenAL seems to use human-readable device names as the ID. +#endif +#ifdef MAL_SUPPORT_NULL + int nullbackend; // Always 0. +#endif +} mal_device_id; + +typedef struct +{ + mal_device_id id; + char name[256]; +} mal_device_info; + +typedef struct +{ + mal_int64 counter; +} mal_timer; + + +typedef struct mal_src mal_src; +typedef mal_uint32 (* mal_src_read_proc)(mal_uint32 frameCount, void* pFramesOut, void* pUserData); // Returns the number of frames that were read. + +typedef enum +{ + mal_src_algorithm_none, + mal_src_algorithm_linear +} mal_src_algorithm; + +#define MAL_SRC_CACHE_SIZE_IN_FRAMES 512 +typedef struct +{ + mal_src* pSRC; + float pCachedFrames[MAL_MAX_CHANNELS * MAL_SRC_CACHE_SIZE_IN_FRAMES]; + mal_uint32 cachedFrameCount; + mal_uint32 iNextFrame; +} mal_src_cache; + +typedef struct +{ + mal_uint32 sampleRateIn; + mal_uint32 sampleRateOut; + mal_format formatIn; + mal_format formatOut; + mal_uint32 channels; + mal_src_algorithm algorithm; + mal_uint32 cacheSizeInFrames; // The number of frames to read from the client at a time. +} mal_src_config; + +struct mal_src +{ + mal_src_config config; + mal_src_read_proc onRead; + void* pUserData; + float ratio; + float bin[256]; + mal_src_cache cache; // <-- For simplifying and optimizing client -> memory reading. + + union + { + struct + { + float alpha; + mal_bool32 isPrevFramesLoaded : 1; + mal_bool32 isNextFramesLoaded : 1; + } linear; + }; +}; + +typedef struct mal_dsp mal_dsp; +typedef mal_uint32 (* mal_dsp_read_proc)(mal_uint32 frameCount, void* pSamplesOut, void* pUserData); + +typedef struct +{ + mal_format formatIn; + mal_uint32 channelsIn; + mal_uint32 sampleRateIn; + mal_channel channelMapIn[MAL_MAX_CHANNELS]; + mal_format formatOut; + mal_uint32 channelsOut; + mal_uint32 sampleRateOut; + mal_channel channelMapOut[MAL_MAX_CHANNELS]; + mal_uint32 cacheSizeInFrames; // Applications should set this to 0 for now. +} mal_dsp_config; + +struct mal_dsp +{ + mal_dsp_config config; + mal_dsp_read_proc onRead; + void* pUserDataForOnRead; + mal_src src; // For sample rate conversion. + mal_channel channelMapInPostMix[MAL_MAX_CHANNELS]; // <-- When mixing, new channels may need to be created. This represents the channel map after mixing. + mal_channel channelShuffleTable[MAL_MAX_CHANNELS]; + mal_bool32 isChannelMappingRequired : 1; + mal_bool32 isSRCRequired : 1; + mal_bool32 isPassthrough : 1; // <-- Will be set to true when the DSP pipeline is an optimized passthrough. +}; + + +typedef struct +{ + mal_format format; + mal_uint32 channels; + mal_uint32 sampleRate; + mal_channel channelMap[MAL_MAX_CHANNELS]; + mal_uint32 bufferSizeInFrames; + mal_uint32 periods; + mal_bool32 preferExclusiveMode; + mal_recv_proc onRecvCallback; + mal_send_proc onSendCallback; + mal_stop_proc onStopCallback; + + struct + { + mal_bool32 noMMap; // Disables MMap mode. + } alsa; +} mal_device_config; + +typedef struct +{ + mal_log_proc onLog; + + struct + { + mal_bool32 useVerboseDeviceEnumeration; + mal_bool32 excludeNullDevice; + } alsa; +} mal_context_config; + +struct mal_context +{ + mal_backend backend; // DirectSound, ALSA, etc. + mal_context_config config; + + union + { +#ifdef MAL_SUPPORT_WASAPI + struct + { + int _unused; + } wasapi; +#endif +#ifdef MAL_SUPPORT_DSOUND + struct + { + /*HMODULE*/ mal_handle hDSoundDLL; + } dsound; +#endif +#ifdef MAL_SUPPORT_WINMM + struct + { + /*HMODULE*/ mal_handle hWinMM; + mal_proc waveOutGetNumDevs; + mal_proc waveOutGetDevCapsA; + mal_proc waveOutOpen; + mal_proc waveOutClose; + mal_proc waveOutPrepareHeader; + mal_proc waveOutUnprepareHeader; + mal_proc waveOutWrite; + mal_proc waveOutReset; + mal_proc waveInGetNumDevs; + mal_proc waveInGetDevCapsA; + mal_proc waveInOpen; + mal_proc waveInClose; + mal_proc waveInPrepareHeader; + mal_proc waveInUnprepareHeader; + mal_proc waveInAddBuffer; + mal_proc waveInStart; + mal_proc waveInReset; + } winmm; +#endif +#ifdef MAL_SUPPORT_ALSA + struct + { + mal_handle asoundSO; + mal_proc snd_pcm_open; + mal_proc snd_pcm_close; + mal_proc snd_pcm_hw_params_sizeof; + mal_proc snd_pcm_hw_params_any; + mal_proc snd_pcm_hw_params_set_format; + mal_proc snd_pcm_hw_params_set_format_first; + mal_proc snd_pcm_hw_params_get_format_mask; + mal_proc snd_pcm_hw_params_set_channels_near; + mal_proc snd_pcm_hw_params_set_rate_resample; + mal_proc snd_pcm_hw_params_set_rate_near; + mal_proc snd_pcm_hw_params_set_buffer_size_near; + mal_proc snd_pcm_hw_params_set_periods_near; + mal_proc snd_pcm_hw_params_set_access; + mal_proc snd_pcm_hw_params_get_format; + mal_proc snd_pcm_hw_params_get_channels; + mal_proc snd_pcm_hw_params_get_rate; + mal_proc snd_pcm_hw_params_get_buffer_size; + mal_proc snd_pcm_hw_params_get_periods; + mal_proc snd_pcm_hw_params_get_access; + mal_proc snd_pcm_hw_params; + mal_proc snd_pcm_sw_params_sizeof; + mal_proc snd_pcm_sw_params_current; + mal_proc snd_pcm_sw_params_set_avail_min; + mal_proc snd_pcm_sw_params_set_start_threshold; + mal_proc snd_pcm_sw_params; + mal_proc snd_pcm_format_mask_sizeof; + mal_proc snd_pcm_format_mask_test; + mal_proc snd_pcm_get_chmap; + mal_proc snd_pcm_prepare; + mal_proc snd_pcm_start; + mal_proc snd_pcm_drop; + mal_proc snd_device_name_hint; + mal_proc snd_device_name_get_hint; + mal_proc snd_card_get_index; + mal_proc snd_device_name_free_hint; + mal_proc snd_pcm_mmap_begin; + mal_proc snd_pcm_mmap_commit; + mal_proc snd_pcm_recover; + mal_proc snd_pcm_readi; + mal_proc snd_pcm_writei; + mal_proc snd_pcm_avail; + mal_proc snd_pcm_avail_update; + mal_proc snd_pcm_wait; + } alsa; +#endif +#ifdef MAL_SUPPORT_COREAUDIO + struct + { + int _unused; + } coreaudio; +#endif +#ifdef MAL_SUPPORT_OSS + struct + { + int versionMajor; + int versionMinor; + } oss; +#endif +#ifdef MAL_SUPPORT_OPENSL + struct + { + int _unused; + } opensl; +#endif +#ifdef MAL_SUPPORT_OPENAL + struct + { + /*HMODULE*/ mal_handle hOpenAL; // OpenAL32.dll, etc. + mal_proc alcCreateContext; + mal_proc alcMakeContextCurrent; + mal_proc alcProcessContext; + mal_proc alcSuspendContext; + mal_proc alcDestroyContext; + mal_proc alcGetCurrentContext; + mal_proc alcGetContextsDevice; + mal_proc alcOpenDevice; + mal_proc alcCloseDevice; + mal_proc alcGetError; + mal_proc alcIsExtensionPresent; + mal_proc alcGetProcAddress; + mal_proc alcGetEnumValue; + mal_proc alcGetString; + mal_proc alcGetIntegerv; + mal_proc alcCaptureOpenDevice; + mal_proc alcCaptureCloseDevice; + mal_proc alcCaptureStart; + mal_proc alcCaptureStop; + mal_proc alcCaptureSamples; + + mal_proc alEnable; + mal_proc alDisable; + mal_proc alIsEnabled; + mal_proc alGetString; + mal_proc alGetBooleanv; + mal_proc alGetIntegerv; + mal_proc alGetFloatv; + mal_proc alGetDoublev; + mal_proc alGetBoolean; + mal_proc alGetInteger; + mal_proc alGetFloat; + mal_proc alGetDouble; + mal_proc alGetError; + mal_proc alIsExtensionPresent; + mal_proc alGetProcAddress; + mal_proc alGetEnumValue; + mal_proc alGenSources; + mal_proc alDeleteSources; + mal_proc alIsSource; + mal_proc alSourcef; + mal_proc alSource3f; + mal_proc alSourcefv; + mal_proc alSourcei; + mal_proc alSource3i; + mal_proc alSourceiv; + mal_proc alGetSourcef; + mal_proc alGetSource3f; + mal_proc alGetSourcefv; + mal_proc alGetSourcei; + mal_proc alGetSource3i; + mal_proc alGetSourceiv; + mal_proc alSourcePlayv; + mal_proc alSourceStopv; + mal_proc alSourceRewindv; + mal_proc alSourcePausev; + mal_proc alSourcePlay; + mal_proc alSourceStop; + mal_proc alSourceRewind; + mal_proc alSourcePause; + mal_proc alSourceQueueBuffers; + mal_proc alSourceUnqueueBuffers; + mal_proc alGenBuffers; + mal_proc alDeleteBuffers; + mal_proc alIsBuffer; + mal_proc alBufferData; + mal_proc alBufferf; + mal_proc alBuffer3f; + mal_proc alBufferfv; + mal_proc alBufferi; + mal_proc alBuffer3i; + mal_proc alBufferiv; + mal_proc alGetBufferf; + mal_proc alGetBuffer3f; + mal_proc alGetBufferfv; + mal_proc alGetBufferi; + mal_proc alGetBuffer3i; + mal_proc alGetBufferiv; + + mal_uint32 isFloat32Supported : 1; + mal_uint32 isMCFormatsSupported : 1; + } openal; +#endif +#ifdef MAL_SUPPORT_NULL + struct + { + int _unused; + } null_device; +#endif + }; + + union + { +#ifdef MAL_WIN32 + struct + { + /*HMODULE*/ mal_handle hOle32DLL; + mal_proc CoInitializeEx; + mal_proc CoUninitialize; + mal_proc CoCreateInstance; + mal_proc CoTaskMemFree; + mal_proc PropVariantClear; + + /*HMODULE*/ mal_handle hUser32DLL; + mal_proc GetForegroundWindow; + mal_proc GetDesktopWindow; + } win32; +#endif +#ifdef MAL_POSIX + struct + { + mal_handle pthreadSO; + mal_proc pthread_create; + mal_proc pthread_join; + mal_proc pthread_mutex_init; + mal_proc pthread_mutex_destroy; + mal_proc pthread_mutex_lock; + mal_proc pthread_mutex_unlock; + mal_proc pthread_cond_init; + mal_proc pthread_cond_destroy; + mal_proc pthread_cond_wait; + mal_proc pthread_cond_signal; + } posix; +#endif + int _unused; + }; +}; + +struct mal_device +{ + mal_context* pContext; + mal_device_type type; + mal_format format; + mal_uint32 channels; + mal_uint32 sampleRate; + mal_uint8 channelMap[MAL_MAX_CHANNELS]; + mal_uint32 bufferSizeInFrames; + mal_uint32 periods; + mal_uint32 state; + mal_recv_proc onRecv; + mal_send_proc onSend; + mal_stop_proc onStop; + void* pUserData; // Application defined data. + mal_mutex lock; + mal_event wakeupEvent; + mal_event startEvent; + mal_event stopEvent; + mal_thread thread; + mal_result workResult; // This is set by the worker thread after it's finished doing a job. + mal_bool32 usingDefaultBufferSize : 1; + mal_bool32 usingDefaultPeriods : 1; + mal_bool32 exclusiveMode : 1; + mal_format internalFormat; + mal_uint32 internalChannels; + mal_uint32 internalSampleRate; + mal_uint8 internalChannelMap[MAL_MAX_CHANNELS]; + mal_dsp dsp; // Samples run through this to convert samples to a format suitable for use by the backend. + mal_uint32 _dspFrameCount; // Internal use only. Used when running the device -> DSP -> client pipeline. See mal_device__on_read_from_device(). + const mal_uint8* _dspFrames; // ^^^ AS ABOVE ^^^ + + union + { +#ifdef MAL_SUPPORT_WASAPI + struct + { + /*IAudioClient**/ mal_ptr pAudioClient; + /*IAudioRenderClient**/ mal_ptr pRenderClient; + /*IAudioCaptureClient**/ mal_ptr pCaptureClient; + /*HANDLE*/ mal_handle hEvent; + /*HANDLE*/ mal_handle hStopEvent; + mal_bool32 breakFromMainLoop; + } wasapi; +#endif +#ifdef MAL_SUPPORT_DSOUND + struct + { + /*HMODULE*/ mal_handle hDSoundDLL; + /*LPDIRECTSOUND*/ mal_ptr pPlayback; + /*LPDIRECTSOUNDBUFFER*/ mal_ptr pPlaybackPrimaryBuffer; + /*LPDIRECTSOUNDBUFFER*/ mal_ptr pPlaybackBuffer; + /*LPDIRECTSOUNDCAPTURE*/ mal_ptr pCapture; + /*LPDIRECTSOUNDCAPTUREBUFFER*/ mal_ptr pCaptureBuffer; + /*LPDIRECTSOUNDNOTIFY*/ mal_ptr pNotify; + /*HANDLE*/ mal_handle pNotifyEvents[MAL_MAX_PERIODS_DSOUND]; // One event handle for each period. + /*HANDLE*/ mal_handle hStopEvent; + mal_uint32 lastProcessedFrame; // This is circular. + mal_bool32 breakFromMainLoop; + } dsound; +#endif +#ifdef MAL_SUPPORT_WINMM + struct + { + /*HWAVEOUT, HWAVEIN*/ mal_handle hDevice; + /*HANDLE*/ mal_handle hEvent; + mal_uint32 fragmentSizeInFrames; + mal_uint32 fragmentSizeInBytes; + mal_uint32 iNextHeader; // [0,periods). Used as an index into pWAVEHDR. + /*WAVEHDR**/ mal_uint8* pWAVEHDR; // One instantiation for each period. + mal_uint8* pIntermediaryBuffer; + mal_uint8* _pHeapData; // Used internally and is used for the heap allocated data for the intermediary buffer and the WAVEHDR structures. + mal_bool32 breakFromMainLoop; + } winmm; +#endif +#ifdef MAL_SUPPORT_ALSA + struct + { + /*snd_pcm_t**/ mal_ptr pPCM; + mal_bool32 isUsingMMap : 1; + mal_bool32 breakFromMainLoop : 1; + void* pIntermediaryBuffer; + } alsa; +#endif +#ifdef MAL_SUPPORT_COREAUDIO + struct + { + int _unused; + } coreaudio; +#endif +#ifdef MAL_SUPPORT_OSS + struct + { + int fd; + mal_uint32 fragmentSizeInFrames; + mal_bool32 breakFromMainLoop; + void* pIntermediaryBuffer; + } oss; +#endif +#ifdef MAL_SUPPORT_OPENSL + struct + { + /*SLObjectItf*/ mal_ptr pOutputMixObj; + /*SLOutputMixItf*/ mal_ptr pOutputMix; + /*SLObjectItf*/ mal_ptr pAudioPlayerObj; + /*SLPlayItf*/ mal_ptr pAudioPlayer; + /*SLObjectItf*/ mal_ptr pAudioRecorderObj; + /*SLRecordItf*/ mal_ptr pAudioRecorder; + /*SLAndroidSimpleBufferQueueItf*/ mal_ptr pBufferQueue; + mal_uint32 periodSizeInFrames; + mal_uint32 currentBufferIndex; + mal_uint8* pBuffer; // This is malloc()'d and is used for storing audio data. Typed as mal_uint8 for easy offsetting. + } opensl; +#endif +#ifdef MAL_SUPPORT_OPENAL + struct + { + /*ALCcontext**/ mal_ptr pContextALC; + /*ALCdevice**/ mal_ptr pDeviceALC; + /*ALuint*/ mal_uint32 sourceAL; + /*ALuint*/ mal_uint32 buffersAL[MAL_MAX_PERIODS_OPENAL]; + /*ALenum*/ mal_uint32 formatAL; + mal_uint32 subBufferSizeInFrames; // This is the size of each of the OpenAL buffers (buffersAL). + mal_uint8* pIntermediaryBuffer; // This is malloc()'d and is used as the destination for reading from the client. Typed as mal_uint8 for easy offsetting. + mal_uint32 iNextBuffer; // The next buffer to unenqueue and then re-enqueue as new data is read. + mal_bool32 breakFromMainLoop; + } openal; +#endif +#ifdef MAL_SUPPORT_NULL + struct + { + mal_timer timer; + mal_uint32 lastProcessedFrame; // This is circular. + mal_bool32 breakFromMainLoop; + mal_uint8* pBuffer; // This is malloc()'d and is used as the destination for reading from the client. Typed as mal_uint8 for easy offsetting. + } null_device; +#endif + }; +}; +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + +// Initializes a context. +// +// The context is used for selecting and initializing the relevant backends. +// +// Note that the location of the device cannot change throughout it's lifetime. Consider allocating +// the mal_context object with malloc() if this is an issue. The reason for this is that a pointer +// to the context is stored in the mal_device structure. +// +// is used to allow the application to prioritize backends depending on it's specific +// requirements. This can be null in which case it uses the default priority, which is as follows: +// - WASAPI +// - DirectSound +// - WinMM +// - ALSA +// - OSS +// - OpenSL|ES +// - OpenAL +// - Null +// +// The onLog callback is used for posting log messages back to the client for diagnostics, debugging, +// etc. You can pass NULL for this if you do not need it. +// +// Return Value: +// MAL_SUCCESS if successful; any other error code otherwise. +// +// Thread Safety: UNSAFE +// +// Effeciency: LOW +// This will dynamically load backends DLLs/SOs (such as dsound.dll). +mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, const mal_context_config* pConfig, mal_context* pContext); + +// Uninitializes a context. +// +// Results are undefined if you call this while any device created by this context is still active. +// +// Return Value: +// MAL_SUCCESS if successful; any other error code otherwise. +// +// Thread Safety: UNSAFE +// +// Efficiency: LOW +// This will unload the backend DLLs/SOs. +mal_result mal_context_uninit(mal_context* pContext); + +// Enumerates over each device of the given type (playback or capture). +// +// It is _not_ safe to assume the first enumerated device is the default device. +// +// Some backends and platforms may only support default playback and capture devices. +// +// Return Value: +// MAL_SUCCESS if successful; any other error code otherwise. +// +// Thread Safety: SAFE, SEE NOTES. +// This API uses an application-defined buffer for output. This is thread-safe so long as the +// application ensures mutal exclusion to the output buffer at their level. +// +// Efficiency: LOW +// This API dynamically links to backend DLLs/SOs (such as dsound.dll). +mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo); + +// Initializes a device. +// +// The device ID (pDeviceID) can be null, in which case the default device is used. Otherwise, you +// can retrieve the ID by calling mal_enumerate_devices() and using the ID from the returned data. +// Set pDeviceID to NULL to use the default device. Do _not_ rely on the first device ID returned +// by mal_enumerate_devices() to be the default device. +// +// This will try it's hardest to create a valid device, even if it means adjusting input arguments. +// Look at pDevice->internalChannels, pDevice->internalSampleRate, etc. to determine the actual +// properties after initialization. +// +// If is 0, it will default to MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS. If +// is set to 0 it will default to MAL_DEFAULT_PERIODS. +// +// The property controls how frequently the background thread is woken to check for more +// data. It's tied to the buffer size, so as an example, if your buffer size is equivalent to 10 +// milliseconds and you have 2 periods, the CPU will wake up approximately every 5 milliseconds. +// +// Consider using mal_device_config_init(), mal_device_config_init_playback(), etc. to make it easier +// to initialize a mal_device_config object. +// +// When compiling for UWP you must ensure you call this function on the main UI thread because the +// operating system may need to present the user with a message asking for permissions. Please refer +// to the official documentation for ActivateAudioInterfaceAsync() for more information. +// +// Return Value: +// MAL_SUCCESS if successful; any other error code otherwise. +// +// Thread Safety: UNSAFE +// It is not safe to call this function simultaneously for different devices because some backends +// depend on and mutate global state (such as OpenSL|ES). The same applies to calling this as the +// same time as mal_device_uninit(). +// +// Results are undefined if you try using a device before this function has returned. +// +// Efficiency: LOW +// This is just slow due to the nature of it being an initialization API. +mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, void* pUserData, mal_device* pDevice); + +// Uninitializes a device. +// +// This will explicitly stop the device. You do not need to call mal_device_stop() beforehand, but it's +// harmless if you do. +// +// Return Value: +// MAL_SUCCESS if successful; any other error code otherwise. +// +// Thread Safety: UNSAFE +// As soon as this API is called the device should be considered undefined. All bets are off if you +// try using the device at the same time as uninitializing it. +// +// Efficiency: LOW +// This will stop the device with mal_device_stop() which is a slow, synchronized call. It also needs +// to destroy internal objects like the backend-specific objects and the background thread. +void mal_device_uninit(mal_device* pDevice); + +// Sets the callback to use when the application has received data from the device. +// +// Thread Safety: SAFE +// This API is implemented as a simple atomic assignment. +// +// Efficiency: HIGH +// This is just an atomic assignment. +void mal_device_set_recv_callback(mal_device* pDevice, mal_recv_proc proc); + +// Sets the callback to use when the application needs to send data to the device for playback. +// +// Note that the implementation of this callback must copy over as many samples as is available. The +// return value specifies how many samples were written to the output buffer. The backend will fill +// any leftover samples with silence. +// +// Thread Safety: SAFE +// This API is implemented as a simple atomic assignment. +// +// Efficiency: HIGH +// This is just an atomic assignment. +void mal_device_set_send_callback(mal_device* pDevice, mal_send_proc proc); + +// Sets the callback to use when the device has stopped, either explicitly or as a result of an error. +// +// Thread Safety: SAFE +// This API is implemented as a simple atomic assignment. +// +// Efficiency: HIGH +// This is just an atomic assignment. +void mal_device_set_stop_callback(mal_device* pDevice, mal_stop_proc proc); + +// Activates the device. For playback devices this begins playback. For capture devices it begins +// recording. +// +// For a playback device, this will retrieve an initial chunk of audio data from the client before +// returning. The reason for this is to ensure there is valid audio data in the buffer, which needs +// to be done _before_ the device begins playback. +// +// Return Value: +// - MAL_SUCCESS if successful; any other error code otherwise. +// - MAL_INVALID_ARGS +// One or more of the input arguments is invalid. +// - MAL_DEVICE_NOT_INITIALIZED +// The device is not currently or was never initialized. +// - MAL_DEVICE_BUSY +// The device is in the process of stopping. This will only happen if mal_device_start() and +// mal_device_stop() is called simultaneous on separate threads. This will never be returned in +// single-threaded applications. +// - MAL_DEVICE_ALREADY_STARTING +// The device is already in the process of starting. This will never be returned in single-threaded +// applications. +// - MAL_DEVICE_ALREADY_STARTED +// The device is already started. +// - MAL_FAILED_TO_READ_DATA_FROM_CLIENT +// Failed to read the initial chunk of audio data from the client. This initial chunk of data is +// required so that the device has valid audio data as soon as it starts playing. This will never +// be returned for capture devices. +// - MAL_FAILED_TO_START_BACKEND_DEVICE +// There was a backend-specific error starting the device. +// +// Thread Safety: SAFE +// +// Efficiency: LOW +// This API waits until the backend device has been started for real by the worker thread. It also +// waits on a mutex for thread-safety. +mal_result mal_device_start(mal_device* pDevice); + +// Puts the device to sleep, but does not uninitialize it. Use mal_device_start() to start it up again. +// +// Return Value: +// - MAL_SUCCESS if successful; any other error code otherwise. +// - MAL_INVALID_ARGS +// One or more of the input arguments is invalid. +// - MAL_DEVICE_NOT_INITIALIZED +// The device is not currently or was never initialized. +// - MAL_DEVICE_BUSY +// The device is in the process of starting. This will only happen if mal_device_start() and +// mal_device_stop() is called simultaneous on separate threads. This will never be returned in +// single-threaded applications. +// - MAL_DEVICE_ALREADY_STOPPING +// The device is already in the process of stopping. This will never be returned in single-threaded +// applications. +// - MAL_DEVICE_ALREADY_STOPPED +// The device is already stopped. +// - MAL_FAILED_TO_STOP_BACKEND_DEVICE +// There was a backend-specific error stopping the device. +// +// Thread Safety: SAFE +// +// Efficiency: LOW +// This API needs to wait on the worker thread to stop the backend device properly before returning. It +// also waits on a mutex for thread-safety. +// +// In addition, some backends need to wait for the device to finish playback/recording of the current +// fragment which can take some time (usually proportionate to the buffer size used when initializing +// the device). +mal_result mal_device_stop(mal_device* pDevice); + +// Determines whether or not the device is started. +// +// Return Value: +// True if the device is started, false otherwise. +// +// Thread Safety: SAFE +// If another thread calls mal_device_start() or mal_device_stop() at this same time as this function +// is called, there's a very small chance the return value will be out of sync. +// +// Efficiency: HIGH +// This is implemented with a simple accessor. +mal_bool32 mal_device_is_started(mal_device* pDevice); + +// Retrieves the size of the buffer in bytes for the given device. +// +// Thread Safety: SAFE +// This is calculated from constant values which are set at initialization time and never change. +// +// Efficiency: HIGH +// This is implemented with just a few 32-bit integer multiplications. +mal_uint32 mal_device_get_buffer_size_in_bytes(mal_device* pDevice); + +// Retrieves the size of a sample in bytes for the given format. +// +// Thread Safety: SAFE +// This is API is pure. +// +// Efficiency: HIGH +// This is implemented with a lookup table. +mal_uint32 mal_get_sample_size_in_bytes(mal_format format); + +// Helper function for initializing a mal_context_config object. +mal_context_config mal_context_config_init(mal_log_proc onLog); + +// Helper function for initializing a mal_device_config object. +// +// This is just a helper API, and as such the returned object can be safely modified as needed. +// +// The default channel mapping is based on the channel count, as per the table below. Note that these +// can be freely changed after this function returns if you are needing something in particular. +// +// |---------------|------------------------------| +// | Channel Count | Mapping | +// |---------------|------------------------------| +// | 1 (Mono) | 0: MAL_CHANNEL_FRONT_CENTER | +// |---------------|------------------------------| +// | 2 (Stereo) | 0: MAL_CHANNEL_FRONT_LEFT | +// | | 1: MAL_CHANNEL_FRONT_RIGHT | +// |---------------|------------------------------| +// | 3 (2.1) | 0: MAL_CHANNEL_FRONT_LEFT | +// | | 1: MAL_CHANNEL_FRONT_RIGHT | +// | | 2: MAL_CHANNEL_LFE | +// |---------------|------------------------------| +// | 4 (Quad) | 0: MAL_CHANNEL_FRONT_LEFT | +// | | 1: MAL_CHANNEL_FRONT_RIGHT | +// | | 2: MAL_CHANNEL_BACK_LEFT | +// | | 3: MAL_CHANNEL_BACK_RIGHT | +// |---------------|------------------------------| +// | 5 (4.1) | 0: MAL_CHANNEL_FRONT_LEFT | +// | | 1: MAL_CHANNEL_FRONT_RIGHT | +// | | 2: MAL_CHANNEL_BACK_LEFT | +// | | 3: MAL_CHANNEL_BACK_RIGHT | +// | | 4: MAL_CHANNEL_LFE | +// |---------------|------------------------------| +// | 6 (5.1) | 0: MAL_CHANNEL_FRONT_LEFT | +// | | 1: MAL_CHANNEL_FRONT_RIGHT | +// | | 2: MAL_CHANNEL_FRONT_CENTER | +// | | 3: MAL_CHANNEL_LFE | +// | | 4: MAL_CHANNEL_BACK_LEFT | +// | | 5: MAL_CHANNEL_BACK_RIGHT | +// |---------------|------------------------------| +// | 8 (7.1) | 0: MAL_CHANNEL_FRONT_LEFT | +// | | 1: MAL_CHANNEL_FRONT_RIGHT | +// | | 2: MAL_CHANNEL_FRONT_CENTER | +// | | 3: MAL_CHANNEL_LFE | +// | | 4: MAL_CHANNEL_BACK_LEFT | +// | | 5: MAL_CHANNEL_BACK_RIGHT | +// | | 6: MAL_CHANNEL_SIDE_LEFT | +// | | 7: MAL_CHANNEL_SIDE_RIGHT | +// |---------------|------------------------------| +// | Other | All channels set to 0. This | +// | | is equivalent to the same | +// | | mapping as the device. | +// |---------------|------------------------------| +// +// Thread Safety: SAFE +// +// Efficiency: HIGH +// This just returns a stack allocated object and consists of just a few assignments. +mal_device_config mal_device_config_init(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_recv_proc onRecvCallback, mal_send_proc onSendCallback); + +// A simplified version of mal_device_config_init() for capture devices. +static inline mal_device_config mal_device_config_init_capture(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_recv_proc onRecvCallback) { return mal_device_config_init(format, channels, sampleRate, onRecvCallback, NULL); } + +// A simplified version of mal_device_config_init() for playback devices. +static inline mal_device_config mal_device_config_init_playback(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_send_proc onSendCallback) { return mal_device_config_init(format, channels, sampleRate, NULL, onSendCallback); } + + + + +/////////////////////////////////////////////////////////////////////////////// +// +// SRC +// +/////////////////////////////////////////////////////////////////////////////// + +// Initializes a sample rate conversion object. +mal_result mal_src_init(mal_src_config* pConfig, mal_src_read_proc onRead, void* pUserData, mal_src* pSRC); + +// Reads a number of frames. +// +// Returns the number of frames actually read. +mal_uint32 mal_src_read_frames(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut); + + + +/////////////////////////////////////////////////////////////////////////////// +// +// DSP +// +/////////////////////////////////////////////////////////////////////////////// + +// Initializes a DSP object. +mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* pUserData, mal_dsp* pDSP); + +// Reads a number of frames and runs them through the DSP processor. +mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut); + +// High-level helper for doing a full format conversion in one go. Returns the number of output frames. Call this with pOut set to NULL to +// determine the required size of the output buffer. +// +// A return value of 0 indicates an error. +// +// This function is useful for one-off bulk conversions, but if you're streaming data you should use the DSP APIs instead. +mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut, const void* pIn, mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_uint32 frameCountIn); + + +/////////////////////////////////////////////////////////////////////////////// +// +// Utiltities +// +/////////////////////////////////////////////////////////////////////////////// + +mal_bool32 mal_mutex_create(mal_context* pContext, mal_mutex* pMutex); +void mal_mutex_delete(mal_context* pContext, mal_mutex* pMutex); +void mal_mutex_lock(mal_context* pContext, mal_mutex* pMutex); +void mal_mutex_unlock(mal_context* pContext, mal_mutex* pMutex); + + + +/////////////////////////////////////////////////////////////////////////////// +// +// Miscellaneous Helpers +// +/////////////////////////////////////////////////////////////////////////////// + +// Blends two frames in floating point format. +void mal_blend_f32(float* pOut, float* pInA, float* pInB, float factor, mal_uint32 channels); + + + +/////////////////////////////////////////////////////////////////////////////// +// +// Format Conversion +// +/////////////////////////////////////////////////////////////////////////////// +void mal_pcm_u8_to_s16(short* pOut, const unsigned char* pIn, unsigned int count); +void mal_pcm_u8_to_s24(void* pOut, const unsigned char* pIn, unsigned int count); +void mal_pcm_u8_to_s32(int* pOut, const unsigned char* pIn, unsigned int count); +void mal_pcm_u8_to_f32(float* pOut, const unsigned char* pIn, unsigned int count); +void mal_pcm_s16_to_u8(unsigned char* pOut, const short* pIn, unsigned int count); +void mal_pcm_s16_to_s24(void* pOut, const short* pIn, unsigned int count); +void mal_pcm_s16_to_s32(int* pOut, const short* pIn, unsigned int count); +void mal_pcm_s16_to_f32(float* pOut, const short* pIn, unsigned int count); +void mal_pcm_s24_to_u8(unsigned char* pOut, const void* pIn, unsigned int count); +void mal_pcm_s24_to_s16(short* pOut, const void* pIn, unsigned int count); +void mal_pcm_s24_to_s32(int* pOut, const void* pIn, unsigned int count); +void mal_pcm_s24_to_f32(float* pOut, const void* pIn, unsigned int count); +void mal_pcm_s32_to_u8(unsigned char* pOut, const int* pIn, unsigned int count); +void mal_pcm_s32_to_s16(short* pOut, const int* pIn, unsigned int count); +void mal_pcm_s32_to_s24(void* pOut, const int* pIn, unsigned int count); +void mal_pcm_s32_to_f32(float* pOut, const int* pIn, unsigned int count); +void mal_pcm_f32_to_u8(unsigned char* pOut, const float* pIn, unsigned int count); +void mal_pcm_f32_to_s16(short* pOut, const float* pIn, unsigned int count); +void mal_pcm_f32_to_s24(void* pOut, const float* pIn, unsigned int count); +void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count); +void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_format formatIn, unsigned int sampleCount); + +#ifdef __cplusplus +} +#endif +#endif //mini_al_h + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// +// IMPLEMENTATION +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_IMPLEMENTATION +#include + +#ifdef MAL_WIN32 +#include +#else +#include // For malloc()/free() +#include // For memset() +#endif + +#ifdef MAL_POSIX +#include +#include +#endif + +#if !defined(MAL_64BIT) && !defined(MAL_32BIT) +#ifdef _WIN32 +#ifdef _WIN64 +#define MAL_64BIT +#else +#define MAL_32BIT +#endif +#endif +#endif + +#if !defined(MAL_64BIT) && !defined(MAL_32BIT) +#ifdef __GNUC__ +#ifdef __LP64__ +#define MAL_64BIT +#else +#define MAL_32BIT +#endif +#endif +#endif + +#if !defined(MAL_64BIT) && !defined(MAL_32BIT) +#include +#if INTPTR_MAX == INT64_MAX +#define MAL_64BIT +#else +#define MAL_32BIT +#endif +#endif + + +#ifdef MAL_WIN32 + #define MAL_THREADCALL WINAPI + typedef unsigned long mal_thread_result; +#else + #define MAL_THREADCALL + typedef void* mal_thread_result; +#endif +typedef mal_thread_result (MAL_THREADCALL * mal_thread_entry_proc)(void* pData); + +#ifdef MAL_WIN32 +typedef HRESULT (WINAPI * MAL_PFN_CoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit); +typedef void (WINAPI * MAL_PFN_CoUninitialize)(); +typedef HRESULT (WINAPI * MAL_PFN_CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv); +typedef void (WINAPI * MAL_PFN_CoTaskMemFree)(LPVOID pv); +typedef HRESULT (WINAPI * MAL_PFN_PropVariantClear)(PROPVARIANT *pvar); + +typedef HWND (WINAPI * MAL_PFN_GetForegroundWindow)(); +typedef HWND (WINAPI * MAL_PFN_GetDesktopWindow)(); +#endif + + +#define MAL_STATE_UNINITIALIZED 0 +#define MAL_STATE_STOPPED 1 // The device's default state after initialization. +#define MAL_STATE_STARTED 2 // The worker thread is in it's main loop waiting for the driver to request or deliver audio data. +#define MAL_STATE_STARTING 3 // Transitioning from a stopped state to started. +#define MAL_STATE_STOPPING 4 // Transitioning from a started state to stopped. + + +// The default size of the device's buffer in milliseconds. +// +// If this is too small you may get underruns and overruns in which case you'll need to either increase +// this value or use an explicit buffer size. +#ifndef MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS +#define MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS 25 +#endif + +// Default periods when none is specified in mal_device_init(). More periods means more work on the CPU. +#ifndef MAL_DEFAULT_PERIODS +#define MAL_DEFAULT_PERIODS 2 +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// +// Standard Library Stuff +// +/////////////////////////////////////////////////////////////////////////////// +#ifndef mal_zero_memory +#ifdef MAL_WIN32 +#define mal_zero_memory(p, sz) ZeroMemory((p), (sz)) +#else +#define mal_zero_memory(p, sz) memset((p), 0, (sz)) +#endif +#endif + +#define mal_zero_object(p) mal_zero_memory((p), sizeof(*(p))) + +#ifndef mal_copy_memory +#ifdef MAL_WIN32 +#define mal_copy_memory(dst, src, sz) CopyMemory((dst), (src), (sz)) +#else +#define mal_copy_memory(dst, src, sz) memcpy((dst), (src), (sz)) +#endif +#endif + +#ifndef mal_malloc +#ifdef MAL_WIN32 +#define mal_malloc(sz) HeapAlloc(GetProcessHeap(), 0, (sz)) +#else +#define mal_malloc(sz) malloc((sz)) +#endif +#endif + +#ifndef mal_realloc +#ifdef MAL_WIN32 +#define mal_realloc(p, sz) (((sz) > 0) ? ((p) ? HeapReAlloc(GetProcessHeap(), 0, (p), (sz)) : HeapAlloc(GetProcessHeap(), 0, (sz))) : ((VOID*)(SIZE_T)(HeapFree(GetProcessHeap(), 0, (p)) & 0))) +#else +#define mal_realloc(p, sz) realloc((p), (sz)) +#endif +#endif + +#ifndef mal_free +#ifdef MAL_WIN32 +#define mal_free(p) HeapFree(GetProcessHeap(), 0, (p)) +#else +#define mal_free(p) free((p)) +#endif +#endif + +#ifndef mal_assert +#ifdef MAL_WIN32 +#define mal_assert(condition) assert(condition) +#else +#define mal_assert(condition) assert(condition) +#endif +#endif + +#define mal_countof(x) (sizeof(x) / sizeof(x[0])) +#define mal_max(x, y) (((x) > (y)) ? (x) : (y)) +#define mal_min(x, y) (((x) < (y)) ? (x) : (y)) + +#define mal_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / mal_get_sample_size_in_bytes(format) / (channels)) + +// Some of these string utility functions are unused on some platforms. +#if defined(__GNUC__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-function" +#endif +// Return Values: +// 0: Success +// 22: EINVAL +// 34: ERANGE +// +// Not using symbolic constants for errors because I want to avoid #including errno.h +static int mal_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) +{ + if (dst == 0) { + return 22; + } + if (dstSizeInBytes == 0) { + return 34; + } + if (src == 0) { + dst[0] = '\0'; + return 22; + } + + size_t i; + for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) { + dst[i] = src[i]; + } + + if (i < dstSizeInBytes) { + dst[i] = '\0'; + return 0; + } + + dst[0] = '\0'; + return 34; +} + +static int mal_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) +{ + if (dst == 0) { + return 22; + } + if (dstSizeInBytes == 0) { + return 34; + } + if (src == 0) { + dst[0] = '\0'; + return 22; + } + + size_t maxcount = count; + if (count == ((size_t)-1) || count >= dstSizeInBytes) { // -1 = _TRUNCATE + maxcount = dstSizeInBytes - 1; + } + + size_t i; + for (i = 0; i < maxcount && src[i] != '\0'; ++i) { + dst[i] = src[i]; + } + + if (src[i] == '\0' || i == count || count == ((size_t)-1)) { + dst[i] = '\0'; + return 0; + } + + dst[0] = '\0'; + return 34; +} + +static int mal_strcat_s(char* dst, size_t dstSizeInBytes, const char* src) +{ + if (dst == 0) { + return 22; + } + if (dstSizeInBytes == 0) { + return 34; + } + if (src == 0) { + dst[0] = '\0'; + return 22; + } + + char* dstorig = dst; + + while (dstSizeInBytes > 0 && dst[0] != '\0') { + dst += 1; + dstSizeInBytes -= 1; + } + + if (dstSizeInBytes == 0) { + return 22; // Unterminated. + } + + + while (dstSizeInBytes > 0 && src[0] != '\0') { + *dst++ = *src++; + dstSizeInBytes -= 1; + } + + if (dstSizeInBytes > 0) { + dst[0] = '\0'; + } else { + dstorig[0] = '\0'; + return 34; + } + + return 0; +} + +static int mal_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix) +{ + if (dst == NULL || dstSizeInBytes == 0) { + return 22; + } + if (radix < 2 || radix > 36) { + dst[0] = '\0'; + return 22; + } + + int sign = (value < 0 && radix == 10) ? -1 : 1; // The negative sign is only used when the base is 10. + + unsigned int valueU; + if (value < 0) { + valueU = -value; + } else { + valueU = value; + } + + char* dstEnd = dst; + do + { + int remainder = valueU % radix; + if (remainder > 9) { + *dstEnd = (char)((remainder - 10) + 'a'); + } else { + *dstEnd = (char)(remainder + '0'); + } + + dstEnd += 1; + dstSizeInBytes -= 1; + valueU /= radix; + } while (dstSizeInBytes > 0 && valueU > 0); + + if (dstSizeInBytes == 0) { + dst[0] = '\0'; + return 22; // Ran out of room in the output buffer. + } + + if (sign < 0) { + *dstEnd++ = '-'; + dstSizeInBytes -= 1; + } + + if (dstSizeInBytes == 0) { + dst[0] = '\0'; + return 22; // Ran out of room in the output buffer. + } + + *dstEnd = '\0'; + + + // At this point the string will be reversed. + dstEnd -= 1; + while (dst < dstEnd) { + char temp = *dst; + *dst = *dstEnd; + *dstEnd = temp; + + dst += 1; + dstEnd -= 1; + } + + return 0; +} + +static int mal_strcmp(const char* str1, const char* str2) +{ + if (str1 == str2) return 0; + + // These checks differ from the standard implementation. It's not important, but I prefer + // it just for sanity. + if (str1 == NULL) return -1; + if (str2 == NULL) return 1; + + for (;;) { + if (str1[0] == '\0') { + break; + } + if (str1[0] != str2[0]) { + break; + } + + str1 += 1; + str2 += 1; + } + + return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0]; +} +#if defined(__GNUC__) + #pragma GCC diagnostic pop +#endif + + +// Thanks to good old Bit Twiddling Hacks for this one: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 +static inline unsigned int mal_next_power_of_2(unsigned int x) +{ + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + + return x; +} + +static inline unsigned int mal_prev_power_of_2(unsigned int x) +{ + return mal_next_power_of_2(x) >> 1; +} + +static inline unsigned int mal_round_to_power_of_2(unsigned int x) +{ + unsigned int prev = mal_prev_power_of_2(x); + unsigned int next = mal_next_power_of_2(x); + if ((next - x) > (x - prev)) { + return prev; + } else { + return next; + } +} + + + +// Clamps an f32 sample to -1..1 +static inline float mal_clip_f32(float x) +{ + if (x < -1) return -1; + if (x > +1) return +1; + return x; +} + +static inline float mal_mix_f32(float x, float y, float a) +{ + return x*(1-a) + y*a; +} + + +/////////////////////////////////////////////////////////////////////////////// +// +// Atomics +// +/////////////////////////////////////////////////////////////////////////////// +#if defined(_WIN32) && defined(_MSC_VER) +#define mal_memory_barrier() MemoryBarrier() +#define mal_atomic_exchange_32(a, b) InterlockedExchange((LONG*)a, (LONG)b) +#define mal_atomic_exchange_64(a, b) InterlockedExchange64((LONGLONG*)a, (LONGLONG)b) +#define mal_atomic_increment_32(a) InterlockedIncrement((LONG*)a) +#define mal_atomic_decrement_32(a) InterlockedDecrement((LONG*)a) +#else +#define mal_memory_barrier() __sync_synchronize() +#define mal_atomic_exchange_32(a, b) (void)__sync_lock_test_and_set(a, b); __sync_synchronize() +#define mal_atomic_exchange_64(a, b) (void)__sync_lock_test_and_set(a, b); __sync_synchronize() +#define mal_atomic_increment_32(a) __sync_add_and_fetch(a, 1) +#define mal_atomic_decrement_32(a) __sync_sub_and_fetch(a, 1) +#endif + +#ifdef MAL_64BIT +#define mal_atomic_exchange_ptr mal_atomic_exchange_64 +#endif +#ifdef MAL_32BIT +#define mal_atomic_exchange_ptr mal_atomic_exchange_32 +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// +// Timing +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_WIN32 +static LARGE_INTEGER g_mal_TimerFrequency = {{0}}; +void mal_timer_init(mal_timer* pTimer) +{ + if (g_mal_TimerFrequency.QuadPart == 0) { + QueryPerformanceFrequency(&g_mal_TimerFrequency); + } + + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + pTimer->counter = (mal_uint64)counter.QuadPart; +} + +double mal_timer_get_time_in_seconds(mal_timer* pTimer) +{ + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + + return (counter.QuadPart - pTimer->counter) / (double)g_mal_TimerFrequency.QuadPart; +} +#else +void mal_timer_init(mal_timer* pTimer) +{ + struct timespec newTime; + clock_gettime(CLOCK_MONOTONIC, &newTime); + + pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; +} + +double mal_timer_get_time_in_seconds(mal_timer* pTimer) +{ + struct timespec newTime; + clock_gettime(CLOCK_MONOTONIC, &newTime); + + uint64_t newTimeCounter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; + uint64_t oldTimeCounter = pTimer->counter; + + return (newTimeCounter - oldTimeCounter) / 1000000000.0; +} +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// +// Dynamic Linking +// +/////////////////////////////////////////////////////////////////////////////// +mal_handle mal_dlopen(const char* filename) +{ +#ifdef _WIN32 +#ifdef MAL_WIN32_DESKTOP + return (mal_handle)LoadLibraryA(filename); +#else + // *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... + WCHAR filenameW[4096]; + if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { + return NULL; + } + + return (mal_handle)LoadPackagedLibrary(filenameW, 0); +#endif +#else + return (mal_handle)dlopen(filename, RTLD_NOW); +#endif +} + +void mal_dlclose(mal_handle handle) +{ +#ifdef _WIN32 + FreeLibrary((HMODULE)handle); +#else + dlclose((void*)handle); +#endif +} + +mal_proc mal_dlsym(mal_handle handle, const char* symbol) +{ +#ifdef _WIN32 + return (mal_proc)GetProcAddress((HMODULE)handle, symbol); +#else + return (mal_proc)dlsym((void*)handle, symbol); +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// +// +// Threading +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_WIN32 +mal_bool32 mal_thread_create__win32(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) +{ + (void)pContext; + + *pThread = CreateThread(NULL, 0, entryProc, pData, 0, NULL); + if (*pThread == NULL) { + return MAL_FALSE; + } + + return MAL_TRUE; +} + +void mal_thread_wait__win32(mal_context* pContext, mal_thread* pThread) +{ + (void)pContext; + + WaitForSingleObject(*pThread, INFINITE); +} + +void mal_sleep__win32(mal_uint32 milliseconds) +{ + Sleep((DWORD)milliseconds); +} + + +mal_bool32 mal_mutex_create__win32(mal_context* pContext, mal_mutex* pMutex) +{ + (void)pContext; + + *pMutex = CreateEventA(NULL, FALSE, TRUE, NULL); + if (*pMutex == NULL) { + return MAL_FALSE; + } + + return MAL_TRUE; +} + +void mal_mutex_delete__win32(mal_context* pContext, mal_mutex* pMutex) +{ + (void)pContext; + + CloseHandle(*pMutex); +} + +void mal_mutex_lock__win32(mal_context* pContext, mal_mutex* pMutex) +{ + (void)pContext; + + WaitForSingleObject(*pMutex, INFINITE); +} + +void mal_mutex_unlock__win32(mal_context* pContext, mal_mutex* pMutex) +{ + (void)pContext; + + SetEvent(*pMutex); +} + + +mal_bool32 mal_event_create__win32(mal_context* pContext, mal_event* pEvent) +{ + (void)pContext; + + *pEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if (*pEvent == NULL) { + return MAL_FALSE; + } + + return MAL_TRUE; +} + +void mal_event_delete__win32(mal_context* pContext, mal_event* pEvent) +{ + (void)pContext; + + CloseHandle(*pEvent); +} + +mal_bool32 mal_event_wait__win32(mal_context* pContext, mal_event* pEvent) +{ + (void)pContext; + + return WaitForSingleObject(*pEvent, INFINITE) == WAIT_OBJECT_0; +} + +mal_bool32 mal_event_signal__win32(mal_context* pContext, mal_event* pEvent) +{ + (void)pContext; + + return SetEvent(*pEvent); +} +#endif + + +#ifdef MAL_POSIX +typedef int (* mal_pthread_create_proc)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); +typedef int (* mal_pthread_join_proc)(pthread_t thread, void **retval); +typedef int (* mal_pthread_mutex_init_proc)(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr); +typedef int (* mal_pthread_mutex_destroy_proc)(pthread_mutex_t *__mutex); +typedef int (* mal_pthread_mutex_lock_proc)(pthread_mutex_t *__mutex); +typedef int (* mal_pthread_mutex_unlock_proc)(pthread_mutex_t *__mutex); +typedef int (* mal_pthread_cond_init_proc)(pthread_cond_t *__restrict __cond, const pthread_condattr_t *__restrict __cond_attr); +typedef int (* mal_pthread_cond_destroy_proc)(pthread_cond_t *__cond); +typedef int (* mal_pthread_cond_signal_proc)(pthread_cond_t *__cond); +typedef int (* mal_pthread_cond_wait_proc)(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex); + +mal_bool32 mal_thread_create__posix(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) +{ + return ((mal_pthread_create_proc)pContext->posix.pthread_create)(pThread, NULL, entryProc, pData) == 0; +} + +void mal_thread_wait__posix(mal_context* pContext, mal_thread* pThread) +{ + ((mal_pthread_join_proc)pContext->posix.pthread_join)(*pThread, NULL); +} + +void mal_sleep__posix(mal_uint32 milliseconds) +{ + usleep(milliseconds * 1000); // <-- usleep is in microseconds. +} + + +mal_bool32 mal_mutex_create__posix(mal_context* pContext, mal_mutex* pMutex) +{ + return ((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(pMutex, NULL) == 0; +} + +void mal_mutex_delete__posix(mal_context* pContext, mal_mutex* pMutex) +{ + ((mal_pthread_mutex_destroy_proc)pContext->posix.pthread_mutex_destroy)(pMutex); +} + +void mal_mutex_lock__posix(mal_context* pContext, mal_mutex* pMutex) +{ + ((mal_pthread_mutex_lock_proc)pContext->posix.pthread_mutex_lock)(pMutex); +} + +void mal_mutex_unlock__posix(mal_context* pContext, mal_mutex* pMutex) +{ + ((mal_pthread_mutex_unlock_proc)pContext->posix.pthread_mutex_unlock)(pMutex); +} + + +mal_bool32 mal_event_create__posix(mal_context* pContext, mal_event* pEvent) +{ + if (((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pEvent->mutex, NULL) != 0) { + return MAL_FALSE; + } + + if (((mal_pthread_cond_init_proc)pContext->posix.pthread_cond_init)(&pEvent->condition, NULL) != 0) { + return MAL_FALSE; + } + + pEvent->value = 0; + return MAL_TRUE; +} + +void mal_event_delete__posix(mal_context* pContext, mal_event* pEvent) +{ + ((mal_pthread_cond_destroy_proc)pContext->posix.pthread_cond_destroy)(&pEvent->condition); + ((mal_pthread_mutex_destroy_proc)pContext->posix.pthread_mutex_destroy)(&pEvent->mutex); +} + +mal_bool32 mal_event_wait__posix(mal_context* pContext, mal_event* pEvent) +{ + ((mal_pthread_mutex_lock_proc)pContext->posix.pthread_mutex_lock)(&pEvent->mutex); + { + while (pEvent->value == 0) { + ((mal_pthread_cond_wait_proc)pContext->posix.pthread_cond_wait)(&pEvent->condition, &pEvent->mutex); + } + + pEvent->value = 0; // Auto-reset. + } + ((mal_pthread_mutex_unlock_proc)pContext->posix.pthread_mutex_unlock)(&pEvent->mutex); + + return MAL_TRUE; +} + +mal_bool32 mal_event_signal__posix(mal_context* pContext, mal_event* pEvent) +{ + ((mal_pthread_mutex_lock_proc)pContext->posix.pthread_mutex_lock)(&pEvent->mutex); + { + pEvent->value = 1; + ((mal_pthread_cond_signal_proc)pContext->posix.pthread_cond_signal)(&pEvent->condition); + } + ((mal_pthread_mutex_unlock_proc)pContext->posix.pthread_mutex_unlock)(&pEvent->mutex); + + return MAL_TRUE; +} +#endif + +mal_bool32 mal_thread_create(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) +{ + if (pThread == NULL || entryProc == NULL) return MAL_FALSE; + +#ifdef MAL_WIN32 + return mal_thread_create__win32(pContext, pThread, entryProc, pData); +#endif +#ifdef MAL_POSIX + return mal_thread_create__posix(pContext, pThread, entryProc, pData); +#endif +} + +void mal_thread_wait(mal_context* pContext, mal_thread* pThread) +{ + if (pThread == NULL) return; + +#ifdef MAL_WIN32 + mal_thread_wait__win32(pContext, pThread); +#endif +#ifdef MAL_POSIX + mal_thread_wait__posix(pContext, pThread); +#endif +} + +void mal_sleep(mal_uint32 milliseconds) +{ +#ifdef MAL_WIN32 + mal_sleep__win32(milliseconds); +#endif +#ifdef MAL_POSIX + mal_sleep__posix(milliseconds); +#endif +} + + +mal_bool32 mal_mutex_create(mal_context* pContext, mal_mutex* pMutex) +{ + if (pMutex == NULL) return MAL_FALSE; + +#ifdef MAL_WIN32 + return mal_mutex_create__win32(pContext, pMutex); +#endif +#ifdef MAL_POSIX + return mal_mutex_create__posix(pContext, pMutex); +#endif +} + +void mal_mutex_delete(mal_context* pContext, mal_mutex* pMutex) +{ + if (pMutex == NULL) return; + +#ifdef MAL_WIN32 + mal_mutex_delete__win32(pContext, pMutex); +#endif +#ifdef MAL_POSIX + mal_mutex_delete__posix(pContext, pMutex); +#endif +} + +void mal_mutex_lock(mal_context* pContext, mal_mutex* pMutex) +{ + if (pMutex == NULL) return; + +#ifdef MAL_WIN32 + mal_mutex_lock__win32(pContext, pMutex); +#endif +#ifdef MAL_POSIX + mal_mutex_lock__posix(pContext, pMutex); +#endif +} + +void mal_mutex_unlock(mal_context* pContext, mal_mutex* pMutex) +{ + if (pMutex == NULL) return; + +#ifdef MAL_WIN32 + mal_mutex_unlock__win32(pContext, pMutex); +#endif +#ifdef MAL_POSIX + mal_mutex_unlock__posix(pContext, pMutex); +#endif +} + + +mal_bool32 mal_event_create(mal_context* pContext, mal_event* pEvent) +{ + if (pEvent == NULL) return MAL_FALSE; + +#ifdef MAL_WIN32 + return mal_event_create__win32(pContext, pEvent); +#endif +#ifdef MAL_POSIX + return mal_event_create__posix(pContext, pEvent); +#endif +} + +void mal_event_delete(mal_context* pContext, mal_event* pEvent) +{ + if (pEvent == NULL) return; + +#ifdef MAL_WIN32 + mal_event_delete__win32(pContext, pEvent); +#endif +#ifdef MAL_POSIX + mal_event_delete__posix(pContext, pEvent); +#endif +} + +mal_bool32 mal_event_wait(mal_context* pContext, mal_event* pEvent) +{ + if (pEvent == NULL) return MAL_FALSE; + +#ifdef MAL_WIN32 + return mal_event_wait__win32(pContext, pEvent); +#endif +#ifdef MAL_POSIX + return mal_event_wait__posix(pContext, pEvent); +#endif +} + +mal_bool32 mal_event_signal(mal_context* pContext, mal_event* pEvent) +{ + if (pEvent == NULL) return MAL_FALSE; + +#ifdef MAL_WIN32 + return mal_event_signal__win32(pContext, pEvent); +#endif +#ifdef MAL_POSIX + return mal_event_signal__posix(pContext, pEvent); +#endif +} + + +// Posts a log message. +static void mal_log(mal_context* pContext, mal_device* pDevice, const char* message) +{ + if (pContext == NULL) return; + + mal_log_proc onLog = pContext->config.onLog; + if (onLog) { + onLog(pContext, pDevice, message); + } +} + +// Posts an error. Throw a breakpoint in here if you're needing to debug. The return value is always "resultCode". +static mal_result mal_context_post_error(mal_context* pContext, mal_device* pDevice, const char* message, mal_result resultCode) +{ + // Derive the context from the device if necessary. + if (pContext == NULL) { + if (pDevice != NULL) { + pContext = pDevice->pContext; + } + } + + mal_log(pContext, pDevice, message); + return resultCode; +} + +static mal_result mal_post_error(mal_device* pDevice, const char* message, mal_result resultCode) +{ + return mal_context_post_error(NULL, pDevice, message, resultCode); +} + + +#if !defined(MAL_ANDROID) +static void mal_get_default_channel_mapping(mal_backend backend, mal_uint32 channels, mal_channel channelMap[MAL_MAX_CHANNELS]) +{ + if (channels == 1) { // Mono + channelMap[0] = MAL_CHANNEL_FRONT_CENTER; + } else if (channels == 2) { // Stereo + channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + } else if (channels == 3) { // 2.1 + channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + channelMap[2] = MAL_CHANNEL_LFE; + } else if (channels == 4) { // 4.0 + channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + channelMap[2] = MAL_CHANNEL_SIDE_LEFT; + channelMap[3] = MAL_CHANNEL_SIDE_RIGHT; + } else if (channels == 5) { // Not sure about this one. 4.1? + channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + channelMap[2] = MAL_CHANNEL_SIDE_LEFT; + channelMap[3] = MAL_CHANNEL_SIDE_RIGHT; + channelMap[4] = MAL_CHANNEL_LFE; + } else if (channels >= 6) { // 5.1 + // Some backends use different default layouts. + if (backend == mal_backend_wasapi || backend == mal_backend_dsound || backend == mal_backend_winmm || backend == mal_backend_oss) { + channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + channelMap[2] = MAL_CHANNEL_FRONT_CENTER; + channelMap[3] = MAL_CHANNEL_LFE; + channelMap[4] = MAL_CHANNEL_SIDE_LEFT; + channelMap[5] = MAL_CHANNEL_SIDE_RIGHT; + } else { + channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + channelMap[2] = MAL_CHANNEL_SIDE_LEFT; + channelMap[3] = MAL_CHANNEL_SIDE_RIGHT; + channelMap[4] = MAL_CHANNEL_FRONT_CENTER; + channelMap[5] = MAL_CHANNEL_LFE; + } + + if (channels == 7) { // Not sure about this one. + channelMap[6] = MAL_CHANNEL_BACK_CENTER; + } else { + // I don't know what mapping to use in this case, but I'm making it upwards compatible with 7.1. Good luck! + mal_assert(channels >= 8); + channelMap[6] = MAL_CHANNEL_BACK_LEFT; + channelMap[7] = MAL_CHANNEL_BACK_RIGHT; + + // Beyond 7.1 I'm just guessing... + if (channels == 9) { + channelMap[8] = MAL_CHANNEL_BACK_CENTER; + } else if (channels == 10) { + channelMap[8] = MAL_CHANNEL_FRONT_LEFT_CENTER; + channelMap[9] = MAL_CHANNEL_FRONT_RIGHT_CENTER; + } else if (channels == 11) { + channelMap[ 8] = MAL_CHANNEL_FRONT_LEFT_CENTER; + channelMap[ 9] = MAL_CHANNEL_FRONT_RIGHT_CENTER; + channelMap[10] = MAL_CHANNEL_BACK_CENTER; + } else { + mal_assert(channels >= 12); + for (mal_uint8 iChannel = 11; iChannel < channels && iChannel < MAL_MAX_CHANNELS; ++iChannel) { + channelMap[iChannel] = iChannel + 1; + } + } + } + } +} +#endif + + +// The callback for reading from the client -> DSP -> device. +static inline mal_uint32 mal_device__on_read_from_client(mal_uint32 frameCount, void* pFramesOut, void* pUserData) +{ + mal_device* pDevice = (mal_device*)pUserData; + mal_assert(pDevice != NULL); + + mal_send_proc onSend = pDevice->onSend; + if (onSend) { + return onSend(pDevice, frameCount, pFramesOut); + } + + return 0; +} + +// The callback for reading from the device -> DSP -> client. +static inline mal_uint32 mal_device__on_read_from_device(mal_uint32 frameCount, void* pFramesOut, void* pUserData) +{ + mal_device* pDevice = (mal_device*)pUserData; + mal_assert(pDevice != NULL); + + if (pDevice->_dspFrameCount == 0) { + return 0; // Nothing left. + } + + mal_uint32 framesToRead = frameCount; + if (framesToRead > pDevice->_dspFrameCount) { + framesToRead = pDevice->_dspFrameCount; + } + + mal_uint32 bytesToRead = framesToRead * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); + mal_copy_memory(pFramesOut, pDevice->_dspFrames, bytesToRead); + pDevice->_dspFrameCount -= framesToRead; + pDevice->_dspFrames += bytesToRead; + + return framesToRead; +} + +// A helper function for reading sample data from the client. Returns the number of samples read from the client. Remaining samples +// are filled with silence. +static inline mal_uint32 mal_device__read_frames_from_client(mal_device* pDevice, mal_uint32 frameCount, void* pSamples) +{ + mal_assert(pDevice != NULL); + mal_assert(frameCount > 0); + mal_assert(pSamples != NULL); + + mal_uint32 framesRead = mal_dsp_read_frames(&pDevice->dsp, frameCount, pSamples); + mal_uint32 samplesRead = framesRead * pDevice->internalChannels; + mal_uint32 sampleSize = mal_get_sample_size_in_bytes(pDevice->internalFormat); + mal_uint32 consumedBytes = samplesRead*sampleSize; + mal_uint32 remainingBytes = ((frameCount * pDevice->internalChannels) - samplesRead)*sampleSize; + mal_zero_memory((mal_uint8*)pSamples + consumedBytes, remainingBytes); + + return samplesRead; +} + +// A helper for sending sample data to the client. +static inline void mal_device__send_frames_to_client(mal_device* pDevice, mal_uint32 frameCount, const void* pSamples) +{ + mal_assert(pDevice != NULL); + mal_assert(frameCount > 0); + mal_assert(pSamples != NULL); + + mal_recv_proc onRecv = pDevice->onRecv; + if (onRecv) { + pDevice->_dspFrameCount = frameCount; + pDevice->_dspFrames = (const mal_uint8*)pSamples; + + mal_uint8 chunkBuffer[4096]; + mal_uint32 chunkFrameCount = sizeof(chunkBuffer) / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; + + for (;;) { + mal_uint32 framesJustRead = mal_dsp_read_frames(&pDevice->dsp, chunkFrameCount, chunkBuffer); + if (framesJustRead == 0) { + break; + } + + onRecv(pDevice, framesJustRead, chunkBuffer); + + if (framesJustRead < chunkFrameCount) { + break; + } + } + } +} + +// A helper for changing the state of the device. +static inline void mal_device__set_state(mal_device* pDevice, mal_uint32 newState) +{ + mal_atomic_exchange_32(&pDevice->state, newState); +} + +// A helper for getting the state of the device. +static inline mal_uint32 mal_device__get_state(mal_device* pDevice) +{ + return pDevice->state; +} + + +#ifdef MAL_WIN32 +static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +//static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +//static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// +// Null Backend +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_ENABLE_NULL +mal_result mal_context_init__null(mal_context* pContext) +{ + mal_assert(pContext != NULL); + + // The null backend always works. + (void)pContext; + return MAL_SUCCESS; +} + +mal_result mal_context_uninit__null(mal_context* pContext) +{ + mal_assert(pContext != NULL); + mal_assert(pContext->backend == mal_backend_null); + + (void)pContext; + return MAL_SUCCESS; +} + +static mal_result mal_enumerate_devices__null(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) +{ + (void)pContext; + + mal_uint32 infoSize = *pCount; + *pCount = 1; // There's only one "device" each for playback and recording for the null backend. + + if (pInfo != NULL && infoSize > 0) { + mal_zero_object(pInfo); + + if (type == mal_device_type_playback) { + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "NULL Playback Device", (size_t)-1); + } else { + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "NULL Capture Device", (size_t)-1); + } + } + + return MAL_SUCCESS; +} + +static void mal_device_uninit__null(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + mal_free(pDevice->null_device.pBuffer); +} + +static mal_result mal_device_init__null(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) +{ + (void)pContext; + (void)type; + (void)pDeviceID; + + mal_assert(pDevice != NULL); + mal_zero_object(&pDevice->null_device); + + pDevice->bufferSizeInFrames = pConfig->bufferSizeInFrames; + pDevice->periods = pConfig->periods; + + pDevice->null_device.pBuffer = (mal_uint8*)mal_malloc(pDevice->bufferSizeInFrames * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format)); + if (pDevice->null_device.pBuffer == NULL) { + return MAL_OUT_OF_MEMORY; + } + + mal_zero_memory(pDevice->null_device.pBuffer, mal_device_get_buffer_size_in_bytes(pDevice)); + + return MAL_SUCCESS; +} + +static mal_result mal_device__start_backend__null(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + mal_timer_init(&pDevice->null_device.timer); + pDevice->null_device.lastProcessedFrame = 0; + + return MAL_SUCCESS; +} + +static mal_result mal_device__stop_backend__null(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + (void)pDevice; + + return MAL_SUCCESS; +} + +static mal_result mal_device__break_main_loop__null(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + pDevice->null_device.breakFromMainLoop = MAL_TRUE; + return MAL_SUCCESS; +} + +static mal_bool32 mal_device__get_current_frame__null(mal_device* pDevice, mal_uint32* pCurrentPos) +{ + mal_assert(pDevice != NULL); + mal_assert(pCurrentPos != NULL); + *pCurrentPos = 0; + + mal_uint64 currentFrameAbs = (mal_uint64)(mal_timer_get_time_in_seconds(&pDevice->null_device.timer) * pDevice->sampleRate) / pDevice->channels; + + *pCurrentPos = (mal_uint32)(currentFrameAbs % pDevice->bufferSizeInFrames); + return MAL_TRUE; +} + +static mal_uint32 mal_device__get_available_frames__null(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + mal_uint32 currentFrame; + if (!mal_device__get_current_frame__null(pDevice, ¤tFrame)) { + return 0; + } + + // In a playback device the last processed frame should always be ahead of the current frame. The space between + // the last processed and current frame (moving forward, starting from the last processed frame) is the amount + // of space available to write. + // + // For a recording device it's the other way around - the last processed frame is always _behind_ the current + // frame and the space between is the available space. + mal_uint32 totalFrameCount = pDevice->bufferSizeInFrames; + if (pDevice->type == mal_device_type_playback) { + mal_uint32 committedBeg = currentFrame; + mal_uint32 committedEnd = pDevice->null_device.lastProcessedFrame; + if (committedEnd <= committedBeg) { + committedEnd += totalFrameCount; // Wrap around. + } + + mal_uint32 committedSize = (committedEnd - committedBeg); + mal_assert(committedSize <= totalFrameCount); + + return totalFrameCount - committedSize; + } else { + mal_uint32 validBeg = pDevice->null_device.lastProcessedFrame; + mal_uint32 validEnd = currentFrame; + if (validEnd < validBeg) { + validEnd += totalFrameCount; // Wrap around. + } + + mal_uint32 validSize = (validEnd - validBeg); + mal_assert(validSize <= totalFrameCount); + + return validSize; + } +} + +static mal_uint32 mal_device__wait_for_frames__null(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + while (!pDevice->null_device.breakFromMainLoop) { + mal_uint32 framesAvailable = mal_device__get_available_frames__null(pDevice); + if (framesAvailable > 0) { + return framesAvailable; + } + + mal_sleep(16); + } + + // We'll get here if the loop was terminated. Just return whatever's available. + return mal_device__get_available_frames__null(pDevice); +} + +static mal_result mal_device__main_loop__null(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + pDevice->null_device.breakFromMainLoop = MAL_FALSE; + while (!pDevice->null_device.breakFromMainLoop) { + mal_uint32 framesAvailable = mal_device__wait_for_frames__null(pDevice); + if (framesAvailable == 0) { + continue; + } + + // If it's a playback device, don't bother grabbing more data if the device is being stopped. + if (pDevice->null_device.breakFromMainLoop && pDevice->type == mal_device_type_playback) { + return MAL_FALSE; + } + + if (framesAvailable + pDevice->null_device.lastProcessedFrame > pDevice->bufferSizeInFrames) { + framesAvailable = pDevice->bufferSizeInFrames - pDevice->null_device.lastProcessedFrame; + } + + mal_uint32 sampleCount = framesAvailable * pDevice->channels; + mal_uint32 lockOffset = pDevice->null_device.lastProcessedFrame * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); + mal_uint32 lockSize = sampleCount * mal_get_sample_size_in_bytes(pDevice->format); + + if (pDevice->type == mal_device_type_playback) { + if (pDevice->null_device.breakFromMainLoop) { + return MAL_FALSE; + } + + mal_device__read_frames_from_client(pDevice, framesAvailable, pDevice->null_device.pBuffer + lockOffset); + } else { + mal_zero_memory(pDevice->null_device.pBuffer + lockOffset, lockSize); + mal_device__send_frames_to_client(pDevice, framesAvailable, pDevice->null_device.pBuffer + lockOffset); + } + + pDevice->null_device.lastProcessedFrame = (pDevice->null_device.lastProcessedFrame + framesAvailable) % pDevice->bufferSizeInFrames; + } + + return MAL_SUCCESS; +} +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// +// WIN32 COMMON +// +/////////////////////////////////////////////////////////////////////////////// +#if defined(MAL_WIN32) +#include "objbase.h" +#if defined(MAL_WIN32_DESKTOP) + #define mal_CoInitializeEx(pContext, pvReserved, dwCoInit) ((MAL_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit) + #define mal_CoUninitialize(pContext) ((MAL_PFN_CoUninitialize)pContext->win32.CoUninitialize)() + #define mal_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) ((MAL_PFN_CoCreateInstance)pContext->win32.CoCreateInstance)(rclsid, pUnkOuter, dwClsContext, riid, ppv) + #define mal_CoTaskMemFree(pContext, pv) ((MAL_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(pv) + #define mal_PropVariantClear(pContext, pvar) ((MAL_PFN_PropVariantClear)pContext->win32.PropVariantClear)(pvar) +#else + #define mal_CoInitializeEx(pContext, pvReserved, dwCoInit) CoInitializeEx(pvReserved, dwCoInit) + #define mal_CoUninitialize(pContext) CoUninitialize() + #define mal_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv) + #define mal_CoTaskMemFree(pContext, pv) CoTaskMemFree(pv) + #define mal_PropVariantClear(pContext, pvar) PropVariantClear(pvar) +#endif +#endif + +#if defined(MAL_ENABLE_WASAPI) || defined(MAL_ENABLE_DSOUND) +#include + +#ifndef SPEAKER_FRONT_LEFT +#define SPEAKER_FRONT_LEFT 0x1 +#define SPEAKER_FRONT_RIGHT 0x2 +#define SPEAKER_FRONT_CENTER 0x4 +#define SPEAKER_LOW_FREQUENCY 0x8 +#define SPEAKER_BACK_LEFT 0x10 +#define SPEAKER_BACK_RIGHT 0x20 +#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 +#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 +#define SPEAKER_BACK_CENTER 0x100 +#define SPEAKER_SIDE_LEFT 0x200 +#define SPEAKER_SIDE_RIGHT 0x400 +#define SPEAKER_TOP_CENTER 0x800 +#define SPEAKER_TOP_FRONT_LEFT 0x1000 +#define SPEAKER_TOP_FRONT_CENTER 0x2000 +#define SPEAKER_TOP_FRONT_RIGHT 0x4000 +#define SPEAKER_TOP_BACK_LEFT 0x8000 +#define SPEAKER_TOP_BACK_CENTER 0x10000 +#define SPEAKER_TOP_BACK_RIGHT 0x20000 +#endif + +// The SDK that comes with old versions of MSVC (VC6, for example) does not appear to define WAVEFORMATEXTENSIBLE. We +// define our own implementation in this case. +#ifndef _WAVEFORMATEXTENSIBLE_ +typedef struct +{ + WAVEFORMATEX Format; + union + { + WORD wValidBitsPerSample; + WORD wSamplesPerBlock; + WORD wReserved; + } Samples; + DWORD dwChannelMask; + GUID SubFormat; +} WAVEFORMATEXTENSIBLE; +#endif + +#ifndef WAVE_FORMAT_EXTENSIBLE +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif + +// Converts an individual Win32-style channel identifier (SPEAKER_FRONT_LEFT, etc.) to mini_al. +static mal_uint8 mal_channel_id_to_mal__win32(DWORD id) +{ + switch (id) + { + case SPEAKER_FRONT_LEFT: return MAL_CHANNEL_FRONT_LEFT; + case SPEAKER_FRONT_RIGHT: return MAL_CHANNEL_FRONT_RIGHT; + case SPEAKER_FRONT_CENTER: return MAL_CHANNEL_FRONT_CENTER; + case SPEAKER_LOW_FREQUENCY: return MAL_CHANNEL_LFE; + case SPEAKER_BACK_LEFT: return MAL_CHANNEL_BACK_LEFT; + case SPEAKER_BACK_RIGHT: return MAL_CHANNEL_BACK_RIGHT; + case SPEAKER_FRONT_LEFT_OF_CENTER: return MAL_CHANNEL_FRONT_LEFT_CENTER; + case SPEAKER_FRONT_RIGHT_OF_CENTER: return MAL_CHANNEL_FRONT_RIGHT_CENTER; + case SPEAKER_BACK_CENTER: return MAL_CHANNEL_BACK_CENTER; + case SPEAKER_SIDE_LEFT: return MAL_CHANNEL_SIDE_LEFT; + case SPEAKER_SIDE_RIGHT: return MAL_CHANNEL_SIDE_RIGHT; + case SPEAKER_TOP_CENTER: return MAL_CHANNEL_TOP_CENTER; + case SPEAKER_TOP_FRONT_LEFT: return MAL_CHANNEL_TOP_FRONT_LEFT; + case SPEAKER_TOP_FRONT_CENTER: return MAL_CHANNEL_TOP_FRONT_CENTER; + case SPEAKER_TOP_FRONT_RIGHT: return MAL_CHANNEL_TOP_FRONT_RIGHT; + case SPEAKER_TOP_BACK_LEFT: return MAL_CHANNEL_TOP_BACK_LEFT; + case SPEAKER_TOP_BACK_CENTER: return MAL_CHANNEL_TOP_BACK_CENTER; + case SPEAKER_TOP_BACK_RIGHT: return MAL_CHANNEL_TOP_BACK_RIGHT; + default: return 0; + } +} + +// Converts an individual mini_al channel identifier (MAL_CHANNEL_FRONT_LEFT, etc.) to Win32-style. +static DWORD mal_channel_id_to_win32(DWORD id) +{ + switch (id) + { + case MAL_CHANNEL_FRONT_LEFT: return SPEAKER_FRONT_LEFT; + case MAL_CHANNEL_FRONT_RIGHT: return SPEAKER_FRONT_RIGHT; + case MAL_CHANNEL_FRONT_CENTER: return SPEAKER_FRONT_CENTER; + case MAL_CHANNEL_LFE: return SPEAKER_LOW_FREQUENCY; + case MAL_CHANNEL_BACK_LEFT: return SPEAKER_BACK_LEFT; + case MAL_CHANNEL_BACK_RIGHT: return SPEAKER_BACK_RIGHT; + case MAL_CHANNEL_FRONT_LEFT_CENTER: return SPEAKER_FRONT_LEFT_OF_CENTER; + case MAL_CHANNEL_FRONT_RIGHT_CENTER: return SPEAKER_FRONT_RIGHT_OF_CENTER; + case MAL_CHANNEL_BACK_CENTER: return SPEAKER_BACK_CENTER; + case MAL_CHANNEL_SIDE_LEFT: return SPEAKER_SIDE_LEFT; + case MAL_CHANNEL_SIDE_RIGHT: return SPEAKER_SIDE_RIGHT; + case MAL_CHANNEL_TOP_CENTER: return SPEAKER_TOP_CENTER; + case MAL_CHANNEL_TOP_FRONT_LEFT: return SPEAKER_TOP_FRONT_LEFT; + case MAL_CHANNEL_TOP_FRONT_CENTER: return SPEAKER_TOP_FRONT_CENTER; + case MAL_CHANNEL_TOP_FRONT_RIGHT: return SPEAKER_TOP_FRONT_RIGHT; + case MAL_CHANNEL_TOP_BACK_LEFT: return SPEAKER_TOP_BACK_LEFT; + case MAL_CHANNEL_TOP_BACK_CENTER: return SPEAKER_TOP_BACK_CENTER; + case MAL_CHANNEL_TOP_BACK_RIGHT: return SPEAKER_TOP_BACK_RIGHT; + default: return 0; + } +} + +// Converts a channel mapping to a Win32-style channel mask. +static DWORD mal_channel_map_to_channel_mask__win32(const mal_uint8 channelMap[MAL_MAX_CHANNELS], mal_uint32 channels) +{ + DWORD dwChannelMask = 0; + for (mal_uint32 iChannel = 0; iChannel < channels; ++iChannel) { + dwChannelMask |= mal_channel_id_to_win32(channelMap[iChannel]); + } + + return dwChannelMask; +} + +// Converts a Win32-style channel mask to a mini_al channel map. +static void mal_channel_mask_to_channel_map__win32(DWORD dwChannelMask, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) +{ + if (channels == 1 && dwChannelMask == 0) { + channelMap[0] = MAL_CHANNEL_FRONT_CENTER; + } else if (channels == 2 && dwChannelMask == 0) { + channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + } else { + // Just iterate over each bit. + mal_uint32 iChannel = 0; + for (mal_uint32 iBit = 0; iBit < 32; ++iBit) { + DWORD bitValue = (dwChannelMask & (1 << iBit)); + if (bitValue != 0) { + // The bit is set. + channelMap[iChannel] = mal_channel_id_to_mal__win32(bitValue); + iChannel += 1; + } + } + } +} +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// +// WASAPI Backend +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_ENABLE_WASAPI +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable:4091) // 'typedef ': ignored on left of '' when no variable is declared +#endif +#include +#include +#include +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + +const PROPERTYKEY g_malPKEY_Device_FriendlyName = {{0xa45c254e, 0xdf1c, 0x4efd, {0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0}}, 14}; +const PROPERTYKEY g_malPKEY_AudioEngine_DeviceFormat = {{0xf19f064d, 0x82c, 0x4e27, {0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c}}, 0}; + +const IID g_malCLSID_MMDeviceEnumerator_Instance = {0xBCDE0395, 0xE52F, 0x467C, {0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E}}; // BCDE0395-E52F-467C-8E3D-C4579291692E = __uuidof(MMDeviceEnumerator) +const IID g_malIID_IMMDeviceEnumerator_Instance = {0xA95664D2, 0x9614, 0x4F35, {0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6}}; // A95664D2-9614-4F35-A746-DE8DB63617E6 = __uuidof(IMMDeviceEnumerator) +const IID g_malIID_IAudioClient_Instance = {0x1CB9AD4C, 0xDBFA, 0x4C32, {0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2}}; // 1CB9AD4C-DBFA-4C32-B178-C2F568A703B2 = __uuidof(IAudioClient) +const IID g_malIID_IAudioRenderClient_Instance = {0xF294ACFC, 0x3146, 0x4483, {0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2}}; // F294ACFC-3146-4483-A7BF-ADDCA7C260E2 = __uuidof(IAudioRenderClient) +const IID g_malIID_IAudioCaptureClient_Instance = {0xC8ADBD64, 0xE71E, 0x48A0, {0xA4, 0xDE, 0x18, 0x5C, 0x39, 0x5C, 0xD3, 0x17}}; // C8ADBD64-E71E-48A0-A4DE-185C395CD317 = __uuidof(IAudioCaptureClient) + +#ifndef MAL_WIN32_DESKTOP +const IID g_malIID_DEVINTERFACE_AUDIO_RENDER = {0xE6327CAD, 0xDCEC, 0x4949, {0xAE, 0x8A, 0x99, 0x1E, 0x97, 0x6A, 0x79, 0xD2}}; // E6327CAD-DCEC-4949-AE8A-991E976A79D2 +const IID g_malIID_DEVINTERFACE_AUDIO_CAPTURE = {0x2EEF81BE, 0x33FA, 0x4800, {0x96, 0x70, 0x1C, 0xD4, 0x74, 0x97, 0x2C, 0x3F}}; // 2EEF81BE-33FA-4800-9670-1CD474972C3F +#endif + +#ifdef __cplusplus +#define g_malCLSID_MMDeviceEnumerator g_malCLSID_MMDeviceEnumerator_Instance +#define g_malIID_IMMDeviceEnumerator g_malIID_IMMDeviceEnumerator_Instance +#define g_malIID_IAudioClient g_malIID_IAudioClient_Instance +#define g_malIID_IAudioRenderClient g_malIID_IAudioRenderClient_Instance +#define g_malIID_IAudioCaptureClient g_malIID_IAudioCaptureClient_Instance +#else +#define g_malCLSID_MMDeviceEnumerator &g_malCLSID_MMDeviceEnumerator_Instance +#define g_malIID_IMMDeviceEnumerator &g_malIID_IMMDeviceEnumerator_Instance +#define g_malIID_IAudioClient &g_malIID_IAudioClient_Instance +#define g_malIID_IAudioRenderClient &g_malIID_IAudioRenderClient_Instance +#define g_malIID_IAudioCaptureClient &g_malIID_IAudioCaptureClient_Instance +#endif + +#ifdef __cplusplus +#define mal_is_guid_equal(a, b) IsEqualGUID(a, b) +#else +#define mal_is_guid_equal(a, b) IsEqualGUID(&a, &b) +#endif + +#ifdef MAL_WIN32_DESKTOP + // IMMDeviceEnumerator + #ifdef __cplusplus + #define IMMDeviceEnumerator_Release(p) ((IMMDeviceEnumerator*)p)->Release() + #else + #define IMMDeviceEnumerator_Release(p) ((IMMDeviceEnumerator*)p)->lpVtbl->Release((IMMDeviceEnumerator*)p) + #endif + #ifdef __cplusplus + #define IMMDeviceEnumerator_EnumAudioEndpoints(p, a, b, c) ((IMMDeviceEnumerator*)p)->EnumAudioEndpoints(a, b, c) + #else + #define IMMDeviceEnumerator_EnumAudioEndpoints(p, a, b, c) ((IMMDeviceEnumerator*)p)->lpVtbl->EnumAudioEndpoints(p, a, b, c) + #endif + #ifdef __cplusplus + #define IMMDeviceEnumerator_GetDefaultAudioEndpoint(p, a, b, c) ((IMMDeviceEnumerator*)p)->GetDefaultAudioEndpoint(a, b, c) + #else + #define IMMDeviceEnumerator_GetDefaultAudioEndpoint(p, a, b, c) ((IMMDeviceEnumerator*)p)->lpVtbl->GetDefaultAudioEndpoint(p, a, b, c) + #endif + #ifdef __cplusplus + #define IMMDeviceEnumerator_GetDevice(p, a, b) ((IMMDeviceEnumerator*)p)->GetDevice(a, b) + #else + #define IMMDeviceEnumerator_GetDevice(p, a, b) ((IMMDeviceEnumerator*)p)->lpVtbl->GetDevice(p, a, b) + #endif + + // IMMDeviceCollection + #ifdef __cplusplus + #define IMMDeviceCollection_Release(p) ((IMMDeviceCollection*)p)->Release() + #else + #define IMMDeviceCollection_Release(p) ((IMMDeviceCollection*)p)->lpVtbl->Release((IMMDeviceCollection*)p) + #endif + #ifdef __cplusplus + #define IMMDeviceCollection_GetCount(p, a) ((IMMDeviceCollection*)p)->GetCount(a) + #else + #define IMMDeviceCollection_GetCount(p, a) ((IMMDeviceCollection*)p)->lpVtbl->GetCount((IMMDeviceCollection*)p, a) + #endif + #ifdef __cplusplus + #define IMMDeviceCollection_Item(p, a, b) ((IMMDeviceCollection*)p)->Item(a, b) + #else + #define IMMDeviceCollection_Item(p, a, b) ((IMMDeviceCollection*)p)->lpVtbl->Item((IMMDeviceCollection*)p, a, b) + #endif + + // IMMDevice + #ifdef __cplusplus + #define IMMDevice_Release(p) ((IMMDevice*)p)->Release() + #else + #define IMMDevice_Release(p) ((IMMDevice*)p)->lpVtbl->Release((IMMDevice*)p) + #endif + #ifdef __cplusplus + #define IMMDevice_GetId(p, a) ((IMMDevice*)p)->GetId(a) + #else + #define IMMDevice_GetId(p, a) ((IMMDevice*)p)->lpVtbl->GetId((IMMDevice*)p, a) + #endif + #ifdef __cplusplus + #define IMMDevice_OpenPropertyStore(p, a, b) ((IMMDevice*)p)->OpenPropertyStore(a, b) + #else + #define IMMDevice_OpenPropertyStore(p, a, b) ((IMMDevice*)p)->lpVtbl->OpenPropertyStore((IMMDevice*)p, a, b) + #endif + #ifdef __cplusplus + #define IMMDevice_Activate(p, a, b, c, d) ((IMMDevice*)p)->Activate(a, b, c, d) + #else + #define IMMDevice_Activate(p, a, b, c, d) ((IMMDevice*)p)->lpVtbl->Activate((IMMDevice*)p, a, b, c, d) + #endif +#else + // IActivateAudioInterfaceAsyncOperation + #ifdef __cplusplus + #define IActivateAudioInterfaceAsyncOperation_Release(p) ((IActivateAudioInterfaceAsyncOperation*)p)->Release() + #else + #define IActivateAudioInterfaceAsyncOperation_Release(p) ((IActivateAudioInterfaceAsyncOperation*)p)->lpVtbl->Release((IActivateAudioInterfaceAsyncOperation*)p) + #endif + #ifdef __cplusplus + #define IActivateAudioInterfaceAsyncOperation_GetActivateResult(p, a, b) ((IActivateAudioInterfaceAsyncOperation*)p)->GetActivateResult(a, b) + #else + #define IActivateAudioInterfaceAsyncOperation_GetActivateResult(p, a, b) ((IActivateAudioInterfaceAsyncOperation*)p)->lpVtbl->GetActivateResult((IActivateAudioInterfaceAsyncOperation*)p, a, b) + #endif +#endif + +// IPropertyStore +#ifdef __cplusplus + #define IPropertyStore_Release(p) ((IPropertyStore*)p)->Release() +#else + #define IPropertyStore_Release(p) ((IPropertyStore*)p)->lpVtbl->Release((IPropertyStore*)p) +#endif +#ifdef __cplusplus + #define IPropertyStore_GetValue(p, a, b) ((IPropertyStore*)p)->GetValue(a, b) +#else + #define IPropertyStore_GetValue(p, a, b) ((IPropertyStore*)p)->lpVtbl->GetValue((IPropertyStore*)p, &a, b) +#endif + +// IAudioClient +#ifdef __cplusplus + #define IAudioClient_Release(p) ((IAudioClient*)p)->Release() +#else + #define IAudioClient_Release(p) ((IAudioClient*)p)->lpVtbl->Release((IAudioClient*)p) +#endif +#ifdef __cplusplus + #define IAudioClient_IsFormatSupported(p, a, b, c) ((IAudioClient*)p)->IsFormatSupported(a, b, c) +#else + #define IAudioClient_IsFormatSupported(p, a, b, c) ((IAudioClient*)p)->lpVtbl->IsFormatSupported((IAudioClient*)p, a, b, c) +#endif +#ifdef __cplusplus + #define IAudioClient_GetMixFormat(p, a) ((IAudioClient*)p)->GetMixFormat(a) +#else + #define IAudioClient_GetMixFormat(p, a) ((IAudioClient*)p)->lpVtbl->GetMixFormat((IAudioClient*)p, a) +#endif +#ifdef __cplusplus + #define IAudioClient_Initialize(p, a, b, c, d, e, f) ((IAudioClient*)p)->Initialize(a, b, c, d, e, f) +#else + #define IAudioClient_Initialize(p, a, b, c, d, e, f) ((IAudioClient*)p)->lpVtbl->Initialize((IAudioClient*)p, a, b, c, d, e, f) +#endif +#ifdef __cplusplus + #define IAudioClient_GetBufferSize(p, a) ((IAudioClient*)p)->GetBufferSize(a) +#else + #define IAudioClient_GetBufferSize(p, a) ((IAudioClient*)p)->lpVtbl->GetBufferSize((IAudioClient*)p, a) +#endif +#ifdef __cplusplus + #define IAudioClient_GetService(p, a, b) ((IAudioClient*)p)->GetService(a, b) +#else + #define IAudioClient_GetService(p, a, b) ((IAudioClient*)p)->lpVtbl->GetService((IAudioClient*)p, a, b) +#endif +#ifdef __cplusplus + #define IAudioClient_Start(p) ((IAudioClient*)p)->Start() +#else + #define IAudioClient_Start(p) ((IAudioClient*)p)->lpVtbl->Start((IAudioClient*)p) +#endif +#ifdef __cplusplus + #define IAudioClient_Stop(p) ((IAudioClient*)p)->Stop() +#else + #define IAudioClient_Stop(p) ((IAudioClient*)p)->lpVtbl->Stop((IAudioClient*)p) +#endif +#ifdef __cplusplus + #define IAudioClient_GetCurrentPadding(p, a) ((IAudioClient*)p)->GetCurrentPadding(a) +#else + #define IAudioClient_GetCurrentPadding(p, a) ((IAudioClient*)p)->lpVtbl->GetCurrentPadding((IAudioClient*)p, a) +#endif +#ifdef __cplusplus + #define IAudioClient_SetEventHandle(p, a) ((IAudioClient*)p)->SetEventHandle(a) +#else + #define IAudioClient_SetEventHandle(p, a) ((IAudioClient*)p)->lpVtbl->SetEventHandle((IAudioClient*)p, a) +#endif + +// IAudioRenderClient +#ifdef __cplusplus + #define IAudioRenderClient_Release(p) ((IAudioRenderClient*)p)->Release() +#else + #define IAudioRenderClient_Release(p) ((IAudioRenderClient*)p)->lpVtbl->Release((IAudioRenderClient*)p) +#endif +#ifdef __cplusplus + #define IAudioRenderClient_GetBuffer(p, a, b) ((IAudioRenderClient*)p)->GetBuffer(a, b) +#else + #define IAudioRenderClient_GetBuffer(p, a, b) ((IAudioRenderClient*)p)->lpVtbl->GetBuffer((IAudioRenderClient*)p, a, b) +#endif +#ifdef __cplusplus + #define IAudioRenderClient_ReleaseBuffer(p, a, b) ((IAudioRenderClient*)p)->ReleaseBuffer(a, b) +#else + #define IAudioRenderClient_ReleaseBuffer(p, a, b) ((IAudioRenderClient*)p)->lpVtbl->ReleaseBuffer((IAudioRenderClient*)p, a, b) +#endif + +// IAudioCaptureClient +#ifdef __cplusplus + #define IAudioCaptureClient_Release(p) ((IAudioCaptureClient*)p)->Release() +#else + #define IAudioCaptureClient_Release(p) ((IAudioCaptureClient*)p)->lpVtbl->Release((IAudioCaptureClient*)p) +#endif +#ifdef __cplusplus + #define IAudioCaptureClient_GetNextPacketSize(p, a) ((IAudioCaptureClient*)p)->GetNextPacketSize(a) +#else + #define IAudioCaptureClient_GetNextPacketSize(p, a) ((IAudioCaptureClient*)p)->lpVtbl->GetNextPacketSize((IAudioCaptureClient*)p, a) +#endif +#ifdef __cplusplus + #define IAudioCaptureClient_GetBuffer(p, a, b, c, d, e) ((IAudioCaptureClient*)p)->GetBuffer(a, b, c, d, e) +#else + #define IAudioCaptureClient_GetBuffer(p, a, b, c, d, e) ((IAudioCaptureClient*)p)->lpVtbl->GetBuffer((IAudioCaptureClient*)p, a, b, c, d, e) +#endif +#ifdef __cplusplus + #define IAudioCaptureClient_ReleaseBuffer(p, a) ((IAudioCaptureClient*)p)->ReleaseBuffer(a) +#else + #define IAudioCaptureClient_ReleaseBuffer(p, a) ((IAudioCaptureClient*)p)->lpVtbl->ReleaseBuffer((IAudioCaptureClient*)p, a) +#endif + +mal_result mal_context_init__wasapi(mal_context* pContext) +{ + mal_assert(pContext != NULL); + (void)pContext; + +#ifdef MAL_WIN32_DESKTOP + // WASAPI is only supported in Vista SP1 and newer. The reason for SP1 and not the base version of Vista is that event-driven + // exclusive mode does not work until SP1. + OSVERSIONINFOEXW osvi; + mal_zero_object(&osvi); + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMajorVersion = HIBYTE(_WIN32_WINNT_VISTA); + osvi.dwMinorVersion = LOBYTE(_WIN32_WINNT_VISTA); + osvi.wServicePackMajor = 1; + if (VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL), VER_MINORVERSION, VER_GREATER_EQUAL), VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL))) { + return MAL_SUCCESS; + } else { + return MAL_NO_BACKEND; + } +#else + return MAL_SUCCESS; +#endif +} + +mal_result mal_context_uninit__wasapi(mal_context* pContext) +{ + mal_assert(pContext != NULL); + mal_assert(pContext->backend == mal_backend_wasapi); + (void)pContext; + + return MAL_SUCCESS; +} + +static mal_result mal_enumerate_devices__wasapi(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) +{ + mal_uint32 infoSize = *pCount; + *pCount = 0; + +#ifdef MAL_WIN32_DESKTOP + IMMDeviceEnumerator* pDeviceEnumerator; + HRESULT hr = mal_CoCreateInstance(pContext, g_malCLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, g_malIID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); + if (FAILED(hr)) { + return mal_context_post_error(pContext, NULL, "[WASAPI] Failed to create device enumerator.", MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR); + } + + IMMDeviceCollection* pDeviceCollection; + hr = IMMDeviceEnumerator_EnumAudioEndpoints(pDeviceEnumerator, (type == mal_device_type_playback) ? eRender : eCapture, DEVICE_STATE_ACTIVE, &pDeviceCollection); + if (FAILED(hr)) { + IMMDeviceEnumerator_Release(pDeviceEnumerator); + return mal_context_post_error(pContext, NULL, "[WASAPI] Failed to enumerate audio endpoints.", MAL_NO_DEVICE); + } + + IMMDeviceEnumerator_Release(pDeviceEnumerator); + + UINT count; + hr = IMMDeviceCollection_GetCount(pDeviceCollection, &count); + if (FAILED(hr)) { + IMMDeviceCollection_Release(pDeviceCollection); + return mal_context_post_error(pContext, NULL, "[WASAPI] Failed to get device count.", MAL_NO_DEVICE); + } + + for (mal_uint32 iDevice = 0; iDevice < count; ++iDevice) { + if (pInfo != NULL) { + if (infoSize > 0) { + mal_zero_object(pInfo); + + IMMDevice* pDevice; + hr = IMMDeviceCollection_Item(pDeviceCollection, iDevice, &pDevice); + if (SUCCEEDED(hr)) { + // ID. + LPWSTR id; + hr = IMMDevice_GetId(pDevice, &id); + if (SUCCEEDED(hr)) { + size_t idlen = wcslen(id); + if (idlen+sizeof(wchar_t) > sizeof(pInfo->id.wasapi)) { + mal_CoTaskMemFree(pContext, id); + mal_assert(MAL_FALSE); // NOTE: If this is triggered, please report it. It means the format of the ID must haved change and is too long to fit in our fixed sized buffer. + continue; + } + + memcpy(pInfo->id.wasapi, id, idlen * sizeof(wchar_t)); + pInfo->id.wasapi[idlen] = '\0'; + + mal_CoTaskMemFree(pContext, id); + } + + // Description / Friendly Name. + IPropertyStore *pProperties; + hr = IMMDevice_OpenPropertyStore(pDevice, STGM_READ, &pProperties); + if (SUCCEEDED(hr)) { + PROPVARIANT varName; + PropVariantInit(&varName); + hr = IPropertyStore_GetValue(pProperties, g_malPKEY_Device_FriendlyName, &varName); + if (SUCCEEDED(hr)) { + WideCharToMultiByte(CP_UTF8, 0, varName.pwszVal, -1, pInfo->name, sizeof(pInfo->name), 0, FALSE); + mal_PropVariantClear(pContext, &varName); + } + + IPropertyStore_Release(pProperties); + } + } + + pInfo += 1; + infoSize -= 1; + *pCount += 1; + } + } else { + *pCount += 1; + } + } + + IMMDeviceCollection_Release(pDeviceCollection); +#else + // The MMDevice API is only supported on desktop applications. For now, while I'm still figuring out how to properly enumerate + // over devices without using MMDevice, I'm restricting devices to defaults. + if (pInfo != NULL) { + if (infoSize > 0) { + if (type == mal_device_type_playback) { + mal_copy_memory(pInfo->id.wasapi, &g_malIID_DEVINTERFACE_AUDIO_RENDER, sizeof(g_malIID_DEVINTERFACE_AUDIO_RENDER)); + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1); + } else { + mal_copy_memory(pInfo->id.wasapi, &g_malIID_DEVINTERFACE_AUDIO_CAPTURE, sizeof(g_malIID_DEVINTERFACE_AUDIO_CAPTURE)); + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1); + } + + pInfo += 1; + *pCount += 1; + } + } else { + *pCount += 1; + } +#endif + + return MAL_SUCCESS; +} + +static void mal_device_uninit__wasapi(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->wasapi.pRenderClient) { + IAudioRenderClient_Release(pDevice->wasapi.pRenderClient); + } + if (pDevice->wasapi.pCaptureClient) { + IAudioCaptureClient_Release(pDevice->wasapi.pCaptureClient); + } + if (pDevice->wasapi.pAudioClient) { + IAudioClient_Release(pDevice->wasapi.pAudioClient); + } + + if (pDevice->wasapi.hEvent) { + CloseHandle(pDevice->wasapi.hEvent); + } + if (pDevice->wasapi.hStopEvent) { + CloseHandle(pDevice->wasapi.hStopEvent); + } +} + +#ifndef MAL_WIN32_DESKTOP + #ifdef __cplusplus + #include + class malCompletionHandler : public Microsoft::WRL::RuntimeClass< Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::ClassicCom >, Microsoft::WRL::FtmBase, IActivateAudioInterfaceCompletionHandler > + { + public: + + malCompletionHandler() + : m_hEvent(NULL) + { + } + + mal_result Init() + { + m_hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + if (m_hEvent == NULL) { + return MAL_ERROR; + } + + return MAL_SUCCESS; + } + + void Uninit() + { + if (m_hEvent != NULL) { + CloseHandle(m_hEvent); + } + } + + void Wait() + { + WaitForSingleObject(m_hEvent, INFINITE); + } + + HRESULT STDMETHODCALLTYPE ActivateCompleted(IActivateAudioInterfaceAsyncOperation *activateOperation) + { + (void)activateOperation; + SetEvent(m_hEvent); + return S_OK; + } + + private: + HANDLE m_hEvent; // This is created in Init(), deleted in Uninit(), waited on in Wait() and signaled in ActivateCompleted(). + }; + #else + #error "The UWP build is currently only supported in C++." + #endif +#endif // !MAL_WIN32_DESKTOP + +static mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) +{ + (void)pContext; + + mal_assert(pDevice != NULL); + mal_zero_object(&pDevice->wasapi); + + HRESULT hr; + mal_result result = MAL_SUCCESS; + const char* errorMsg = ""; + AUDCLNT_SHAREMODE shareMode = AUDCLNT_SHAREMODE_SHARED; + + WAVEFORMATEXTENSIBLE wf; + mal_zero_object(&wf); + wf.Format.cbSize = sizeof(wf); + wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wf.Format.nChannels = (WORD)pDevice->channels; + wf.Format.nSamplesPerSec = (DWORD)pDevice->sampleRate; + wf.Format.wBitsPerSample = (WORD)mal_get_sample_size_in_bytes(pDevice->format)*8; + wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8; + wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; + wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; + wf.dwChannelMask = mal_channel_map_to_channel_mask__win32(pDevice->channelMap, pDevice->channels); + if (pDevice->format == mal_format_f32) { + wf.SubFormat = MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + } else { + wf.SubFormat = MAL_GUID_KSDATAFORMAT_SUBTYPE_PCM; + } + +#ifdef MAL_WIN32_DESKTOP + IMMDevice* pMMDevice = NULL; + + IMMDeviceEnumerator* pDeviceEnumerator; + hr = mal_CoCreateInstance(pContext, g_malCLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, g_malIID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); + if (FAILED(hr)) { + errorMsg = "[WASAPI] Failed to create IMMDeviceEnumerator.", result = MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR; + goto done; + } + + if (pDeviceID == NULL) { + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator, (type == mal_device_type_playback) ? eRender : eCapture, eConsole, &pMMDevice); + if (FAILED(hr)) { + IMMDeviceEnumerator_Release(pDeviceEnumerator); + errorMsg = "[WASAPI] Failed to create default backend device.", result = MAL_WASAPI_FAILED_TO_CREATE_DEVICE; + goto done; + } + } else { + hr = IMMDeviceEnumerator_GetDevice(pDeviceEnumerator, pDeviceID->wasapi, &pMMDevice); + if (FAILED(hr)) { + IMMDeviceEnumerator_Release(pDeviceEnumerator); + errorMsg = "[WASAPI] Failed to create backend device.", result = MAL_WASAPI_FAILED_TO_CREATE_DEVICE; + goto done; + } + } + + IMMDeviceEnumerator_Release(pDeviceEnumerator); + + hr = IMMDevice_Activate(pMMDevice, g_malIID_IAudioClient, CLSCTX_ALL, NULL, &pDevice->wasapi.pAudioClient); + if (FAILED(hr)) { + errorMsg = "[WASAPI] Failed to activate device.", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; + goto done; + } +#else + IActivateAudioInterfaceAsyncOperation *pAsyncOp = NULL; + malCompletionHandler completionHandler; + + IID iid; + if (pDeviceID != NULL) { + mal_copy_memory(&iid, pDeviceID->wasapi, sizeof(iid)); + } else { + if (type == mal_device_type_playback) { + iid = g_malIID_DEVINTERFACE_AUDIO_RENDER; + } else { + iid = g_malIID_DEVINTERFACE_AUDIO_CAPTURE; + } + } + + LPOLESTR iidStr; + hr = StringFromIID(iid, &iidStr); + if (FAILED(hr)) { + errorMsg = "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.", result = MAL_OUT_OF_MEMORY; + goto done; + } + + result = completionHandler.Init(); + if (result != MAL_SUCCESS) { + mal_CoTaskMemFree(pContext, iidStr); + + errorMsg = "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; + goto done; + } + + hr = ActivateAudioInterfaceAsync(iidStr, g_malIID_IAudioClient, NULL, &completionHandler, &pAsyncOp); + if (FAILED(hr)) { + completionHandler.Uninit(); + mal_CoTaskMemFree(pContext, iidStr); + + errorMsg = "[WASAPI] ActivateAudioInterfaceAsync() failed.", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; + goto done; + } + + mal_CoTaskMemFree(pContext, iidStr); + + // Wait for the async operation for finish. + completionHandler.Wait(); + completionHandler.Uninit(); + + HRESULT activateResult; + IUnknown* pActivatedInterface; + hr = IActivateAudioInterfaceAsyncOperation_GetActivateResult(pAsyncOp, &activateResult, &pActivatedInterface); + if (FAILED(hr) || FAILED(activateResult)) { + errorMsg = "[WASAPI] Failed to activate device.", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; + goto done; + } + + // Here is where we grab the IAudioClient interface. + hr = pActivatedInterface->QueryInterface(g_malIID_IAudioClient, &pDevice->wasapi.pAudioClient); + if (FAILED(hr)) { + errorMsg = "[WASAPI] Failed to query IAudioClient interface.", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; + goto done; + } +#endif + + // Here is where we try to determine the best format to use with the device. If the client if wanting exclusive mode, first try finding the best format for that. If this fails, fall back to shared mode. + WAVEFORMATEXTENSIBLE* pBestFormatTemp = NULL; + result = MAL_FORMAT_NOT_SUPPORTED; + if (pConfig->preferExclusiveMode) { + hr = IAudioClient_IsFormatSupported(pDevice->wasapi.pAudioClient, AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wf, NULL); + #ifdef MAL_WIN32_DESKTOP + if (hr == AUDCLNT_E_UNSUPPORTED_FORMAT) { + // The format isn't supported, so retrieve the actual format from the property store and try that. + IPropertyStore* pStore = NULL; + hr = IMMDevice_OpenPropertyStore(pMMDevice, STGM_READ, &pStore); + if (SUCCEEDED(hr)) { + PROPVARIANT prop; + PropVariantInit(&prop); + hr = IPropertyStore_GetValue(pStore, g_malPKEY_AudioEngine_DeviceFormat, &prop); + if (SUCCEEDED(hr)) { + WAVEFORMATEX* pActualFormat = (WAVEFORMATEX*)prop.blob.pBlobData; + hr = IAudioClient_IsFormatSupported(pDevice->wasapi.pAudioClient, AUDCLNT_SHAREMODE_EXCLUSIVE, pActualFormat, NULL); + if (SUCCEEDED(hr)) { + mal_copy_memory(&wf, pActualFormat, sizeof(WAVEFORMATEXTENSIBLE)); + } + + mal_PropVariantClear(pDevice->pContext, &prop); + } + + IPropertyStore_Release(pStore); + } + } + #endif + + if (hr == S_OK) { + shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; + result = MAL_SUCCESS; + } + } + + // Fall back to shared mode if necessary. + if (result != MAL_SUCCESS) { + hr = IAudioClient_IsFormatSupported(pDevice->wasapi.pAudioClient, AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*)&wf, (WAVEFORMATEX**)&pBestFormatTemp); + if (hr != S_OK && hr != S_FALSE) { + hr = IAudioClient_GetMixFormat(pDevice->wasapi.pAudioClient, (WAVEFORMATEX**)&pBestFormatTemp); + if (hr != S_OK) { + result = MAL_WASAPI_FAILED_TO_FIND_BEST_FORMAT; + } else { + result = MAL_SUCCESS; + } + } else { + result = MAL_SUCCESS; + } + + shareMode = AUDCLNT_SHAREMODE_SHARED; + } + + // Return an error if we still haven't found a format. + if (result != MAL_SUCCESS) { + errorMsg = "[WASAPI] Failed to find best device mix format.", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; + goto done; + } + + if (pBestFormatTemp != NULL) { + mal_copy_memory(&wf, pBestFormatTemp, sizeof(wf)); + mal_CoTaskMemFree(pDevice->pContext, pBestFormatTemp); + } + + + REFERENCE_TIME bufferDurationInMicroseconds = ((mal_uint64)pDevice->bufferSizeInFrames * 1000 * 1000) / pConfig->sampleRate; + + if (mal_is_guid_equal(wf.SubFormat, MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { + pDevice->internalFormat = mal_format_f32; + } else { + if (wf.Format.wBitsPerSample == 32) { + pDevice->internalFormat = mal_format_s32; + } else if (wf.Format.wBitsPerSample == 24) { + pDevice->internalFormat = mal_format_s24; + } else if (wf.Format.wBitsPerSample == 16) { + pDevice->internalFormat = mal_format_s16; + } else if (wf.Format.wBitsPerSample == 8) { + pDevice->internalFormat = mal_format_u8; + } else { + errorMsg = "[WASAPI] Device's native format is not supported.", result = MAL_FORMAT_NOT_SUPPORTED; + goto done; + } + } + + pDevice->internalChannels = wf.Format.nChannels; + pDevice->internalSampleRate = wf.Format.nSamplesPerSec; + + // Get the internal channel map based on the channel mask. + mal_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDevice->internalChannels, pDevice->internalChannelMap); + + // Slightly different initialization for shared and exclusive modes. + if (shareMode == AUDCLNT_SHAREMODE_SHARED) { + // Shared. + REFERENCE_TIME bufferDuration = bufferDurationInMicroseconds*10; + hr = IAudioClient_Initialize(pDevice->wasapi.pAudioClient, shareMode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufferDuration, 0, (WAVEFORMATEX*)&wf, NULL); + if (FAILED(hr)) { + if (hr == E_ACCESSDENIED) { + errorMsg = "[WASAPI] Failed to initialize device. Access denied.", result = MAL_ACCESS_DENIED; + } else { + errorMsg = "[WASAPI] Failed to initialize device.", result = MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE; + } + + goto done; + } + } else { + // Exclusive. + REFERENCE_TIME bufferDuration = bufferDurationInMicroseconds*10; + hr = IAudioClient_Initialize(pDevice->wasapi.pAudioClient, shareMode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL); + if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) { + UINT bufferSizeInFrames; + hr = IAudioClient_GetBufferSize(pDevice->wasapi.pAudioClient, &bufferSizeInFrames); + if (SUCCEEDED(hr)) { + bufferDuration = (REFERENCE_TIME)((10000.0 * 1000 / wf.Format.nSamplesPerSec * bufferSizeInFrames) + 0.5); + + // Unfortunately we need to release and re-acquire the audio client according to MSDN. Seems silly - why not just call IAudioClient_Initialize() again?! + IAudioClient_Release(pDevice->wasapi.pAudioClient); + + #ifdef MAL_WIN32_DESKTOP + hr = IMMDevice_Activate(pMMDevice, g_malIID_IAudioClient, CLSCTX_ALL, NULL, &pDevice->wasapi.pAudioClient); + #else + hr = pActivatedInterface->QueryInterface(g_malIID_IAudioClient, &pDevice->wasapi.pAudioClient); + #endif + + if (SUCCEEDED(hr)) { + hr = IAudioClient_Initialize(pDevice->wasapi.pAudioClient, shareMode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL); + } + } + } + + if (FAILED(hr)) { + errorMsg = "[WASAPI] Failed to initialize device.", result = MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE; + goto done; + } + } + + hr = IAudioClient_GetBufferSize(pDevice->wasapi.pAudioClient, &pDevice->bufferSizeInFrames); + if (FAILED(hr)) { + errorMsg = "[WASAPI] Failed to get audio client's actual buffer size.", result = MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE; + goto done; + } + + if (type == mal_device_type_playback) { + hr = IAudioClient_GetService((IAudioClient*)pDevice->wasapi.pAudioClient, g_malIID_IAudioRenderClient, &pDevice->wasapi.pRenderClient); + } else { + hr = IAudioClient_GetService((IAudioClient*)pDevice->wasapi.pAudioClient, g_malIID_IAudioCaptureClient, &pDevice->wasapi.pCaptureClient); + } + + if (FAILED(hr)) { + errorMsg = "[WASAPI] Failed to get audio client service.", result = MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE; + goto done; + } + + + if (shareMode == AUDCLNT_SHAREMODE_SHARED) { + pDevice->exclusiveMode = MAL_FALSE; + } else /*if (shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)*/ { + pDevice->exclusiveMode = MAL_TRUE; + } + + + // We need to create and set the event for event-driven mode. This event is signalled whenever a new chunk of audio + // data needs to be written or read from the device. + pDevice->wasapi.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + if (pDevice->wasapi.hEvent == NULL) { + errorMsg = "[WASAPI] Failed to create main event for main loop.", result = MAL_FAILED_TO_CREATE_EVENT; + goto done; + } + + IAudioClient_SetEventHandle(pDevice->wasapi.pAudioClient, pDevice->wasapi.hEvent); + + + // When the device is playing the worker thread will be waiting on a bunch of notification events. To return from + // this wait state we need to signal a special event. + pDevice->wasapi.hStopEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + if (pDevice->wasapi.hStopEvent == NULL) { + errorMsg = "[WASAPI] Failed to create stop event for main loop break notification.", result = MAL_FAILED_TO_CREATE_EVENT; + goto done; + } + + result = MAL_SUCCESS; + +done: + // Clean up. +#ifdef MAL_WIN32_DESKTOP + if (pMMDevice != NULL) { + IMMDevice_Release(pMMDevice); + } +#else + if (pAsyncOp != NULL) { + IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp); + } +#endif + + if (result != MAL_SUCCESS) { + mal_device_uninit__wasapi(pDevice); + return mal_post_error(pDevice, errorMsg, result); + } else { + return MAL_SUCCESS; + } +} + +static mal_result mal_device__start_backend__wasapi(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + // Playback devices need to have an initial chunk of data loaded. + if (pDevice->type == mal_device_type_playback) { + BYTE* pData; + HRESULT hr = IAudioRenderClient_GetBuffer(pDevice->wasapi.pRenderClient, pDevice->bufferSizeInFrames, &pData); + if (FAILED(hr)) { + return mal_post_error(pDevice, "[WASAPI] Failed to retrieve buffer from internal playback device.", MAL_WASAPI_FAILED_TO_GET_INTERNAL_BUFFER); + } + + mal_device__read_frames_from_client(pDevice, pDevice->bufferSizeInFrames, pData); + + hr = IAudioRenderClient_ReleaseBuffer(pDevice->wasapi.pRenderClient, pDevice->bufferSizeInFrames, 0); + if (FAILED(hr)) { + return mal_post_error(pDevice, "[WASAPI] Failed to release internal buffer for playback device.", MAL_WASAPI_FAILED_TO_RELEASE_INTERNAL_BUFFER); + } + } + + HRESULT hr = IAudioClient_Start(pDevice->wasapi.pAudioClient); + if (FAILED(hr)) { + return mal_post_error(pDevice, "[WASAPI] Failed to start internal device.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__stop_backend__wasapi(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + HRESULT hr = IAudioClient_Stop(pDevice->wasapi.pAudioClient); + if (FAILED(hr)) { + return mal_post_error(pDevice, "[WASAPI] Failed to stop internal device.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__break_main_loop__wasapi(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + // The main loop will be waiting on a bunch of events via the WaitForMultipleObjects() API. One of those events + // is a special event we use for forcing that function to return. + pDevice->wasapi.breakFromMainLoop = MAL_TRUE; + SetEvent(pDevice->wasapi.hStopEvent); + return MAL_SUCCESS; +} + +static mal_uint32 mal_device__get_available_frames__wasapi(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + +#if 1 + if (pDevice->type == mal_device_type_playback) { + UINT32 paddingFramesCount; + HRESULT hr = IAudioClient_GetCurrentPadding(pDevice->wasapi.pAudioClient, &paddingFramesCount); + if (FAILED(hr)) { + return 0; + } + + if (pDevice->exclusiveMode) { + return paddingFramesCount; + } else { + return pDevice->bufferSizeInFrames - paddingFramesCount; + } + } else { + UINT32 framesAvailable; + HRESULT hr = IAudioCaptureClient_GetNextPacketSize(pDevice->wasapi.pCaptureClient, &framesAvailable); + if (FAILED(hr)) { + return 0; + } + + return framesAvailable; + } +#else + UINT32 paddingFramesCount; + HRESULT hr = IAudioClient_GetCurrentPadding(pDevice->wasapi.pAudioClient, &paddingFramesCount); + if (FAILED(hr)) { + return 0; + } + + if (pDevice->exclusiveMode) { + return paddingFramesCount; + } else { + return pDevice->bufferSizeInFrames - paddingFramesCount; + } +#endif +} + +static mal_uint32 mal_device__wait_for_frames__wasapi(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + while (!pDevice->wasapi.breakFromMainLoop) { + // Wait for a buffer to become available or for the stop event to be signalled. + HANDLE hEvents[2]; + hEvents[0] = (HANDLE)pDevice->wasapi.hEvent; + hEvents[1] = (HANDLE)pDevice->wasapi.hStopEvent; + if (WaitForMultipleObjects(mal_countof(hEvents), hEvents, FALSE, INFINITE) == WAIT_FAILED) { + break; + } + + // Break from the main loop if the device isn't started anymore. Likely what's happened is the application + // has requested that the device be stopped. + if (!mal_device_is_started(pDevice)) { + break; + } + + mal_uint32 framesAvailable = mal_device__get_available_frames__wasapi(pDevice); + if (framesAvailable > 0) { + return framesAvailable; + } + } + + // We'll get here if the loop was terminated. Just return whatever's available. + return mal_device__get_available_frames__wasapi(pDevice); +} + +static mal_result mal_device__main_loop__wasapi(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + // Make sure the stop event is not signaled to ensure we don't end up immediately returning from WaitForMultipleObjects(). + ResetEvent(pDevice->wasapi.hStopEvent); + + pDevice->wasapi.breakFromMainLoop = MAL_FALSE; + while (!pDevice->wasapi.breakFromMainLoop) { + mal_uint32 framesAvailable = mal_device__wait_for_frames__wasapi(pDevice); + if (framesAvailable == 0) { + continue; + } + + // If it's a playback device, don't bother grabbing more data if the device is being stopped. + if (pDevice->wasapi.breakFromMainLoop && pDevice->type == mal_device_type_playback) { + return MAL_FALSE; + } + + if (pDevice->type == mal_device_type_playback) { + BYTE* pData; + HRESULT hr = IAudioRenderClient_GetBuffer(pDevice->wasapi.pRenderClient, framesAvailable, &pData); + if (FAILED(hr)) { + return mal_post_error(pDevice, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for sending new data to the device.", MAL_WASAPI_FAILED_TO_GET_INTERNAL_BUFFER); + } + + mal_device__read_frames_from_client(pDevice, framesAvailable, pData); + + hr = IAudioRenderClient_ReleaseBuffer(pDevice->wasapi.pRenderClient, framesAvailable, 0); + if (FAILED(hr)) { + return mal_post_error(pDevice, "[WASAPI] Failed to release internal buffer from playback device in preparation for sending new data to the device.", MAL_WASAPI_FAILED_TO_RELEASE_INTERNAL_BUFFER); + } + } else { + UINT32 framesRemaining = framesAvailable; + while (framesRemaining > 0) { + BYTE* pData; + UINT32 framesToSend; + DWORD flags; + HRESULT hr = IAudioCaptureClient_GetBuffer(pDevice->wasapi.pCaptureClient, &pData, &framesToSend, &flags, NULL, NULL); + if (FAILED(hr)) { + mal_post_error(pDevice, "[WASAPI] WARNING: Failed to retrieve internal buffer from capture device in preparation for sending new data to the client.", MAL_WASAPI_FAILED_TO_GET_INTERNAL_BUFFER); + break; + } + + if (hr != AUDCLNT_S_BUFFER_EMPTY) { + mal_device__send_frames_to_client(pDevice, framesToSend, pData); + + hr = IAudioCaptureClient_ReleaseBuffer(pDevice->wasapi.pCaptureClient, framesToSend); + if (FAILED(hr)) { + mal_post_error(pDevice, "[WASAPI] WARNING: Failed to release internal buffer from capture device in preparation for sending new data to the client.", MAL_WASAPI_FAILED_TO_RELEASE_INTERNAL_BUFFER); + break; + } + + if (framesRemaining >= framesToSend) { + framesRemaining -= framesToSend; + } else { + framesRemaining = 0; + } + } + } + } + } + + return MAL_SUCCESS; +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// DirectSound Backend +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_ENABLE_DSOUND +#include + +#if 0 // MAL_GUID_NULL is not currently used, but leaving it here in case I need to add it back again. +static GUID MAL_GUID_NULL = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +#endif +static GUID MAL_GUID_IID_DirectSoundNotify = {0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}}; +static GUID MAL_GUID_IID_IDirectSoundCaptureBuffer = {0xb0210782, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}}; + +typedef HRESULT (WINAPI * mal_DirectSoundCreateProc)(const GUID* pcGuidDevice, LPDIRECTSOUND *ppDS8, LPUNKNOWN pUnkOuter); +typedef HRESULT (WINAPI * mal_DirectSoundEnumerateAProc)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); +typedef HRESULT (WINAPI * mal_DirectSoundCaptureCreateProc)(const GUID* pcGuidDevice, LPDIRECTSOUNDCAPTURE *ppDSC8, LPUNKNOWN pUnkOuter); +typedef HRESULT (WINAPI * mal_DirectSoundCaptureEnumerateAProc)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); + +static HMODULE mal_open_dsound_dll() +{ + return LoadLibraryW(L"dsound.dll"); +} + +static void mal_close_dsound_dll(HMODULE hModule) +{ + FreeLibrary(hModule); +} + + +mal_result mal_context_init__dsound(mal_context* pContext) +{ + mal_assert(pContext != NULL); + + (void)pContext; + return MAL_SUCCESS; +} + +mal_result mal_context_uninit__dsound(mal_context* pContext) +{ + mal_assert(pContext != NULL); + mal_assert(pContext->backend == mal_backend_dsound); + + (void)pContext; + return MAL_SUCCESS; +} + + +typedef struct +{ + mal_uint32 deviceCount; + mal_uint32 infoCount; + mal_device_info* pInfo; +} mal_device_enum_data__dsound; + +static BOOL CALLBACK mal_enum_devices_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) +{ + (void)lpcstrModule; + + mal_device_enum_data__dsound* pData = (mal_device_enum_data__dsound*)lpContext; + mal_assert(pData != NULL); + + if (pData->pInfo != NULL) { + if (pData->infoCount > 0) { + mal_zero_object(pData->pInfo); + mal_strncpy_s(pData->pInfo->name, sizeof(pData->pInfo->name), lpcstrDescription, (size_t)-1); + + if (lpGuid != NULL) { + mal_copy_memory(pData->pInfo->id.dsound, lpGuid, 16); + } else { + mal_zero_memory(pData->pInfo->id.dsound, 16); + } + + pData->pInfo += 1; + pData->infoCount -= 1; + pData->deviceCount += 1; + } + } else { + pData->deviceCount += 1; + } + + return TRUE; +} + +static mal_result mal_enumerate_devices__dsound(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) +{ + (void)pContext; + + mal_uint32 infoSize = *pCount; + *pCount = 0; + + mal_device_enum_data__dsound enumData; + enumData.deviceCount = 0; + enumData.infoCount = infoSize; + enumData.pInfo = pInfo; + + HMODULE dsoundDLL = mal_open_dsound_dll(); + if (dsoundDLL == NULL) { + return MAL_NO_BACKEND; + } + + if (type == mal_device_type_playback) { + mal_DirectSoundEnumerateAProc pDirectSoundEnumerateA = (mal_DirectSoundEnumerateAProc)GetProcAddress(dsoundDLL, "DirectSoundEnumerateA"); + if (pDirectSoundEnumerateA) { + pDirectSoundEnumerateA(mal_enum_devices_callback__dsound, &enumData); + } + } else { + mal_DirectSoundCaptureEnumerateAProc pDirectSoundCaptureEnumerateA = (mal_DirectSoundCaptureEnumerateAProc)GetProcAddress(dsoundDLL, "DirectSoundCaptureEnumerateA"); + if (pDirectSoundCaptureEnumerateA) { + pDirectSoundCaptureEnumerateA(mal_enum_devices_callback__dsound, &enumData); + } + } + + + mal_close_dsound_dll(dsoundDLL); + + *pCount = enumData.deviceCount; + return MAL_SUCCESS; +} + +static void mal_device_uninit__dsound(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->dsound.hDSoundDLL != NULL) { + if (pDevice->dsound.pNotify) { + IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)pDevice->dsound.pNotify); + } + + if (pDevice->dsound.hStopEvent) { + CloseHandle(pDevice->dsound.hStopEvent); + } + for (mal_uint32 i = 0; i < pDevice->periods; ++i) { + if (pDevice->dsound.pNotifyEvents[i]) { + CloseHandle(pDevice->dsound.pNotifyEvents[i]); + } + } + + if (pDevice->dsound.pCaptureBuffer) { + IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDBUFFER)pDevice->dsound.pCaptureBuffer); + } + if (pDevice->dsound.pCapture) { + IDirectSoundCapture_Release((LPDIRECTSOUNDCAPTURE)pDevice->dsound.pCapture); + } + + if (pDevice->dsound.pPlaybackBuffer) { + IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer); + } + if (pDevice->dsound.pPlaybackPrimaryBuffer) { + IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackPrimaryBuffer); + } + if (pDevice->dsound.pPlayback != NULL) { + IDirectSound_Release((LPDIRECTSOUND)pDevice->dsound.pPlayback); + } + + mal_close_dsound_dll((HMODULE)pDevice->dsound.hDSoundDLL); + } +} + +static mal_result mal_device_init__dsound(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) +{ + (void)pContext; + +#ifdef __cplusplus + GUID _MAL_GUID_IID_DirectSoundNotify = MAL_GUID_IID_DirectSoundNotify; + GUID _MAL_GUID_IID_IDirectSoundCaptureBuffer = MAL_GUID_IID_IDirectSoundCaptureBuffer; +#else + GUID* _MAL_GUID_IID_DirectSoundNotify = &MAL_GUID_IID_DirectSoundNotify; + GUID* _MAL_GUID_IID_IDirectSoundCaptureBuffer = &MAL_GUID_IID_IDirectSoundCaptureBuffer; +#endif + + mal_assert(pDevice != NULL); + mal_zero_object(&pDevice->dsound); + + pDevice->dsound.hDSoundDLL = (mal_handle)mal_open_dsound_dll(); + if (pDevice->dsound.hDSoundDLL == NULL) { + return MAL_NO_BACKEND; + } + + // Check that we have a valid format. + GUID subformat; + switch (pConfig->format) + { + case mal_format_u8: + case mal_format_s16: + case mal_format_s24: + case mal_format_s32: + { + subformat = MAL_GUID_KSDATAFORMAT_SUBTYPE_PCM; + } break; + + case mal_format_f32: + { + subformat = MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + } break; + + default: + return MAL_FORMAT_NOT_SUPPORTED; + } + + + WAVEFORMATEXTENSIBLE wf; + mal_zero_object(&wf); + wf.Format.cbSize = sizeof(wf); + wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wf.Format.nChannels = (WORD)pConfig->channels; + wf.Format.nSamplesPerSec = (DWORD)pConfig->sampleRate; + wf.Format.wBitsPerSample = (WORD)mal_get_sample_size_in_bytes(pConfig->format)*8; + wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8; + wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; + wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; + wf.dwChannelMask = mal_channel_map_to_channel_mask__win32(pConfig->channelMap, pConfig->channels); + wf.SubFormat = subformat; + + DWORD bufferSizeInBytes = 0; + + // Unfortunately DirectSound uses different APIs and data structures for playback and catpure devices :( + if (type == mal_device_type_playback) { + mal_DirectSoundCreateProc pDirectSoundCreate = (mal_DirectSoundCreateProc)GetProcAddress((HMODULE)pDevice->dsound.hDSoundDLL, "DirectSoundCreate"); + if (pDirectSoundCreate == NULL) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] Could not find DirectSoundCreate().", MAL_API_NOT_FOUND); + } + + if (FAILED(pDirectSoundCreate((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, (LPDIRECTSOUND*)&pDevice->dsound.pPlayback, NULL))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] DirectSoundCreate() failed for playback device.", MAL_DSOUND_FAILED_TO_CREATE_DEVICE); + } + + // The cooperative level must be set before doing anything else. + HWND hWnd = ((MAL_PFN_GetForegroundWindow)pContext->win32.GetForegroundWindow)(); + if (hWnd == NULL) { + hWnd = ((MAL_PFN_GetDesktopWindow)pContext->win32.GetDesktopWindow)(); + } + if (FAILED(IDirectSound_SetCooperativeLevel((LPDIRECTSOUND)pDevice->dsound.pPlayback, hWnd, (pConfig->preferExclusiveMode) ? DSSCL_EXCLUSIVE : DSSCL_PRIORITY))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device.", MAL_DSOUND_FAILED_TO_SET_COOP_LEVEL); + } + + DSBUFFERDESC descDSPrimary; + mal_zero_object(&descDSPrimary); + descDSPrimary.dwSize = sizeof(DSBUFFERDESC); + descDSPrimary.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME; + if (FAILED(IDirectSound_CreateSoundBuffer((LPDIRECTSOUND)pDevice->dsound.pPlayback, &descDSPrimary, (LPDIRECTSOUNDBUFFER*)&pDevice->dsound.pPlaybackPrimaryBuffer, NULL))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's primary buffer.", MAL_DSOUND_FAILED_TO_CREATE_BUFFER); + } + + // From MSDN: + // + // The method succeeds even if the hardware does not support the requested format; DirectSound sets the buffer to the closest + // supported format. To determine whether this has happened, an application can call the GetFormat method for the primary buffer + // and compare the result with the format that was requested with the SetFormat method. + if (FAILED(IDirectSoundBuffer_SetFormat((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)&wf))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] Failed to set format of playback device's primary buffer.", MAL_FORMAT_NOT_SUPPORTED); + } + + // Get the _actual_ properties of the buffer. This is silly API design... + DWORD requiredSize; + if (FAILED(IDirectSoundBuffer_GetFormat((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackPrimaryBuffer, NULL, 0, &requiredSize))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.", MAL_FORMAT_NOT_SUPPORTED); + } + + char rawdata[1024]; + WAVEFORMATEXTENSIBLE* pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata; + if (FAILED(IDirectSoundBuffer_GetFormat((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)pActualFormat, requiredSize, NULL))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.", MAL_FORMAT_NOT_SUPPORTED); + } + + pDevice->internalChannels = pActualFormat->Format.nChannels; + pDevice->internalSampleRate = pActualFormat->Format.nSamplesPerSec; + bufferSizeInBytes = pDevice->bufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->format); + + // Get the internal channel map based on the channel mask. + mal_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDevice->internalChannels, pDevice->internalChannelMap); + + + // Meaning of dwFlags (from MSDN): + // + // DSBCAPS_CTRLPOSITIONNOTIFY + // The buffer has position notification capability. + // + // DSBCAPS_GLOBALFOCUS + // With this flag set, an application using DirectSound can continue to play its buffers if the user switches focus to + // another application, even if the new application uses DirectSound. + // + // DSBCAPS_GETCURRENTPOSITION2 + // In the first version of DirectSound, the play cursor was significantly ahead of the actual playing sound on emulated + // sound cards; it was directly behind the write cursor. Now, if the DSBCAPS_GETCURRENTPOSITION2 flag is specified, the + // application can get a more accurate play cursor. + DSBUFFERDESC descDS; + mal_zero_object(&descDS); + descDS.dwSize = sizeof(DSBUFFERDESC); + descDS.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; + descDS.dwBufferBytes = bufferSizeInBytes; + descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; + if (FAILED(IDirectSound_CreateSoundBuffer((LPDIRECTSOUND)pDevice->dsound.pPlayback, &descDS, (LPDIRECTSOUNDBUFFER*)&pDevice->dsound.pPlaybackBuffer, NULL))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer.", MAL_DSOUND_FAILED_TO_CREATE_BUFFER); + } + + // Notifications are set up via a DIRECTSOUNDNOTIFY object which is retrieved from the buffer. + if (FAILED(IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, _MAL_GUID_IID_DirectSoundNotify, (void**)&pDevice->dsound.pNotify))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] IDirectSoundBuffer_QueryInterface() failed for playback device's IDirectSoundNotify object.", MAL_DSOUND_FAILED_TO_QUERY_INTERFACE); + } + } else { + // The default buffer size is treated slightly differently for DirectSound which, for some reason, seems to + // have worse latency with capture than playback (sometimes _much_ worse). + if (pDevice->usingDefaultBufferSize) { + pDevice->bufferSizeInFrames *= 2; // <-- Might need to fiddle with this to find a more ideal value. May even be able to just add a fixed amount rather than scaling. + } + + mal_DirectSoundCaptureCreateProc pDirectSoundCaptureCreate = (mal_DirectSoundCaptureCreateProc)GetProcAddress((HMODULE)pDevice->dsound.hDSoundDLL, "DirectSoundCaptureCreate"); + if (pDirectSoundCaptureCreate == NULL) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] Could not find DirectSoundCreate().", MAL_API_NOT_FOUND); + } + + if (FAILED(pDirectSoundCaptureCreate((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, (LPDIRECTSOUNDCAPTURE*)&pDevice->dsound.pCapture, NULL))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] DirectSoundCaptureCreate() failed for capture device.", MAL_DSOUND_FAILED_TO_CREATE_DEVICE); + } + + bufferSizeInBytes = pDevice->bufferSizeInFrames * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); + + DSCBUFFERDESC descDS; + mal_zero_object(&descDS); + descDS.dwSize = sizeof(descDS); + descDS.dwFlags = 0; + descDS.dwBufferBytes = bufferSizeInBytes; + descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; + LPDIRECTSOUNDCAPTUREBUFFER pDSCB_Temp; + if (FAILED(IDirectSoundCapture_CreateCaptureBuffer((LPDIRECTSOUNDCAPTURE)pDevice->dsound.pCapture, &descDS, &pDSCB_Temp, NULL))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", MAL_DSOUND_FAILED_TO_CREATE_BUFFER); + } + + HRESULT hr = IDirectSoundCapture_QueryInterface(pDSCB_Temp, _MAL_GUID_IID_IDirectSoundCaptureBuffer, (LPVOID*)&pDevice->dsound.pCaptureBuffer); + IDirectSoundCaptureBuffer_Release(pDSCB_Temp); + if (FAILED(hr)) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] IDirectSoundCapture_QueryInterface() failed for capture device's IDirectSoundCaptureBuffer8 object.", MAL_DSOUND_FAILED_TO_QUERY_INTERFACE); + } + + // Notifications are set up via a DIRECTSOUNDNOTIFY object which is retrieved from the buffer. + if (FAILED(IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer, _MAL_GUID_IID_DirectSoundNotify, (void**)&pDevice->dsound.pNotify))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] IDirectSoundCaptureBuffer_QueryInterface() failed for capture device's IDirectSoundNotify object.", MAL_DSOUND_FAILED_TO_QUERY_INTERFACE); + } + } + + // We need a notification for each period. The notification offset is slightly different depending on whether or not the + // device is a playback or capture device. For a playback device we want to be notified when a period just starts playing, + // whereas for a capture device we want to be notified when a period has just _finished_ capturing. + mal_uint32 periodSizeInBytes = pDevice->bufferSizeInFrames / pDevice->periods; + DSBPOSITIONNOTIFY notifyPoints[MAL_MAX_PERIODS_DSOUND]; // One notification event for each period. + for (mal_uint32 i = 0; i < pDevice->periods; ++i) { + pDevice->dsound.pNotifyEvents[i] = CreateEventA(NULL, FALSE, FALSE, NULL); + if (pDevice->dsound.pNotifyEvents[i] == NULL) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] Failed to create event for buffer notifications.", MAL_FAILED_TO_CREATE_EVENT); + } + + // The notification offset is in bytes. + notifyPoints[i].dwOffset = i * periodSizeInBytes; + notifyPoints[i].hEventNotify = pDevice->dsound.pNotifyEvents[i]; + } + + if (FAILED(IDirectSoundNotify_SetNotificationPositions((LPDIRECTSOUNDNOTIFY)pDevice->dsound.pNotify, pDevice->periods, notifyPoints))) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] IDirectSoundNotify_SetNotificationPositions() failed.", MAL_DSOUND_FAILED_TO_SET_NOTIFICATIONS); + } + + // When the device is playing the worker thread will be waiting on a bunch of notification events. To return from + // this wait state we need to signal a special event. + pDevice->dsound.hStopEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + if (pDevice->dsound.hStopEvent == NULL) { + mal_device_uninit__dsound(pDevice); + return mal_post_error(pDevice, "[DirectSound] Failed to create event for main loop break notification.", MAL_FAILED_TO_CREATE_EVENT); + } + + return MAL_SUCCESS; +} + + +static mal_result mal_device__start_backend__dsound(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->type == mal_device_type_playback) { + // Before playing anything we need to grab an initial group of samples from the client. + mal_uint32 framesToRead = pDevice->bufferSizeInFrames / pDevice->periods; + mal_uint32 desiredLockSize = framesToRead * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); + + void* pLockPtr; + DWORD actualLockSize; + void* pLockPtr2; + DWORD actualLockSize2; + if (SUCCEEDED(IDirectSoundBuffer_Lock((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, 0, desiredLockSize, &pLockPtr, &actualLockSize, &pLockPtr2, &actualLockSize2, 0))) { + framesToRead = actualLockSize / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; + mal_device__read_frames_from_client(pDevice, framesToRead, pLockPtr); + IDirectSoundBuffer_Unlock((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, pLockPtr, actualLockSize, pLockPtr2, actualLockSize2); + + pDevice->dsound.lastProcessedFrame = framesToRead; + if (FAILED(IDirectSoundBuffer_Play((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, 0, 0, DSBPLAY_LOOPING))) { + return mal_post_error(pDevice, "[DirectSound] IDirectSoundBuffer_Play() failed.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + } else { + return mal_post_error(pDevice, "[DirectSound] IDirectSoundBuffer_Lock() failed.", MAL_FAILED_TO_MAP_DEVICE_BUFFER); + } + } else { + if (FAILED(IDirectSoundCaptureBuffer_Start((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer, DSCBSTART_LOOPING))) { + return mal_post_error(pDevice, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__stop_backend__dsound(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->type == mal_device_type_playback) { + if (FAILED(IDirectSoundBuffer_Stop((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer))) { + return mal_post_error(pDevice, "[DirectSound] IDirectSoundBuffer_Stop() failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); + } + + IDirectSoundBuffer_SetCurrentPosition((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, 0); + } else { + if (FAILED(IDirectSoundCaptureBuffer_Stop((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer))) { + return mal_post_error(pDevice, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); + } + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__break_main_loop__dsound(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + // The main loop will be waiting on a bunch of events via the WaitForMultipleObjects() API. One of those events + // is a special event we use for forcing that function to return. + pDevice->dsound.breakFromMainLoop = MAL_TRUE; + SetEvent(pDevice->dsound.hStopEvent); + return MAL_SUCCESS; +} + +static mal_bool32 mal_device__get_current_frame__dsound(mal_device* pDevice, mal_uint32* pCurrentPos) +{ + mal_assert(pDevice != NULL); + mal_assert(pCurrentPos != NULL); + *pCurrentPos = 0; + + DWORD dwCurrentPosition; + if (pDevice->type == mal_device_type_playback) { + if (FAILED(IDirectSoundBuffer_GetCurrentPosition((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, NULL, &dwCurrentPosition))) { + return MAL_FALSE; + } + } else { + if (FAILED(IDirectSoundCaptureBuffer_GetCurrentPosition((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer, &dwCurrentPosition, NULL))) { + return MAL_FALSE; + } + } + + *pCurrentPos = (mal_uint32)dwCurrentPosition / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; + return MAL_TRUE; +} + +static mal_uint32 mal_device__get_available_frames__dsound(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + mal_uint32 currentFrame; + if (!mal_device__get_current_frame__dsound(pDevice, ¤tFrame)) { + return 0; + } + + // In a playback device the last processed frame should always be ahead of the current frame. The space between + // the last processed and current frame (moving forward, starting from the last processed frame) is the amount + // of space available to write. + // + // For a recording device it's the other way around - the last processed frame is always _behind_ the current + // frame and the space between is the available space. + mal_uint32 totalFrameCount = pDevice->bufferSizeInFrames; + if (pDevice->type == mal_device_type_playback) { + mal_uint32 committedBeg = currentFrame; + mal_uint32 committedEnd; + committedEnd = pDevice->dsound.lastProcessedFrame; + if (committedEnd <= committedBeg) { + committedEnd += totalFrameCount; + } + + mal_uint32 committedSize = (committedEnd - committedBeg); + mal_assert(committedSize <= totalFrameCount); + + return totalFrameCount - committedSize; + } else { + mal_uint32 validBeg = pDevice->dsound.lastProcessedFrame; + mal_uint32 validEnd = currentFrame; + if (validEnd < validBeg) { + validEnd += totalFrameCount; // Wrap around. + } + + mal_uint32 validSize = (validEnd - validBeg); + mal_assert(validSize <= totalFrameCount); + + return validSize; + } +} + +static mal_uint32 mal_device__wait_for_frames__dsound(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + // The timeout to use for putting the thread to sleep is based on the size of the buffer and the period count. + DWORD timeoutInMilliseconds = (pDevice->bufferSizeInFrames / (pDevice->sampleRate/1000)) / pDevice->periods; + if (timeoutInMilliseconds < 1) { + timeoutInMilliseconds = 1; + } + + unsigned int eventCount = pDevice->periods + 1; + HANDLE pEvents[MAL_MAX_PERIODS_DSOUND + 1]; // +1 for the stop event. + mal_copy_memory(pEvents, pDevice->dsound.pNotifyEvents, sizeof(HANDLE) * pDevice->periods); + pEvents[eventCount-1] = pDevice->dsound.hStopEvent; + + while (!pDevice->dsound.breakFromMainLoop) { + mal_uint32 framesAvailable = mal_device__get_available_frames__dsound(pDevice); + if (framesAvailable > 0) { + return framesAvailable; + } + + // If we get here it means we weren't able to find any frames. We'll just wait here for a bit. + WaitForMultipleObjects(eventCount, pEvents, FALSE, timeoutInMilliseconds); + } + + // We'll get here if the loop was terminated. Just return whatever's available. + return mal_device__get_available_frames__dsound(pDevice); +} + +static mal_result mal_device__main_loop__dsound(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + // Make sure the stop event is not signaled to ensure we don't end up immediately returning from WaitForMultipleObjects(). + ResetEvent(pDevice->dsound.hStopEvent); + + pDevice->dsound.breakFromMainLoop = MAL_FALSE; + while (!pDevice->dsound.breakFromMainLoop) { + mal_uint32 framesAvailable = mal_device__wait_for_frames__dsound(pDevice); + if (framesAvailable == 0) { + continue; + } + + // If it's a playback device, don't bother grabbing more data if the device is being stopped. + if (pDevice->dsound.breakFromMainLoop && pDevice->type == mal_device_type_playback) { + return MAL_FALSE; + } + + DWORD lockOffset = pDevice->dsound.lastProcessedFrame * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); + DWORD lockSize = framesAvailable * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); + + if (pDevice->type == mal_device_type_playback) { + void* pLockPtr; + DWORD actualLockSize; + void* pLockPtr2; + DWORD actualLockSize2; + if (FAILED(IDirectSoundBuffer_Lock((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, lockOffset, lockSize, &pLockPtr, &actualLockSize, &pLockPtr2, &actualLockSize2, 0))) { + return mal_post_error(pDevice, "[DirectSound] IDirectSoundBuffer_Lock() failed.", MAL_FAILED_TO_MAP_DEVICE_BUFFER); + } + + mal_uint32 frameCount = actualLockSize / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; + mal_device__read_frames_from_client(pDevice, frameCount, pLockPtr); + pDevice->dsound.lastProcessedFrame = (pDevice->dsound.lastProcessedFrame + frameCount) % pDevice->bufferSizeInFrames; + + IDirectSoundBuffer_Unlock((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, pLockPtr, actualLockSize, pLockPtr2, actualLockSize2); + } else { + void* pLockPtr; + DWORD actualLockSize; + void* pLockPtr2; + DWORD actualLockSize2; + if (FAILED(IDirectSoundCaptureBuffer_Lock((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer, lockOffset, lockSize, &pLockPtr, &actualLockSize, &pLockPtr2, &actualLockSize2, 0))) { + return mal_post_error(pDevice, "[DirectSound] IDirectSoundCaptureBuffer_Lock() failed.", MAL_FAILED_TO_MAP_DEVICE_BUFFER); + } + + mal_uint32 frameCount = actualLockSize / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; + mal_device__send_frames_to_client(pDevice, frameCount, pLockPtr); + pDevice->dsound.lastProcessedFrame = (pDevice->dsound.lastProcessedFrame + frameCount) % pDevice->bufferSizeInFrames; + + IDirectSoundCaptureBuffer_Unlock((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer, pLockPtr, actualLockSize, pLockPtr2, actualLockSize2); + } + } + + return MAL_SUCCESS; +} +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// +// WinMM Backend +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_ENABLE_WINMM +#include + +#if !defined(MAXULONG_PTR) +typedef size_t DWORD_PTR; +#endif + +#if !defined(WAVE_FORMAT_44M08) +#define WAVE_FORMAT_44M08 0x00000100 +#define WAVE_FORMAT_44S08 0x00000200 +#define WAVE_FORMAT_44M16 0x00000400 +#define WAVE_FORMAT_44S16 0x00000800 +#define WAVE_FORMAT_48M08 0x00001000 +#define WAVE_FORMAT_48S08 0x00002000 +#define WAVE_FORMAT_48M16 0x00004000 +#define WAVE_FORMAT_48S16 0x00008000 +#define WAVE_FORMAT_96M08 0x00010000 +#define WAVE_FORMAT_96S08 0x00020000 +#define WAVE_FORMAT_96M16 0x00040000 +#define WAVE_FORMAT_96S16 0x00080000 +#endif + +typedef UINT (WINAPI * MAL_PFN_waveOutGetNumDevs)(void); +typedef MMRESULT (WINAPI * MAL_PFN_waveOutGetDevCapsA)(UINT_PTR uDeviceID, LPWAVEOUTCAPSA pwoc, UINT cbwoc); +typedef MMRESULT (WINAPI * MAL_PFN_waveOutOpen)(LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen); +typedef MMRESULT (WINAPI * MAL_PFN_waveOutClose)(HWAVEOUT hwo); +typedef MMRESULT (WINAPI * MAL_PFN_waveOutPrepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MAL_PFN_waveOutUnprepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MAL_PFN_waveOutWrite)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MAL_PFN_waveOutReset)(HWAVEOUT hwo); +typedef UINT (WINAPI * MAL_PFN_waveInGetNumDevs)(void); +typedef MMRESULT (WINAPI * MAL_PFN_waveInGetDevCapsA)(UINT_PTR uDeviceID, LPWAVEINCAPSA pwic, UINT cbwic); +typedef MMRESULT (WINAPI * MAL_PFN_waveInOpen)(LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen); +typedef MMRESULT (WINAPI * MAL_PFN_waveInClose)(HWAVEIN hwi); +typedef MMRESULT (WINAPI * MAL_PFN_waveInPrepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MAL_PFN_waveInUnprepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MAL_PFN_waveInAddBuffer)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); +typedef MMRESULT (WINAPI * MAL_PFN_waveInStart)(HWAVEIN hwi); +typedef MMRESULT (WINAPI * MAL_PFN_waveInReset)(HWAVEIN hwi); + +mal_result mal_result_from_MMRESULT(MMRESULT resultMM) +{ + switch (resultMM) { + case MMSYSERR_NOERROR: return MAL_SUCCESS; + case MMSYSERR_BADDEVICEID: return MAL_INVALID_ARGS; + case MMSYSERR_INVALHANDLE: return MAL_INVALID_ARGS; + case MMSYSERR_NOMEM: return MAL_OUT_OF_MEMORY; + case MMSYSERR_INVALFLAG: return MAL_INVALID_ARGS; + case MMSYSERR_INVALPARAM: return MAL_INVALID_ARGS; + case MMSYSERR_HANDLEBUSY: return MAL_DEVICE_BUSY; + case MMSYSERR_ERROR: return MAL_ERROR; + default: return MAL_ERROR; + } +} + +mal_result mal_context_init__winmm(mal_context* pContext) +{ + mal_assert(pContext != NULL); + + pContext->winmm.hWinMM = mal_dlopen("winmm.dll"); + if (pContext->winmm.hWinMM == NULL) { + return MAL_NO_BACKEND; + } + + pContext->winmm.waveOutGetNumDevs = mal_dlsym(pContext->winmm.hWinMM, "waveOutGetNumDevs"); + pContext->winmm.waveOutGetDevCapsA = mal_dlsym(pContext->winmm.hWinMM, "waveOutGetDevCapsA"); + pContext->winmm.waveOutOpen = mal_dlsym(pContext->winmm.hWinMM, "waveOutOpen"); + pContext->winmm.waveOutClose = mal_dlsym(pContext->winmm.hWinMM, "waveOutClose"); + pContext->winmm.waveOutPrepareHeader = mal_dlsym(pContext->winmm.hWinMM, "waveOutPrepareHeader"); + pContext->winmm.waveOutUnprepareHeader = mal_dlsym(pContext->winmm.hWinMM, "waveOutUnprepareHeader"); + pContext->winmm.waveOutWrite = mal_dlsym(pContext->winmm.hWinMM, "waveOutWrite"); + pContext->winmm.waveOutReset = mal_dlsym(pContext->winmm.hWinMM, "waveOutReset"); + pContext->winmm.waveInGetNumDevs = mal_dlsym(pContext->winmm.hWinMM, "waveInGetNumDevs"); + pContext->winmm.waveInGetDevCapsA = mal_dlsym(pContext->winmm.hWinMM, "waveInGetDevCapsA"); + pContext->winmm.waveInOpen = mal_dlsym(pContext->winmm.hWinMM, "waveInOpen"); + pContext->winmm.waveInClose = mal_dlsym(pContext->winmm.hWinMM, "waveInClose"); + pContext->winmm.waveInPrepareHeader = mal_dlsym(pContext->winmm.hWinMM, "waveInPrepareHeader"); + pContext->winmm.waveInUnprepareHeader = mal_dlsym(pContext->winmm.hWinMM, "waveInUnprepareHeader"); + pContext->winmm.waveInAddBuffer = mal_dlsym(pContext->winmm.hWinMM, "waveInAddBuffer"); + pContext->winmm.waveInStart = mal_dlsym(pContext->winmm.hWinMM, "waveInStart"); + pContext->winmm.waveInReset = mal_dlsym(pContext->winmm.hWinMM, "waveInReset"); + + return MAL_SUCCESS; +} + +mal_result mal_context_uninit__winmm(mal_context* pContext) +{ + mal_assert(pContext != NULL); + mal_assert(pContext->backend == mal_backend_winmm); + + mal_dlclose(pContext->winmm.hWinMM); + return MAL_SUCCESS; +} + +static mal_result mal_enumerate_devices__winmm(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) +{ + (void)pContext; + + mal_uint32 infoSize = *pCount; + *pCount = 0; + + if (type == mal_device_type_playback) { + UINT deviceCount = ((MAL_PFN_waveOutGetNumDevs)pContext->winmm.waveOutGetNumDevs)(); + for (UINT iDevice = 0; iDevice < deviceCount; ++iDevice) { + if (pInfo != NULL) { + if (infoSize > 0) { + WAVEOUTCAPSA caps; + MMRESULT result = ((MAL_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(iDevice, &caps, sizeof(caps)); + if (result == MMSYSERR_NOERROR) { + pInfo->id.winmm = iDevice; + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), caps.szPname, (size_t)-1); + } + + pInfo += 1; + infoSize -= 1; + *pCount += 1; + } + } else { + *pCount += 1; + } + } + } else { + UINT deviceCount = ((MAL_PFN_waveInGetNumDevs)pContext->winmm.waveInGetNumDevs)(); + for (UINT iDevice = 0; iDevice < deviceCount; ++iDevice) { + if (pInfo != NULL) { + if (infoSize > 0) { + WAVEINCAPSA caps; + MMRESULT result = ((MAL_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(iDevice, &caps, sizeof(caps)); + if (result == MMSYSERR_NOERROR) { + pInfo->id.winmm = iDevice; + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), caps.szPname, (size_t)-1); + } + + pInfo += 1; + infoSize -= 1; + *pCount += 1; + } + } else { + *pCount += 1; + } + } + } + + return MAL_SUCCESS; +} + +static void mal_device_uninit__winmm(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->type == mal_device_type_playback) { + ((MAL_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevice); + } else { + ((MAL_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDevice); + } + + mal_free(pDevice->winmm._pHeapData); + CloseHandle((HANDLE)pDevice->winmm.hEvent); +} + +static mal_result mal_device_init__winmm(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) +{ + (void)pContext; + + mal_uint32 heapSize; + mal_uint32 iBit; + + WORD closestBitsPerSample = 0; + WORD closestChannels = 0; + DWORD closestSampleRate = 0; + + mal_assert(pDevice != NULL); + mal_zero_object(&pDevice->winmm); + + UINT winMMDeviceID = 0; + if (pDeviceID != NULL) { + winMMDeviceID = (UINT)pDeviceID->winmm; + } + + const char* errorMsg = ""; + mal_result errorCode = MAL_ERROR; + + + // WinMM doesn't seem to have a good way to query the format of the device. Therefore, we'll restrict the formats to the + // standard formats documented here https://msdn.microsoft.com/en-us/library/windows/desktop/dd743855(v=vs.85).aspx. If + // that link goes stale, just look up the documentation for WAVEOUTCAPS or WAVEINCAPS. + WAVEFORMATEX wf; + mal_zero_object(&wf); + wf.cbSize = sizeof(wf); + wf.wFormatTag = WAVE_FORMAT_PCM; + wf.nChannels = (WORD)pConfig->channels; + wf.nSamplesPerSec = (DWORD)pConfig->sampleRate; + wf.wBitsPerSample = (WORD)mal_get_sample_size_in_bytes(pConfig->format)*8; + + if (wf.nChannels > 2) { + wf.nChannels = 2; + } + + if (wf.wBitsPerSample != 8 && wf.wBitsPerSample != 16) { + if (wf.wBitsPerSample <= 8) { + wf.wBitsPerSample = 8; + } else { + wf.wBitsPerSample = 16; + } + } + + if (wf.nSamplesPerSec <= 11025) { + wf.nSamplesPerSec = 11025; + } else if (wf.nSamplesPerSec <= 22050) { + wf.nSamplesPerSec = 22050; + } else if (wf.nSamplesPerSec <= 44100) { + wf.nSamplesPerSec = 44100; + } else if (wf.nSamplesPerSec <= 48000) { + wf.nSamplesPerSec = 48000; + } else { + wf.nSamplesPerSec = 96000; + } + + + // Change the format based on the closest match of the supported standard formats. + DWORD dwFormats = 0; + if (type == mal_device_type_playback) { + WAVEOUTCAPSA caps; + if (((MAL_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceID, &caps, sizeof(caps)) == MMSYSERR_NOERROR) { + dwFormats = caps.dwFormats; + } else { + errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MAL_WINMM_FAILED_TO_GET_DEVICE_CAPS; + goto on_error; + } + } else { + WAVEINCAPSA caps; + if (((MAL_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceID, &caps, sizeof(caps)) == MMSYSERR_NOERROR) { + dwFormats = caps.dwFormats; + } else { + errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MAL_WINMM_FAILED_TO_GET_DEVICE_CAPS; + goto on_error; + } + } + + if (dwFormats == 0) { + errorMsg = "[WinMM] Failed to retrieve the supported formats for the internal device.", errorCode = MAL_WINMM_FAILED_TO_GET_SUPPORTED_FORMATS; + goto on_error; + } + + for (iBit = 0; iBit < 32; ++iBit) { + WORD formatBitsPerSample = 0; + WORD formatChannels = 0; + DWORD formatSampleRate = 0; + + DWORD format = (dwFormats & (1 << iBit)); + if (format != 0) { + switch (format) + { + case WAVE_FORMAT_1M08: + { + formatBitsPerSample = 8; + formatChannels = 1; + formatSampleRate = 110025; + } break; + case WAVE_FORMAT_1M16: + { + formatBitsPerSample = 16; + formatChannels = 1; + formatSampleRate = 110025; + } break; + case WAVE_FORMAT_1S08: + { + formatBitsPerSample = 8; + formatChannels = 2; + formatSampleRate = 110025; + } break; + case WAVE_FORMAT_1S16: + { + formatBitsPerSample = 16; + formatChannels = 2; + formatSampleRate = 110025; + } break; + case WAVE_FORMAT_2M08: + { + formatBitsPerSample = 8; + formatChannels = 1; + formatSampleRate = 22050; + } break; + case WAVE_FORMAT_2M16: + { + formatBitsPerSample = 16; + formatChannels = 1; + formatSampleRate = 22050; + } break; + case WAVE_FORMAT_2S08: + { + formatBitsPerSample = 8; + formatChannels = 2; + formatSampleRate = 22050; + } break; + case WAVE_FORMAT_2S16: + { + formatBitsPerSample = 16; + formatChannels = 2; + formatSampleRate = 22050; + } break; + case WAVE_FORMAT_44M08: + { + formatBitsPerSample = 8; + formatChannels = 1; + formatSampleRate = 44100; + } break; + case WAVE_FORMAT_44M16: + { + formatBitsPerSample = 16; + formatChannels = 1; + formatSampleRate = 44100; + } break; + case WAVE_FORMAT_44S08: + { + formatBitsPerSample = 8; + formatChannels = 2; + formatSampleRate = 44100; + } break; + case WAVE_FORMAT_44S16: + { + formatBitsPerSample = 16; + formatChannels = 2; + formatSampleRate = 44100; + } break; + case WAVE_FORMAT_48M08: + { + formatBitsPerSample = 8; + formatChannels = 1; + formatSampleRate = 48000; + } break; + case WAVE_FORMAT_48M16: + { + formatBitsPerSample = 16; + formatChannels = 1; + formatSampleRate = 48000; + } break; + case WAVE_FORMAT_48S08: + { + formatBitsPerSample = 8; + formatChannels = 2; + formatSampleRate = 48000; + } break; + case WAVE_FORMAT_48S16: + { + formatBitsPerSample = 16; + formatChannels = 2; + formatSampleRate = 48000; + } break; + case WAVE_FORMAT_96M08: + { + formatBitsPerSample = 8; + formatChannels = 1; + formatSampleRate = 96000; + } break; + case WAVE_FORMAT_96M16: + { + formatBitsPerSample = 16; + formatChannels = 1; + formatSampleRate = 96000; + } break; + case WAVE_FORMAT_96S08: + { + formatBitsPerSample = 8; + formatChannels = 2; + formatSampleRate = 96000; + } break; + case WAVE_FORMAT_96S16: + { + formatBitsPerSample = 16; + formatChannels = 2; + formatSampleRate = 96000; + } break; + default: + { + errorMsg = "[WinMM] The internal device does not support any of the standard formats.", errorCode = MAL_ERROR; // <-- Should never hit this. + goto on_error; + } break; + } + + if (formatBitsPerSample == wf.wBitsPerSample && formatChannels == wf.nChannels && formatSampleRate == wf.nSamplesPerSec) { + break; // It's an exact match. + } else { + // It's not an exact match. Compare it with the closest match. + if (closestBitsPerSample == 0) { + // This is the first format, so nothing to compare against. + closestBitsPerSample = formatBitsPerSample; + closestChannels = formatChannels; + closestSampleRate = formatSampleRate; + } else { + // Prefer the channel count be the same over the others. + if (formatChannels != closestChannels) { + // Channels aren't equal. Favour the one equal to our desired channel count. + if (formatChannels == wf.nChannels) { + closestBitsPerSample = formatBitsPerSample; + closestChannels = formatChannels; + closestSampleRate = formatSampleRate; + } + } else { + // The channels are equal. Look at the format now. + if (formatBitsPerSample != closestBitsPerSample) { + if (formatBitsPerSample == wf.wBitsPerSample) { + closestBitsPerSample = formatBitsPerSample; + closestChannels = formatChannels; + closestSampleRate = formatSampleRate; + } + } else { + // Both the channels and formats are the same, so now just favour whichever's sample rate is closest to the requested rate. + mal_uint32 closestRateDiff = (closestSampleRate > wf.nSamplesPerSec) ? (closestSampleRate - wf.nSamplesPerSec) : (wf.nSamplesPerSec - closestSampleRate); + mal_uint32 formatRateDiff = (formatSampleRate > wf.nSamplesPerSec) ? (formatSampleRate - wf.nSamplesPerSec) : (wf.nSamplesPerSec - formatSampleRate); + if (formatRateDiff < closestRateDiff) { + closestBitsPerSample = formatBitsPerSample; + closestChannels = formatChannels; + closestSampleRate = formatSampleRate; + } + } + } + } + } + } + } + + wf.wBitsPerSample = closestBitsPerSample; + wf.nChannels = closestChannels; + wf.nSamplesPerSec = closestSampleRate; + wf.nBlockAlign = (wf.nChannels * wf.wBitsPerSample) / 8; + wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; + + + // We use an event to know when a new fragment needs to be enqueued. + pDevice->winmm.hEvent = (mal_handle)CreateEvent(NULL, TRUE, TRUE, NULL); + if (pDevice->winmm.hEvent == NULL) { + errorMsg = "[WinMM] Failed to create event for fragment enqueing.", errorCode = MAL_FAILED_TO_CREATE_EVENT; + goto on_error; + } + + + if (type == mal_device_type_playback) { + MMRESULT result = ((MAL_PFN_waveOutOpen)pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevice, winMMDeviceID, &wf, (DWORD_PTR)pDevice->winmm.hEvent, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC); + if (result != MMSYSERR_NOERROR) { + errorMsg = "[WinMM] Failed to open playback device.", errorCode = MAL_FAILED_TO_OPEN_BACKEND_DEVICE; + goto on_error; + } + } else { + MMRESULT result = ((MAL_PFN_waveInOpen)pDevice->pContext->winmm.waveInOpen)((LPHWAVEIN)&pDevice->winmm.hDevice, winMMDeviceID, &wf, (DWORD_PTR)pDevice->winmm.hEvent, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC); + if (result != MMSYSERR_NOERROR) { + errorMsg = "[WinMM] Failed to open capture device.", errorCode = MAL_FAILED_TO_OPEN_BACKEND_DEVICE; + goto on_error; + } + } + + + // The internal formats need to be set based on the wf object. + if (wf.wFormatTag == WAVE_FORMAT_PCM) { + switch (wf.wBitsPerSample) { + case 8: pDevice->internalFormat = mal_format_u8; break; + case 16: pDevice->internalFormat = mal_format_s16; break; + case 24: pDevice->internalFormat = mal_format_s24; break; + case 32: pDevice->internalFormat = mal_format_s32; break; + default: mal_post_error(pDevice, "[WinMM] The device's internal format is not supported by mini_al.", MAL_FORMAT_NOT_SUPPORTED); + } + } else { + errorMsg = "[WinMM] The device's internal format is not supported by mini_al.", errorCode = MAL_FORMAT_NOT_SUPPORTED; + goto on_error; + } + + pDevice->internalChannels = wf.nChannels; + pDevice->internalSampleRate = wf.nSamplesPerSec; + + + // Just use the default channel mapping. WinMM only supports mono or stereo anyway so it'll reliably be left/right order for stereo. + mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); + + + // Latency with WinMM seems pretty bad from my testing... Need to increase the default buffer size. + if (pDevice->usingDefaultBufferSize) { + if (pDevice->type == mal_device_type_playback) { + pDevice->bufferSizeInFrames *= 4; // <-- Might need to fiddle with this to find a more ideal value. May even be able to just add a fixed amount rather than scaling. + } else { + pDevice->bufferSizeInFrames *= 2; + } + } + + // The size of the intermediary buffer needs to be able to fit every fragment. + pDevice->winmm.fragmentSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods; + pDevice->winmm.fragmentSizeInBytes = pDevice->winmm.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); + + heapSize = (sizeof(WAVEHDR) * pDevice->periods) + (pDevice->winmm.fragmentSizeInBytes * pDevice->periods); + pDevice->winmm._pHeapData = (mal_uint8*)mal_malloc(heapSize); + if (pDevice->winmm._pHeapData == NULL) { + errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MAL_OUT_OF_MEMORY; + goto on_error; + } + + mal_zero_memory(pDevice->winmm._pHeapData, pDevice->winmm.fragmentSizeInBytes * pDevice->periods); + + pDevice->winmm.pWAVEHDR = pDevice->winmm._pHeapData; + pDevice->winmm.pIntermediaryBuffer = pDevice->winmm._pHeapData + (sizeof(WAVEHDR) * pDevice->periods); + + + return MAL_SUCCESS; + +on_error: + if (pDevice->type == mal_device_type_playback) { + ((MAL_PFN_waveOutClose)pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevice); + } else { + ((MAL_PFN_waveInClose)pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDevice); + } + + mal_free(pDevice->winmm._pHeapData); + return mal_post_error(pDevice, errorMsg, errorCode); +} + + +static mal_result mal_device__start_backend__winmm(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->type == mal_device_type_playback) { + // Playback. The device is started when we call waveOutWrite() with a block of data. From MSDN: + // + // Unless the device is paused by calling the waveOutPause function, playback begins when the first data block is sent to the device. + // + // When starting the device we commit every fragment. We signal the event before calling waveOutWrite(). + mal_uint32 i; + for (i = 0; i < pDevice->periods; ++i) { + mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]); + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBuffer + (pDevice->winmm.fragmentSizeInBytes * i)); + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBufferLength = pDevice->winmm.fragmentSizeInBytes; + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwFlags = 0L; + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwLoops = 0L; + mal_device__read_frames_from_client(pDevice, pDevice->winmm.fragmentSizeInFrames, ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData); + + if (((MAL_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR) { + return mal_post_error(pDevice, "[WinMM] Failed to start backend device. Failed to prepare header.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + } + + ResetEvent(pDevice->winmm.hEvent); + + for (i = 0; i < pDevice->periods; ++i) { + if (((MAL_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR) { + return mal_post_error(pDevice, "[WinMM] Failed to start backend device. Failed to send data to the backend device.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + } + } else { + // Capture. + for (mal_uint32 i = 0; i < pDevice->periods; ++i) { + mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]); + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBuffer + (pDevice->winmm.fragmentSizeInBytes * i)); + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBufferLength = pDevice->winmm.fragmentSizeInBytes; + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwFlags = 0L; + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwLoops = 0L; + + MMRESULT resultMM = ((MAL_PFN_waveInPrepareHeader)pDevice->pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] Failed to prepare header for capture device in preparation for adding a new capture buffer for the device.", mal_result_from_MMRESULT(resultMM)); + break; + } + + resultMM = ((MAL_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] Failed to add new capture buffer to the internal capture device.", mal_result_from_MMRESULT(resultMM)); + break; + } + } + + ResetEvent(pDevice->winmm.hEvent); + + if (((MAL_PFN_waveInStart)pDevice->pContext->winmm.waveInStart)((HWAVEIN)pDevice->winmm.hDevice) != MMSYSERR_NOERROR) { + return mal_post_error(pDevice, "[WinMM] Failed to start backend device.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + } + + pDevice->winmm.iNextHeader = 0; + return MAL_SUCCESS; +} + +static mal_result mal_device__stop_backend__winmm(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->type == mal_device_type_playback) { + MMRESULT resultMM = ((MAL_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevice); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] WARNING: Failed to reset playback device.", mal_result_from_MMRESULT(resultMM)); + } + + // Unprepare all WAVEHDR structures. + for (mal_uint32 i = 0; i < pDevice->periods; ++i) { + resultMM = ((MAL_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] WARNING: Failed to unprepare header for playback device.", mal_result_from_MMRESULT(resultMM)); + } + } + } else { + MMRESULT resultMM = ((MAL_PFN_waveInReset)pDevice->pContext->winmm.waveInReset)((HWAVEIN)pDevice->winmm.hDevice); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] WARNING: Failed to reset capture device.", mal_result_from_MMRESULT(resultMM)); + } + + // Unprepare all WAVEHDR structures. + for (mal_uint32 i = 0; i < pDevice->periods; ++i) { + resultMM = ((MAL_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] WARNING: Failed to unprepare header for playback device.", mal_result_from_MMRESULT(resultMM)); + } + } + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__break_main_loop__winmm(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + pDevice->winmm.breakFromMainLoop = MAL_TRUE; + SetEvent((HANDLE)pDevice->winmm.hEvent); + + return MAL_SUCCESS; +} + +static mal_result mal_device__main_loop__winmm(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + mal_uint32 counter; + + pDevice->winmm.breakFromMainLoop = MAL_FALSE; + while (!pDevice->winmm.breakFromMainLoop) { + // Wait for a block of data to finish processing... + if (WaitForSingleObject((HANDLE)pDevice->winmm.hEvent, INFINITE) != WAIT_OBJECT_0) { + break; + } + + // Break from the main loop if the device isn't started anymore. Likely what's happened is the application + // has requested that the device be stopped. + if (!mal_device_is_started(pDevice)) { + break; + } + + // Any headers that are marked as done need to be handled. We start by processing the completed blocks. Then we reset the event + // and then write or add replacement buffers to the device. + mal_uint32 iFirstHeader = pDevice->winmm.iNextHeader; + for (counter = 0; counter < pDevice->periods; ++counter) { + mal_uint32 i = pDevice->winmm.iNextHeader; + if ((((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwFlags & WHDR_DONE) == 0) { + break; + } + + if (pDevice->type == mal_device_type_playback) { + // Playback. + MMRESULT resultMM = ((MAL_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] Failed to unprepare header for playback device in preparation for sending a new block of data to the device for playback.", mal_result_from_MMRESULT(resultMM)); + break; + } + + mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]); + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBuffer + (pDevice->winmm.fragmentSizeInBytes * i)); + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBufferLength = pDevice->winmm.fragmentSizeInBytes; + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwFlags = 0L; + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwLoops = 0L; + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwUser = 1; // <-- Used in the next section to identify the buffers that needs to be re-written to the device. + mal_device__read_frames_from_client(pDevice, pDevice->winmm.fragmentSizeInFrames, ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData); + + resultMM = ((MAL_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] Failed to prepare header for playback device in preparation for sending a new block of data to the device for playback.", mal_result_from_MMRESULT(resultMM)); + break; + } + } else { + // Capture. + mal_uint32 framesCaptured = (mal_uint32)(((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBytesRecorded) / pDevice->internalChannels / mal_get_sample_size_in_bytes(pDevice->internalFormat); + if (framesCaptured > 0) { + mal_device__send_frames_to_client(pDevice, framesCaptured, ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData); + } + + MMRESULT resultMM = ((MAL_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] Failed to unprepare header for capture device in preparation for adding a new capture buffer for the device.", mal_result_from_MMRESULT(resultMM)); + break; + } + + mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]); + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBuffer + (pDevice->winmm.fragmentSizeInBytes * i)); + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBufferLength = pDevice->winmm.fragmentSizeInBytes; + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwFlags = 0L; + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwLoops = 0L; + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwUser = 1; // <-- Used in the next section to identify the buffers that needs to be re-added to the device. + + resultMM = ((MAL_PFN_waveInPrepareHeader)pDevice->pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] Failed to prepare header for capture device in preparation for adding a new capture buffer for the device.", mal_result_from_MMRESULT(resultMM)); + break; + } + } + + pDevice->winmm.iNextHeader = (pDevice->winmm.iNextHeader + 1) % pDevice->periods; + } + + ResetEvent((HANDLE)pDevice->winmm.hEvent); + + for (counter = 0; counter < pDevice->periods; ++counter) { + mal_uint32 i = (iFirstHeader + counter) % pDevice->periods; + + if (((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwUser == 1) { + ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwUser = 0; + + if (pDevice->type == mal_device_type_playback) { + // Playback. + MMRESULT resultMM = ((MAL_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] Failed to write data to the internal playback device.", mal_result_from_MMRESULT(resultMM)); + break; + } + } else { + // Capture. + MMRESULT resultMM = ((MAL_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); + if (resultMM != MMSYSERR_NOERROR) { + mal_post_error(pDevice, "[WinMM] Failed to add new capture buffer to the internal capture device.", mal_result_from_MMRESULT(resultMM)); + break; + } + } + } + } + } + + return MAL_SUCCESS; +} +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// +// ALSA Backend +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_ENABLE_ALSA +#include + +typedef int (* mal_snd_pcm_open_proc) (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode); +typedef int (* mal_snd_pcm_close_proc) (snd_pcm_t *pcm); +typedef size_t (* mal_snd_pcm_hw_params_sizeof_proc) (void); +typedef int (* mal_snd_pcm_hw_params_any_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +typedef int (* mal_snd_pcm_hw_params_set_format_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); +typedef int (* mal_snd_pcm_hw_params_set_format_first_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format); +typedef void (* mal_snd_pcm_hw_params_get_format_mask_proc) (snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); +typedef int (* mal_snd_pcm_hw_params_set_channels_near_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +typedef int (* mal_snd_pcm_hw_params_set_rate_resample_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +typedef int (* mal_snd_pcm_hw_params_set_rate_near_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +typedef int (* mal_snd_pcm_hw_params_set_buffer_size_near_proc)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +typedef int (* mal_snd_pcm_hw_params_set_periods_near_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +typedef int (* mal_snd_pcm_hw_params_set_access_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access); +typedef int (* mal_snd_pcm_hw_params_get_format_proc) (snd_pcm_hw_params_t *params, snd_pcm_format_t *format); +typedef int (* mal_snd_pcm_hw_params_get_channels_proc) (snd_pcm_hw_params_t *params, unsigned int *val); +typedef int (* mal_snd_pcm_hw_params_get_rate_proc) (snd_pcm_hw_params_t *params, unsigned int *rate, int *dir); +typedef int (* mal_snd_pcm_hw_params_get_buffer_size_proc) (snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +typedef int (* mal_snd_pcm_hw_params_get_periods_proc) (snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +typedef int (* mal_snd_pcm_hw_params_get_access_proc) (snd_pcm_hw_params_t *params, snd_pcm_access_t *_access); +typedef int (* mal_snd_pcm_hw_params_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +typedef size_t (* mal_snd_pcm_sw_params_sizeof_proc) (void); +typedef int (* mal_snd_pcm_sw_params_current_proc) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params); +typedef int (* mal_snd_pcm_sw_params_set_avail_min_proc) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +typedef int (* mal_snd_pcm_sw_params_set_start_threshold_proc) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +typedef int (* mal_snd_pcm_sw_params_proc) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params); +typedef size_t (* mal_snd_pcm_format_mask_sizeof_proc) (void); +typedef int (* mal_snd_pcm_format_mask_test_proc) (const snd_pcm_format_mask_t *mask, snd_pcm_format_t val); +typedef snd_pcm_chmap_t * (* mal_snd_pcm_get_chmap_proc) (snd_pcm_t *pcm); +typedef int (* mal_snd_pcm_prepare_proc) (snd_pcm_t *pcm); +typedef int (* mal_snd_pcm_start_proc) (snd_pcm_t *pcm); +typedef int (* mal_snd_pcm_drop_proc) (snd_pcm_t *pcm); +typedef int (* mal_snd_device_name_hint_proc) (int card, const char *iface, void ***hints); +typedef char * (* mal_snd_device_name_get_hint_proc) (const void *hint, const char *id); +typedef int (* mal_snd_card_get_index_proc) (const char *name); +typedef int (* mal_snd_device_name_free_hint_proc) (void **hints); +typedef int (* mal_snd_pcm_mmap_begin_proc) (snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames); +typedef snd_pcm_sframes_t (* mal_snd_pcm_mmap_commit_proc) (snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t frames); +typedef int (* mal_snd_pcm_recover_proc) (snd_pcm_t *pcm, int err, int silent); +typedef snd_pcm_sframes_t (* mal_snd_pcm_readi_proc) (snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); +typedef snd_pcm_sframes_t (* mal_snd_pcm_writei_proc) (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); +typedef snd_pcm_sframes_t (* mal_snd_pcm_avail_proc) (snd_pcm_t *pcm); +typedef snd_pcm_sframes_t (* mal_snd_pcm_avail_update_proc) (snd_pcm_t *pcm); +typedef int (* mal_snd_pcm_wait_proc) (snd_pcm_t *pcm, int timeout); + +static snd_pcm_format_t g_mal_ALSAFormats[] = { + SND_PCM_FORMAT_UNKNOWN, // mal_format_unknown + SND_PCM_FORMAT_U8, // mal_format_u8 + SND_PCM_FORMAT_S16_LE, // mal_format_s16 + SND_PCM_FORMAT_S24_3LE, // mal_format_s24 + SND_PCM_FORMAT_S32_LE, // mal_format_s32 + SND_PCM_FORMAT_FLOAT_LE // mal_format_f32 +}; + +snd_pcm_format_t mal_convert_mal_format_to_alsa_format(mal_format format) +{ + return g_mal_ALSAFormats[format]; +} + +mal_format mal_convert_alsa_format_to_mal_format(snd_pcm_format_t formatALSA) +{ + switch (formatALSA) + { + case SND_PCM_FORMAT_U8: return mal_format_u8; + case SND_PCM_FORMAT_S16_LE: return mal_format_s16; + case SND_PCM_FORMAT_S24_3LE: return mal_format_s24; + case SND_PCM_FORMAT_S32_LE: return mal_format_s32; + case SND_PCM_FORMAT_FLOAT_LE: return mal_format_f32; + default: return mal_format_unknown; + } +} + +mal_channel mal_convert_alsa_channel_position_to_mal_channel(unsigned int alsaChannelPos) +{ + switch (alsaChannelPos) + { + case SND_CHMAP_FL: return MAL_CHANNEL_FRONT_LEFT; + case SND_CHMAP_FR: return MAL_CHANNEL_FRONT_RIGHT; + case SND_CHMAP_RL: return MAL_CHANNEL_BACK_LEFT; + case SND_CHMAP_RR: return MAL_CHANNEL_BACK_RIGHT; + case SND_CHMAP_FC: return MAL_CHANNEL_FRONT_CENTER; + case SND_CHMAP_LFE: return MAL_CHANNEL_LFE; + case SND_CHMAP_SL: return MAL_CHANNEL_SIDE_LEFT; + case SND_CHMAP_SR: return MAL_CHANNEL_SIDE_RIGHT; + case SND_CHMAP_RC: return MAL_CHANNEL_BACK_CENTER; + case SND_CHMAP_FLC: return MAL_CHANNEL_FRONT_LEFT_CENTER; + case SND_CHMAP_FRC: return MAL_CHANNEL_FRONT_RIGHT_CENTER; + case SND_CHMAP_RLC: return 0; + case SND_CHMAP_RRC: return 0; + case SND_CHMAP_FLW: return 0; + case SND_CHMAP_FRW: return 0; + case SND_CHMAP_FLH: return 0; + case SND_CHMAP_FCH: return 0; + case SND_CHMAP_FRH: return 0; + case SND_CHMAP_TC: return MAL_CHANNEL_TOP_CENTER; + case SND_CHMAP_TFL: return MAL_CHANNEL_TOP_FRONT_LEFT; + case SND_CHMAP_TFR: return MAL_CHANNEL_TOP_FRONT_RIGHT; + case SND_CHMAP_TFC: return MAL_CHANNEL_TOP_FRONT_CENTER; + case SND_CHMAP_TRL: return MAL_CHANNEL_TOP_BACK_LEFT; + case SND_CHMAP_TRR: return MAL_CHANNEL_TOP_BACK_RIGHT; + case SND_CHMAP_TRC: return MAL_CHANNEL_TOP_BACK_CENTER; + default: break; + } + + return 0; +} + +mal_result mal_context_init__alsa(mal_context* pContext) +{ + mal_assert(pContext != NULL); + + pContext->alsa.asoundSO = mal_dlopen("libasound.so"); + if (pContext->alsa.asoundSO == NULL) { + return MAL_NO_BACKEND; + } + + pContext->alsa.snd_pcm_open = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_open"); + pContext->alsa.snd_pcm_close = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_close"); + pContext->alsa.snd_pcm_hw_params_sizeof = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_sizeof"); + pContext->alsa.snd_pcm_hw_params_any = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_any"); + pContext->alsa.snd_pcm_hw_params_set_format = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format"); + pContext->alsa.snd_pcm_hw_params_set_format_first = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format_first"); + pContext->alsa.snd_pcm_hw_params_get_format_mask = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format_mask"); + pContext->alsa.snd_pcm_hw_params_set_channels_near = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_near"); + pContext->alsa.snd_pcm_hw_params_set_rate_resample = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_resample"); + pContext->alsa.snd_pcm_hw_params_set_rate_near = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_near"); + pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_buffer_size_near"); + pContext->alsa.snd_pcm_hw_params_set_periods_near = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_periods_near"); + pContext->alsa.snd_pcm_hw_params_set_access = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_access"); + pContext->alsa.snd_pcm_hw_params_get_format = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format"); + pContext->alsa.snd_pcm_hw_params_get_channels = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels"); + pContext->alsa.snd_pcm_hw_params_get_rate = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate"); + pContext->alsa.snd_pcm_hw_params_get_buffer_size = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_buffer_size"); + pContext->alsa.snd_pcm_hw_params_get_periods = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_periods"); + pContext->alsa.snd_pcm_hw_params_get_access = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_access"); + pContext->alsa.snd_pcm_hw_params = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params"); + pContext->alsa.snd_pcm_sw_params_sizeof = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_sizeof"); + pContext->alsa.snd_pcm_sw_params_current = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_current"); + pContext->alsa.snd_pcm_sw_params_set_avail_min = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_set_avail_min"); + pContext->alsa.snd_pcm_sw_params_set_start_threshold = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_set_start_threshold"); + pContext->alsa.snd_pcm_sw_params = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params"); + pContext->alsa.snd_pcm_format_mask_sizeof = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_format_mask_sizeof"); + pContext->alsa.snd_pcm_format_mask_test = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_format_mask_test"); + pContext->alsa.snd_pcm_get_chmap = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_get_chmap"); + pContext->alsa.snd_pcm_prepare = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_prepare"); + pContext->alsa.snd_pcm_start = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_start"); + pContext->alsa.snd_pcm_drop = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_drop"); + pContext->alsa.snd_device_name_hint = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_device_name_hint"); + pContext->alsa.snd_device_name_get_hint = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_device_name_get_hint"); + pContext->alsa.snd_card_get_index = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_card_get_index"); + pContext->alsa.snd_device_name_free_hint = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_device_name_free_hint"); + pContext->alsa.snd_pcm_mmap_begin = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_mmap_begin"); + pContext->alsa.snd_pcm_mmap_commit = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_mmap_commit"); + pContext->alsa.snd_pcm_recover = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_recover"); + pContext->alsa.snd_pcm_readi = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_readi"); + pContext->alsa.snd_pcm_writei = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_writei"); + pContext->alsa.snd_pcm_avail = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_avail"); + pContext->alsa.snd_pcm_avail_update = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_avail_update"); + pContext->alsa.snd_pcm_wait = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_wait"); + + return MAL_SUCCESS; +} + +mal_result mal_context_uninit__alsa(mal_context* pContext) +{ + mal_assert(pContext != NULL); + mal_assert(pContext->backend == mal_backend_alsa); + + (void)pContext; + return MAL_SUCCESS; +} + +static const char* mal_find_char(const char* str, char c, int* index) +{ + int i = 0; + for (;;) { + if (str[i] == '\0') { + if (index) *index = -1; + return NULL; + } + + if (str[i] == c) { + if (index) *index = i; + return str + i; + } + + i += 1; + } + + // Should never get here, but treat it as though the character was not found to make me feel + // better inside. + if (index) *index = -1; + return NULL; +} + +// Waits for a number of frames to become available for either capture or playback. The return +// value is the number of frames available. +// +// This will return early if the main loop is broken with mal_device__break_main_loop(). +static mal_uint32 mal_device__wait_for_frames__alsa(mal_device* pDevice, mal_bool32* pRequiresRestart) +{ + mal_assert(pDevice != NULL); + + if (pRequiresRestart) *pRequiresRestart = MAL_FALSE; + + mal_uint32 periodSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods; + + while (!pDevice->alsa.breakFromMainLoop) { + // Wait for something to become available. The timeout should not affect latency - it's only used to break from the wait + // so we can check whether or not the device has been stopped. + const int timeoutInMilliseconds = 10; + int waitResult = ((mal_snd_pcm_wait_proc)pDevice->pContext->alsa.snd_pcm_wait)((snd_pcm_t*)pDevice->alsa.pPCM, timeoutInMilliseconds); + if (waitResult < 0) { + if (waitResult == -EPIPE) { + if (((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, waitResult, MAL_TRUE) < 0) { + return 0; + } + + if (pRequiresRestart) *pRequiresRestart = MAL_TRUE; // A device recovery means a restart for mmap mode. + } + } + + if (pDevice->alsa.breakFromMainLoop) { + return 0; + } + + snd_pcm_sframes_t framesAvailable = ((mal_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((snd_pcm_t*)pDevice->alsa.pPCM); + if (framesAvailable < 0) { + if (framesAvailable == -EPIPE) { + if (((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, framesAvailable, MAL_TRUE) < 0) { + return 0; + } + + if (pRequiresRestart) *pRequiresRestart = MAL_TRUE; // A device recovery means a restart for mmap mode. + + // Try again, but if it fails this time just return an error. + framesAvailable = ((mal_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((snd_pcm_t*)pDevice->alsa.pPCM); + if (framesAvailable < 0) { + return 0; + } + } + } + + // Keep the returned number of samples consistent and based on the period size. + if (framesAvailable >= periodSizeInFrames) { + return periodSizeInFrames; + } + } + + // We'll get here if the loop was terminated. Just return whatever's available. + snd_pcm_sframes_t framesAvailable = ((mal_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((snd_pcm_t*)pDevice->alsa.pPCM); + if (framesAvailable < 0) { + return 0; + } + + return framesAvailable; +} + +static mal_bool32 mal_device_write__alsa(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + if (!mal_device_is_started(pDevice) && mal_device__get_state(pDevice) != MAL_STATE_STARTING) { + return MAL_FALSE; + } + if (pDevice->alsa.breakFromMainLoop) { + return MAL_FALSE; + } + + + if (pDevice->alsa.isUsingMMap) { + // mmap. + mal_bool32 requiresRestart; + mal_uint32 framesAvailable = mal_device__wait_for_frames__alsa(pDevice, &requiresRestart); + if (framesAvailable == 0) { + return MAL_FALSE; + } + + // Don't bother asking the client for more audio data if we're just stopping the device anyway. + if (pDevice->alsa.breakFromMainLoop) { + return MAL_FALSE; + } + + const snd_pcm_channel_area_t* pAreas; + snd_pcm_uframes_t mappedOffset; + snd_pcm_uframes_t mappedFrames = framesAvailable; + while (framesAvailable > 0) { + int result = ((mal_snd_pcm_mmap_begin_proc)pDevice->pContext->alsa.snd_pcm_mmap_begin)((snd_pcm_t*)pDevice->alsa.pPCM, &pAreas, &mappedOffset, &mappedFrames); + if (result < 0) { + return MAL_FALSE; + } + + if (mappedFrames > 0) { + void* pBuffer = (mal_uint8*)pAreas[0].addr + ((pAreas[0].first + (mappedOffset * pAreas[0].step)) / 8); + mal_device__read_frames_from_client(pDevice, mappedFrames, pBuffer); + } + + result = ((mal_snd_pcm_mmap_commit_proc)pDevice->pContext->alsa.snd_pcm_mmap_commit)((snd_pcm_t*)pDevice->alsa.pPCM, mappedOffset, mappedFrames); + if (result < 0 || (snd_pcm_uframes_t)result != mappedFrames) { + ((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, result, MAL_TRUE); + return MAL_FALSE; + } + + if (requiresRestart) { + if (((mal_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((snd_pcm_t*)pDevice->alsa.pPCM) < 0) { + return MAL_FALSE; + } + } + + framesAvailable -= mappedFrames; + } + } else { + // readi/writei. + while (!pDevice->alsa.breakFromMainLoop) { + mal_uint32 framesAvailable = mal_device__wait_for_frames__alsa(pDevice, NULL); + if (framesAvailable == 0) { + continue; + } + + // Don't bother asking the client for more audio data if we're just stopping the device anyway. + if (pDevice->alsa.breakFromMainLoop) { + return MAL_FALSE; + } + + mal_device__read_frames_from_client(pDevice, framesAvailable, pDevice->alsa.pIntermediaryBuffer); + + snd_pcm_sframes_t framesWritten = ((mal_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); + if (framesWritten < 0) { + if (framesWritten == -EAGAIN) { + continue; // Just keep trying... + } else if (framesWritten == -EPIPE) { + // Underrun. Just recover and try writing again. + if (((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, framesWritten, MAL_TRUE) < 0) { + mal_post_error(pDevice, "[ALSA] Failed to recover device after underrun.", MAL_ALSA_FAILED_TO_RECOVER_DEVICE); + return MAL_FALSE; + } + + framesWritten = ((mal_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); + if (framesWritten < 0) { + mal_post_error(pDevice, "[ALSA] Failed to write data to the internal device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); + return MAL_FALSE; + } + + break; // Success. + } else { + mal_post_error(pDevice, "[ALSA] snd_pcm_writei() failed when writing initial data.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); + return MAL_FALSE; + } + } else { + break; // Success. + } + } + } + + return MAL_TRUE; +} + +static mal_bool32 mal_device_read__alsa(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + if (!mal_device_is_started(pDevice)) { + return MAL_FALSE; + } + if (pDevice->alsa.breakFromMainLoop) { + return MAL_FALSE; + } + + mal_uint32 framesToSend = 0; + void* pBuffer = NULL; + if (pDevice->alsa.pIntermediaryBuffer == NULL) { + // mmap. + mal_bool32 requiresRestart; + mal_uint32 framesAvailable = mal_device__wait_for_frames__alsa(pDevice, &requiresRestart); + if (framesAvailable == 0) { + return MAL_FALSE; + } + + const snd_pcm_channel_area_t* pAreas; + snd_pcm_uframes_t mappedOffset; + snd_pcm_uframes_t mappedFrames = framesAvailable; + while (framesAvailable > 0) { + int result = ((mal_snd_pcm_mmap_begin_proc)pDevice->pContext->alsa.snd_pcm_mmap_begin)((snd_pcm_t*)pDevice->alsa.pPCM, &pAreas, &mappedOffset, &mappedFrames); + if (result < 0) { + return MAL_FALSE; + } + + if (mappedFrames > 0) { + void* pBuffer = (mal_uint8*)pAreas[0].addr + ((pAreas[0].first + (mappedOffset * pAreas[0].step)) / 8); + mal_device__send_frames_to_client(pDevice, mappedFrames, pBuffer); + } + + result = ((mal_snd_pcm_mmap_commit_proc)pDevice->pContext->alsa.snd_pcm_mmap_commit)((snd_pcm_t*)pDevice->alsa.pPCM, mappedOffset, mappedFrames); + if (result < 0 || (snd_pcm_uframes_t)result != mappedFrames) { + ((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, result, MAL_TRUE); + return MAL_FALSE; + } + + if (requiresRestart) { + if (((mal_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((snd_pcm_t*)pDevice->alsa.pPCM) < 0) { + return MAL_FALSE; + } + } + + framesAvailable -= mappedFrames; + } + } else { + // readi/writei. + snd_pcm_sframes_t framesRead = 0; + while (!pDevice->alsa.breakFromMainLoop) { + mal_uint32 framesAvailable = mal_device__wait_for_frames__alsa(pDevice, NULL); + if (framesAvailable == 0) { + continue; + } + + framesRead = ((mal_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); + if (framesRead < 0) { + if (framesRead == -EAGAIN) { + continue; // Just keep trying... + } else if (framesRead == -EPIPE) { + // Overrun. Just recover and try reading again. + if (((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, framesRead, MAL_TRUE) < 0) { + mal_post_error(pDevice, "[ALSA] Failed to recover device after overrun.", MAL_ALSA_FAILED_TO_RECOVER_DEVICE); + return MAL_FALSE; + } + + framesRead = ((mal_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); + if (framesRead < 0) { + mal_post_error(pDevice, "[ALSA] Failed to read data from the internal device.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE); + return MAL_FALSE; + } + + break; // Success. + } else { + return MAL_FALSE; + } + } else { + break; // Success. + } + } + + framesToSend = framesRead; + pBuffer = pDevice->alsa.pIntermediaryBuffer; + } + + if (framesToSend > 0) { + mal_device__send_frames_to_client(pDevice, framesToSend, pBuffer); + } + + return MAL_TRUE; +} + + + +static mal_bool32 mal_is_device_name_in_hw_format__alsa(const char* hwid) +{ + // This function is just checking whether or not hwid is in "hw:%d,%d" format. + + if (hwid == NULL) { + return MAL_FALSE; + } + + if (hwid[0] != 'h' || hwid[1] != 'w' || hwid[2] != ':') { + return MAL_FALSE; + } + + hwid += 3; + + int commaPos; + const char* dev = mal_find_char(hwid, ',', &commaPos); + if (dev == NULL) { + return MAL_FALSE; + } else { + dev += 1; // Skip past the ",". + } + + // Check if the part between the ":" and the "," contains only numbers. If not, return false. + for (int i = 0; i < commaPos; ++i) { + if (hwid[i] < '0' || hwid[i] > '9') { + return MAL_FALSE; + } + } + + // Check if everything after the "," is numeric. If not, return false. + int i = 0; + while (dev[i] != '\0') { + if (dev[i] < '0' || dev[i] > '9') { + return MAL_FALSE; + } + i += 1; + } + + return MAL_TRUE; +} + +static int mal_convert_device_name_to_hw_format__alsa(mal_context* pContext, char* dst, size_t dstSize, const char* src) // Returns 0 on success, non-0 on error. +{ + // src should look something like this: "hw:CARD=I82801AAICH,DEV=0" + + if (dst == NULL) return -1; + if (dstSize < 7) return -1; // Absolute minimum size of the output buffer is 7 bytes. + + *dst = '\0'; // Safety. + if (src == NULL) return -1; + + // If the input name is already in "hw:%d,%d" format, just return that verbatim. + if (mal_is_device_name_in_hw_format__alsa(src)) { + return mal_strcpy_s(dst, dstSize, src); + } + + + int colonPos; + src = mal_find_char(src, ':', &colonPos); + if (src == NULL) { + return -1; // Couldn't find a colon + } + + char card[256]; + + int commaPos; + const char* dev = mal_find_char(src, ',', &commaPos); + if (dev == NULL) { + dev = "0"; + mal_strncpy_s(card, sizeof(card), src+6, (size_t)-1); // +6 = ":CARD=" + } else { + dev = dev + 5; // +5 = ",DEV=" + mal_strncpy_s(card, sizeof(card), src+6, commaPos-6); // +6 = ":CARD=" + } + + int cardIndex = ((mal_snd_card_get_index_proc)pContext->alsa.snd_card_get_index)(card); + if (cardIndex < 0) { + return -2; // Failed to retrieve the card index. + } + + //printf("TESTING: CARD=%s,DEV=%s\n", card, dev); + + + // Construction. + dst[0] = 'h'; dst[1] = 'w'; dst[2] = ':'; + if (mal_itoa_s(cardIndex, dst+3, dstSize-3, 10) != 0) { + return -3; + } + if (mal_strcat_s(dst, dstSize, ",") != 0) { + return -3; + } + if (mal_strcat_s(dst, dstSize, dev) != 0) { + return -3; + } + + return 0; +} + +static mal_bool32 mal_does_id_exist_in_list__alsa(mal_device_id* pUniqueIDs, mal_uint32 count, const char* pHWID) +{ + mal_assert(pHWID != NULL); + + for (mal_uint32 i = 0; i < count; ++i) { + if (mal_strcmp(pUniqueIDs[i].alsa, pHWID) == 0) { + return MAL_TRUE; + } + } + + return MAL_FALSE; +} + +static mal_result mal_enumerate_devices__alsa(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) +{ + (void)pContext; + + mal_uint32 infoSize = *pCount; + *pCount = 0; + + char** ppDeviceHints; + if (((mal_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints) < 0) { + return MAL_NO_BACKEND; + } + + mal_device_id* pUniqueIDs = NULL; + mal_uint32 uniqueIDCount = 0; + + char** ppNextDeviceHint = ppDeviceHints; + while (*ppNextDeviceHint != NULL) { + char* NAME = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME"); + char* DESC = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC"); + char* IOID = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID"); + + // Only include devices if they are of the correct type. Special cases for "default", "null" and "pulse" - these are included for both playback and capture + // regardless of the IOID setting. + mal_bool32 includeThisDevice = MAL_FALSE; + if (strcmp(NAME, "default") == 0 || strcmp(NAME, "pulse") == 0 || strcmp(NAME, "null") == 0) { + includeThisDevice = MAL_TRUE; + + // Exclude the "null" device if requested. + if (strcmp(NAME, "null") == 0 && pContext->config.alsa.excludeNullDevice) { + includeThisDevice = MAL_FALSE; + } + } else { + if ((type == mal_device_type_playback && (IOID == NULL || strcmp(IOID, "Output") == 0)) || + (type == mal_device_type_capture && (IOID != NULL && strcmp(IOID, "Input" ) == 0))) { + includeThisDevice = MAL_TRUE; + } + } + + + + if (includeThisDevice) { +#if 0 + printf("NAME: %s\n", NAME); + printf("DESC: %s\n", DESC); + printf("IOID: %s\n", IOID); + + char hwid2[256]; + mal_convert_device_name_to_hw_format__alsa(pContext, hwid2, sizeof(hwid2), NAME); + printf("DEVICE ID: %s (%d)\n\n", hwid2, *pCount); +#endif + + char hwid[sizeof(pUniqueIDs->alsa)]; + if (NAME != NULL) { + if (pContext->config.alsa.useVerboseDeviceEnumeration) { + // Verbose mode. Use the name exactly as-is. + mal_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1); + } else { + // Simplified mode. Use ":%d,%d" format. + if (mal_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) { + // At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the + // plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device + // initialization time and is used as an indicator to try and use the most appropriate plugin depending on the + // device type and sharing mode. + char* dst = hwid; + char* src = hwid+2; + while ((*dst++ = *src++)); + } else { + // Conversion to "hw:%d,%d" failed. Just use the name as-is. + mal_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1); + } + + if (mal_does_id_exist_in_list__alsa(pUniqueIDs, uniqueIDCount, hwid)) { + goto next_device; // The device has already been enumerated. Move on to the next one. + } else { + // The device has not yet been enumerated. Make sure it's added to our list so that it's not enumerated again. + mal_device_id* pNewUniqueIDs = mal_realloc(pUniqueIDs, sizeof(*pUniqueIDs) * (uniqueIDCount + 1)); + if (pNewUniqueIDs == NULL) { + goto next_device; // Failed to allocate memory. + } + + pUniqueIDs = pNewUniqueIDs; + mal_copy_memory(pUniqueIDs[uniqueIDCount].alsa, hwid, sizeof(hwid)); + uniqueIDCount += 1; + } + } + } else { + mal_zero_memory(hwid, sizeof(hwid)); + } + + if (pInfo != NULL) { + if (infoSize > 0) { + mal_zero_object(pInfo); + mal_strncpy_s(pInfo->id.alsa, sizeof(pInfo->id.alsa), hwid, (size_t)-1); + + // DESC is the friendly name. We treat this slightly differently depending on whether or not we are using verbose + // device enumeration. In verbose mode we want to take the entire description so that the end-user can distinguish + // between the subdevices of each card/dev pair. In simplified mode, however, we only want the first part of the + // description. + // + // The value in DESC seems to be split into two lines, with the first line being the name of the device and the + // second line being a description of the device. I don't like having the description be across two lines because + // it makes formatting ugly and annoying. I'm therefore deciding to put it all on a single line with the second line + // being put into parentheses. In simplified mode I'm just stripping the second line entirely. + if (DESC != NULL) { + int lfPos; + const char* line2 = mal_find_char(DESC, '\n', &lfPos); + if (line2 != NULL) { + line2 += 1; // Skip past the new-line character. + + if (pContext->config.alsa.useVerboseDeviceEnumeration) { + // Verbose mode. Put the second line in brackets. + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), DESC, lfPos); + mal_strcat_s (pInfo->name, sizeof(pInfo->name), " ("); + mal_strcat_s (pInfo->name, sizeof(pInfo->name), line2); + mal_strcat_s (pInfo->name, sizeof(pInfo->name), ")"); + } else { + // Simplified mode. Strip the second line entirely. + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), DESC, lfPos); + } + } else { + // There's no second line. Just copy the whole description. + mal_strcpy_s(pInfo->name, sizeof(pInfo->name), DESC); + } + } + + pInfo += 1; + infoSize -= 1; + *pCount += 1; + } + } else { + *pCount += 1; + } + } + + next_device: + free(NAME); + free(DESC); + free(IOID); + ppNextDeviceHint += 1; + } + + mal_free(pUniqueIDs); + + ((mal_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints); + return MAL_SUCCESS; +} + +static void mal_device_uninit__alsa(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if ((snd_pcm_t*)pDevice->alsa.pPCM) { + ((mal_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((snd_pcm_t*)pDevice->alsa.pPCM); + + if (pDevice->alsa.pIntermediaryBuffer != NULL) { + mal_free(pDevice->alsa.pIntermediaryBuffer); + } + } +} + +static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) +{ + (void)pContext; + + mal_assert(pDevice != NULL); + mal_zero_object(&pDevice->alsa); + + snd_pcm_format_t formatALSA = mal_convert_mal_format_to_alsa_format(pConfig->format); + snd_pcm_stream_t stream = (type == mal_device_type_playback) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE; + + if (pDeviceID == NULL) { + // We're opening the default device. I don't know if trying anything other than "default" is necessary, but it makes + // me feel better to try as hard as we can get to get _something_ working. + const char* defaultDeviceNames[] = { + "default", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + }; + + if (pConfig->preferExclusiveMode) { + defaultDeviceNames[1] = "hw"; + defaultDeviceNames[2] = "hw:0"; + defaultDeviceNames[3] = "hw:0,0"; + } else { + if (type == mal_device_type_playback) { + defaultDeviceNames[1] = "dmix"; + defaultDeviceNames[2] = "dmix:0"; + defaultDeviceNames[3] = "dmix:0,0"; + } else { + defaultDeviceNames[1] = "dsnoop"; + defaultDeviceNames[2] = "dsnoop:0"; + defaultDeviceNames[3] = "dsnoop:0,0"; + } + defaultDeviceNames[4] = "hw"; + defaultDeviceNames[5] = "hw:0"; + defaultDeviceNames[6] = "hw:0,0"; + } + + mal_bool32 isDeviceOpen = MAL_FALSE; + for (size_t i = 0; i < mal_countof(defaultDeviceNames); ++i) { + if (defaultDeviceNames[i] != NULL && defaultDeviceNames[i][0] != '\0') { + if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, defaultDeviceNames[i], stream, 0) == 0) { + isDeviceOpen = MAL_TRUE; + break; + } + } + } + + if (!isDeviceOpen) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.", MAL_ALSA_FAILED_TO_OPEN_DEVICE); + } + } else { + // We're trying to open a specific device. There's a few things to consider here: + // + // mini_al recongnizes a special format of device id that excludes the "hw", "dmix", etc. prefix. It looks like this: ":0,0", ":0,1", etc. When + // an ID of this format is specified, it indicates to mini_al that it can try different combinations of plugins ("hw", "dmix", etc.) until it + // finds an appropriate one that works. This comes in very handy when trying to open a device in shared mode ("dmix"), vs exclusive mode ("hw"). + mal_bool32 isDeviceOpen = MAL_FALSE; + if (pDeviceID->alsa[0] != ':') { + // The ID is not in ":0,0" format. Use the ID exactly as-is. + if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, pDeviceID->alsa, stream, 0) == 0) { + isDeviceOpen = MAL_TRUE; + } + } else { + // The ID is in ":0,0" format. Try different plugins depending on the shared mode. + if (pDeviceID->alsa[1] == '\0') { + pDeviceID->alsa[0] = '\0'; // An ID of ":" should be converted to "". + } + + char hwid[256]; + if (!pConfig->preferExclusiveMode) { + if (type == mal_device_type_playback) { + mal_strcpy_s(hwid, sizeof(hwid), "dmix"); + } else { + mal_strcpy_s(hwid, sizeof(hwid), "dsnoop"); + } + + if (mal_strcat_s(hwid, sizeof(hwid), pDeviceID->alsa) == 0) { + if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, hwid, stream, 0) == 0) { + isDeviceOpen = MAL_TRUE; + } + } + } + + // If at this point we still don't have an open device it means we're either preferencing exclusive mode or opening with "dmix"/"dsnoop" failed. + if (!isDeviceOpen) { + mal_strcpy_s(hwid, sizeof(hwid), "hw"); + if (mal_strcat_s(hwid, sizeof(hwid), pDeviceID->alsa) == 0) { + if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, hwid, stream, 0) == 0) { + isDeviceOpen = MAL_TRUE; + } + } + } + } + + if (!isDeviceOpen) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] snd_pcm_open() failed.", MAL_ALSA_FAILED_TO_OPEN_DEVICE); + } + } + + + // Hardware parameters. + snd_pcm_hw_params_t* pHWParams = (snd_pcm_hw_params_t*)alloca(((mal_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)()); + mal_zero_memory(pHWParams, ((mal_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)()); + + if (((mal_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams) < 0) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", MAL_ALSA_FAILED_TO_SET_HW_PARAMS); + } + + + // MMAP Mode + // + // Try using interleaved MMAP access. If this fails, fall back to standard readi/writei. + pDevice->alsa.isUsingMMap = MAL_FALSE; + if (!pConfig->alsa.noMMap && pDevice->type != mal_device_type_capture) { // <-- Disabling MMAP mode for capture devices because I apparently do not have a device that supports it so I can test it... Contributions welcome. + if (((mal_snd_pcm_hw_params_set_access_proc)pContext->alsa.snd_pcm_hw_params_set_access)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, SND_PCM_ACCESS_MMAP_INTERLEAVED) == 0) { + pDevice->alsa.isUsingMMap = MAL_TRUE; + } + } + + if (!pDevice->alsa.isUsingMMap) { + if (((mal_snd_pcm_hw_params_set_access_proc)pContext->alsa.snd_pcm_hw_params_set_access)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {; + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Failed to set access mode to neither SND_PCM_ACCESS_MMAP_INTERLEAVED nor SND_PCM_ACCESS_RW_INTERLEAVED. snd_pcm_hw_params_set_access() failed.", MAL_FORMAT_NOT_SUPPORTED); + } + } + + + // Most important properties first. The documentation for OSS (yes, I know this is ALSA!) recommends format, channels, then sample rate. I can't + // find any documentation for ALSA specifically, so I'm going to copy the recommendation for OSS. + + // Format. + // Try getting every supported format. + snd_pcm_format_mask_t* pFormatMask = (snd_pcm_format_mask_t*)alloca(((mal_snd_pcm_format_mask_sizeof_proc)pContext->alsa.snd_pcm_format_mask_sizeof)()); + mal_zero_memory(pFormatMask, ((mal_snd_pcm_format_mask_sizeof_proc)pContext->alsa.snd_pcm_format_mask_sizeof)()); + + ((mal_snd_pcm_hw_params_get_format_mask_proc)pContext->alsa.snd_pcm_hw_params_get_format_mask)(pHWParams, pFormatMask); + + // At this point we should have a list of supported formats, so now we need to find the best one. We first check if the requested format is + // supported, and if so, use that one. If it's not supported, we just run though a list of formats and try to find the best one. + if (!((mal_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, formatALSA)) { + // The requested format is not supported so now try running through the list of formats and return the best one. + snd_pcm_format_t preferredFormatsALSA[] = { + SND_PCM_FORMAT_FLOAT_LE, // mal_format_f32 + SND_PCM_FORMAT_S32_LE, // mal_format_s32 + SND_PCM_FORMAT_S24_3LE, // mal_format_s24 + SND_PCM_FORMAT_S16_LE, // mal_format_s16 + SND_PCM_FORMAT_U8 // mal_format_u8 + }; + + formatALSA = SND_PCM_FORMAT_UNKNOWN; + for (size_t i = 0; i < (sizeof(preferredFormatsALSA) / sizeof(preferredFormatsALSA[0])); ++i) { + if (((mal_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, preferredFormatsALSA[i])) { + formatALSA = preferredFormatsALSA[i]; + break; + } + } + + if (formatALSA == SND_PCM_FORMAT_UNKNOWN) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Format not supported. The device does not support any mini_al formats.", MAL_FORMAT_NOT_SUPPORTED); + } + } + + if (((mal_snd_pcm_hw_params_set_format_proc)pContext->alsa.snd_pcm_hw_params_set_format)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, formatALSA) < 0) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed.", MAL_FORMAT_NOT_SUPPORTED); + } + + pDevice->internalFormat = mal_convert_alsa_format_to_mal_format(formatALSA); + if (pDevice->internalFormat == mal_format_unknown) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] The chosen format is not supported by mini_al.", MAL_FORMAT_NOT_SUPPORTED); + } + + // Channels. + mal_uint32 channels = pConfig->channels; + if (((mal_snd_pcm_hw_params_set_channels_near_proc)pContext->alsa.snd_pcm_hw_params_set_channels_near)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, &channels) < 0) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed.", MAL_FORMAT_NOT_SUPPORTED); + } + pDevice->internalChannels = channels; + + + // Sample Rate. It appears there's either a bug in ALSA, a bug in some drivers, or I'm doing something silly; but having resampling + // enabled causes problems with some device configurations when used in conjunction with MMAP access mode. To fix this problem we + // need to disable resampling. + // + // To reproduce this problem, open the "plug:dmix" device, and set the sample rate to 44100. Internally, it looks like dmix uses a + // sample rate of 48000. The hardware parameters will get set correctly with no errors, but it looks like the 44100 -> 48000 resampling + // doesn't work properly - but only with MMAP access mode. You will notice skipping/crackling in the audio, and it'll run at a slightly + // faster rate. + // + // mini_al has built-in support for sample rate conversion (albeit low quality at the moment), so disabling resampling should be fine + // for us. The only problem is that it won't be taking advantage of any kind of hardware-accelerated resampling and it won't be very + // good quality until I get a chance to improve the quality of mini_al's software sample rate conversion. + // + // I don't currently know if the dmix plugin is the only one with this error. Indeed, this is the only one I've been able to reproduce + // this error with. In the future, we may want to restrict the disabling of resampling to only known bad plugins. + ((mal_snd_pcm_hw_params_set_rate_resample_proc)pContext->alsa.snd_pcm_hw_params_set_rate_resample)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, 0); + + mal_uint32 sampleRate = pConfig->sampleRate; + if (((mal_snd_pcm_hw_params_set_rate_near_proc)pContext->alsa.snd_pcm_hw_params_set_rate_near)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, &sampleRate, 0) < 0) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed.", MAL_FORMAT_NOT_SUPPORTED); + } + pDevice->internalSampleRate = sampleRate; + + + // Periods. + mal_uint32 periods = pConfig->periods; + int dir = 0; + if (((mal_snd_pcm_hw_params_set_periods_near_proc)pContext->alsa.snd_pcm_hw_params_set_periods_near)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, &periods, &dir) < 0) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed.", MAL_FORMAT_NOT_SUPPORTED); + } + pDevice->periods = periods; + + // Buffer Size + snd_pcm_uframes_t actualBufferSize = pDevice->bufferSizeInFrames; + if (((mal_snd_pcm_hw_params_set_buffer_size_near_proc)pContext->alsa.snd_pcm_hw_params_set_buffer_size_near)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, &actualBufferSize) < 0) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed.", MAL_FORMAT_NOT_SUPPORTED); + } + pDevice->bufferSizeInFrames = actualBufferSize; + + + // Apply hardware parameters. + if (((mal_snd_pcm_hw_params_proc)pContext->alsa.snd_pcm_hw_params)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams) < 0) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed.", MAL_ALSA_FAILED_TO_SET_HW_PARAMS); + } + + + + + // Software parameters. + snd_pcm_sw_params_t* pSWParams = (snd_pcm_sw_params_t*)alloca(((mal_snd_pcm_sw_params_sizeof_proc)pContext->alsa.snd_pcm_sw_params_sizeof)()); + mal_zero_memory(pSWParams, ((mal_snd_pcm_sw_params_sizeof_proc)pContext->alsa.snd_pcm_sw_params_sizeof)()); + + if (((mal_snd_pcm_sw_params_current_proc)pContext->alsa.snd_pcm_sw_params_current)((snd_pcm_t*)pDevice->alsa.pPCM, pSWParams) != 0) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed.", MAL_ALSA_FAILED_TO_SET_SW_PARAMS); + } + + if (((mal_snd_pcm_sw_params_set_avail_min_proc)pContext->alsa.snd_pcm_sw_params_set_avail_min)((snd_pcm_t*)pDevice->alsa.pPCM, pSWParams, (pDevice->sampleRate/1000) * 1) != 0) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] snd_pcm_sw_params_set_avail_min() failed.", MAL_FORMAT_NOT_SUPPORTED); + } + + if (type == mal_device_type_playback && !pDevice->alsa.isUsingMMap) { // Only playback devices in writei/readi mode need a start threshold. + if (((mal_snd_pcm_sw_params_set_start_threshold_proc)pContext->alsa.snd_pcm_sw_params_set_start_threshold)((snd_pcm_t*)pDevice->alsa.pPCM, pSWParams, (pDevice->sampleRate/1000) * 1) != 0) { //mal_prev_power_of_2(pDevice->bufferSizeInFrames/pDevice->periods) + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.", MAL_ALSA_FAILED_TO_SET_SW_PARAMS); + } + } + + if (((mal_snd_pcm_sw_params_proc)pContext->alsa.snd_pcm_sw_params)((snd_pcm_t*)pDevice->alsa.pPCM, pSWParams) != 0) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed.", MAL_ALSA_FAILED_TO_SET_SW_PARAMS); + } + + + + // If we're _not_ using mmap we need to use an intermediary buffer. + if (!pDevice->alsa.isUsingMMap) { + pDevice->alsa.pIntermediaryBuffer = mal_malloc(pDevice->bufferSizeInFrames * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format)); + if (pDevice->alsa.pIntermediaryBuffer == NULL) { + mal_device_uninit__alsa(pDevice); + return mal_post_error(pDevice, "[ALSA] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY); + } + } + + + + // Grab the internal channel map. For now we're not going to bother trying to change the channel map and + // instead just do it ourselves. + snd_pcm_chmap_t* pChmap = ((mal_snd_pcm_get_chmap_proc)pContext->alsa.snd_pcm_get_chmap)((snd_pcm_t*)pDevice->alsa.pPCM); + if (pChmap != NULL) { + // There are cases where the returned channel map can have a different channel count than was returned by snd_pcm_hw_params_set_channels_near(). + if (pChmap->channels >= pDevice->internalChannels) { + // Drop excess channels. + for (mal_uint32 iChannel = 0; iChannel < pDevice->internalChannels; ++iChannel) { + pDevice->internalChannelMap[iChannel] = mal_convert_alsa_channel_position_to_mal_channel(pChmap->pos[iChannel]); + } + } else { + // Excess channels use defaults. Do an initial fill with defaults, overwrite the first pChmap->channels, validate to ensure there are no duplicate + // channels. If validation fails, fall back to defaults. + + // Fill with defaults. + mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); + + // Overwrite first pChmap->channels channels. + for (mal_uint32 iChannel = 0; iChannel < pChmap->channels; ++iChannel) { + pDevice->internalChannelMap[iChannel] = mal_convert_alsa_channel_position_to_mal_channel(pChmap->pos[iChannel]); + } + + // Validate. + mal_bool32 isValid = MAL_TRUE; + for (mal_uint32 i = 0; i < pDevice->internalChannels && isValid; ++i) { + for (mal_uint32 j = i+1; j < pDevice->internalChannels; ++j) { + if (pDevice->internalChannelMap[i] == pDevice->internalChannelMap[j]) { + isValid = MAL_FALSE; + break; + } + } + } + + // If our channel map is invalid, fall back to defaults. + if (!isValid) { + mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); + } + } + + free(pChmap); + pChmap = NULL; + } else { + // Could not retrieve the channel map. Fall back to a hard-coded assumption. + mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); + } + + return MAL_SUCCESS; +} + + +static mal_result mal_device__start_backend__alsa(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + // Prepare the device first... + if (((mal_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((snd_pcm_t*)pDevice->alsa.pPCM) < 0) { + return mal_post_error(pDevice, "[ALSA] Failed to prepare device.", MAL_ALSA_FAILED_TO_PREPARE_DEVICE); + } + + // ... and then grab an initial chunk from the client. After this is done, the device should + // automatically start playing, since that's how we configured the software parameters. + if (pDevice->type == mal_device_type_playback) { + if (!mal_device_write__alsa(pDevice)) { + return mal_post_error(pDevice, "[ALSA] Failed to write initial chunk of data to the playback device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); + } + + // mmap mode requires an explicit start. + if (pDevice->alsa.isUsingMMap) { + if (((mal_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((snd_pcm_t*)pDevice->alsa.pPCM) < 0) { + return mal_post_error(pDevice, "[ALSA] Failed to start capture device.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + } + } else { + if (((mal_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((snd_pcm_t*)pDevice->alsa.pPCM) < 0) { + return mal_post_error(pDevice, "[ALSA] Failed to start capture device.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__stop_backend__alsa(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + ((mal_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((snd_pcm_t*)pDevice->alsa.pPCM); + return MAL_SUCCESS; +} + +static mal_result mal_device__break_main_loop__alsa(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + // Fallback. We just set a variable to tell the worker thread to terminate after handling the + // next bunch of frames. This is a slow way of handling this. + pDevice->alsa.breakFromMainLoop = MAL_TRUE; + return MAL_SUCCESS; +} + +static mal_result mal_device__main_loop__alsa(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + pDevice->alsa.breakFromMainLoop = MAL_FALSE; + if (pDevice->type == mal_device_type_playback) { + // Playback. Read from client, write to device. + while (!pDevice->alsa.breakFromMainLoop && mal_device_write__alsa(pDevice)) { + } + } else { + // Capture. Read from device, write to client. + while (!pDevice->alsa.breakFromMainLoop && mal_device_read__alsa(pDevice)) { + } + } + + return MAL_SUCCESS; +} +#endif // ALSA + + +/////////////////////////////////////////////////////////////////////////////// +// +// OSS Backend +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_ENABLE_OSS +#include +#include +#include +#include + +int mal_open_temp_device__oss() +{ + // The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. + int fd = open("/dev/mixer", O_RDONLY, 0); + if (fd >= 0) { + return fd; + } + + return -1; +} + +mal_result mal_context_init__oss(mal_context* pContext) +{ + mal_assert(pContext != NULL); + + // Try opening a temporary device first so we can get version information. This is closed at the end. + int fd = mal_open_temp_device__oss(); + if (fd == -1) { + return mal_context_post_error(pContext, NULL, "[OSS] Failed to open temporary device for retrieving system properties.", MAL_NO_BACKEND); // Looks liks OSS isn't installed, or there are no available devices. + } + + // Grab the OSS version. + int ossVersion = 0; + int result = ioctl(fd, OSS_GETVERSION, &ossVersion); + if (result == -1) { + close(fd); + return mal_context_post_error(pContext, NULL, "[OSS] Failed to retrieve OSS version.", MAL_NO_BACKEND); + } + + pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16); + pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8); + + close(fd); + return MAL_SUCCESS; +} + +mal_result mal_context_uninit__oss(mal_context* pContext) +{ + mal_assert(pContext != NULL); + mal_assert(pContext->backend == mal_backend_oss); + + (void)pContext; + return MAL_SUCCESS; +} + +static mal_result mal_enumerate_devices__oss(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) +{ + (void)pContext; + + mal_uint32 infoSize = *pCount; + *pCount = 0; + + // The object returned by SNDCTL_SYSINFO will have the information we're after. + int fd = mal_open_temp_device__oss(); + if (fd == -1) { + return mal_context_post_error(pContext, NULL, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MAL_NO_BACKEND); + } + + oss_sysinfo si; + int result = ioctl(fd, SNDCTL_SYSINFO, &si); + if (result != -1) { + for (int iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) { + oss_audioinfo ai; + ai.dev = iAudioDevice; + result = ioctl(fd, SNDCTL_AUDIOINFO, &ai); + if (result != -1) { + mal_bool32 includeThisDevice = MAL_FALSE; + if (type == mal_device_type_playback && (ai.caps & PCM_CAP_OUTPUT) != 0) { + includeThisDevice = MAL_TRUE; + } else if (type == mal_device_type_capture && (ai.caps & PCM_CAP_INPUT) != 0) { + includeThisDevice = MAL_TRUE; + } + + if (includeThisDevice) { + if (ai.devnode[0] != '\0') { // <-- Can be blank, according to documentation. + if (pInfo != NULL) { + if (infoSize > 0) { + mal_strncpy_s(pInfo->id.oss, sizeof(pInfo->id.oss), ai.devnode, (size_t)-1); + + // The human readable device name should be in the "ai.handle" variable, but it can + // sometimes be empty in which case we just fall back to "ai.name" which is less user + // friendly, but usually has a value. + if (ai.handle[0] != '\0') { + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), ai.handle, (size_t)-1); + } else { + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), ai.name, (size_t)-1); + } + + pInfo += 1; + infoSize -= 1; + *pCount += 1; + } + } else { + *pCount += 1; + } + } + } + } + } + } else { + // Failed to retrieve the system information. Just return a default device for both playback and capture. + if (pInfo != NULL) { + if (infoSize > 0) { + mal_strncpy_s(pInfo[0].id.oss, sizeof(pInfo[0].id.oss), "/dev/dsp", (size_t)-1); + if (type == mal_device_type_playback) { + mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Playback Device", (size_t)-1); + } else { + mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Capture Device", (size_t)-1); + } + + *pCount = 1; + } + } else { + *pCount = 1; + } + } + + close(fd); + return MAL_SUCCESS; +} + +static void mal_device_uninit__oss(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + close(pDevice->oss.fd); + mal_free(pDevice->oss.pIntermediaryBuffer); +} + +static mal_result mal_device_init__oss(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) +{ + (void)pContext; + + mal_assert(pDevice != NULL); + mal_zero_object(&pDevice->oss); + + char deviceName[64]; + if (pDeviceID != NULL) { + mal_strncpy_s(deviceName, sizeof(deviceName), pDeviceID->oss, (size_t)-1); + } else { + mal_strncpy_s(deviceName, sizeof(deviceName), "/dev/dsp", (size_t)-1); + } + + pDevice->oss.fd = open(deviceName, (type == mal_device_type_playback) ? O_WRONLY : O_RDONLY, 0); + if (pDevice->oss.fd == -1) { + return mal_post_error(pDevice, "[OSS] Failed to open device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + // The OSS documantation is very clear about the order we should be initializing the device's properties: + // 1) Format + // 2) Channels + // 3) Sample rate. + + // Format. + int ossFormat = AFMT_U8; + switch (pDevice->format) { + case mal_format_s16: ossFormat = AFMT_S16_LE; break; + case mal_format_s24: ossFormat = AFMT_S32_LE; break; + case mal_format_s32: ossFormat = AFMT_S32_LE; break; + case mal_format_f32: ossFormat = AFMT_S32_LE; break; + case mal_format_u8: + default: ossFormat = AFMT_U8; break; + } + int result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SETFMT, &ossFormat); + if (result == -1) { + close(pDevice->oss.fd); + return mal_post_error(pDevice, "[OSS] Failed to set format.", MAL_FORMAT_NOT_SUPPORTED); + } + + switch (ossFormat) { + case AFMT_U8: pDevice->internalFormat = mal_format_u8; break; + case AFMT_S16_LE: pDevice->internalFormat = mal_format_s16; break; + case AFMT_S32_LE: pDevice->internalFormat = mal_format_s32; break; + default: mal_post_error(pDevice, "[OSS] The device's internal format is not supported by mini_al.", MAL_FORMAT_NOT_SUPPORTED); + } + + + // Channels. + int ossChannels = (int)pConfig->channels; + result = ioctl(pDevice->oss.fd, SNDCTL_DSP_CHANNELS, &ossChannels); + if (result == -1) { + close(pDevice->oss.fd); + return mal_post_error(pDevice, "[OSS] Failed to set channel count.", MAL_FORMAT_NOT_SUPPORTED); + } + + pDevice->internalChannels = ossChannels; + + + // Sample rate. + int ossSampleRate = (int)pConfig->sampleRate; + result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SPEED, &ossSampleRate); + if (result == -1) { + close(pDevice->oss.fd); + return mal_post_error(pDevice, "[OSS] Failed to set sample rate.", MAL_FORMAT_NOT_SUPPORTED); + } + + pDevice->sampleRate = ossSampleRate; + + + + // The documentation says that the fragment settings should be set as soon as possible, but I'm not sure if + // it should be done before or after format/channels/rate. + // + // OSS wants the fragment size in bytes and a power of 2. When setting, we specify the power, not the actual + // value. + mal_uint32 fragmentSizeInBytes = mal_round_to_power_of_2(pDevice->bufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); + if (fragmentSizeInBytes < 16) { + fragmentSizeInBytes = 16; + } + + mal_uint32 ossFragmentSizePower = 4; + fragmentSizeInBytes >>= 4; + while (fragmentSizeInBytes >>= 1) { + ossFragmentSizePower += 1; + } + + int ossFragment = (int)((pDevice->periods << 16) | ossFragmentSizePower); + result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SETFRAGMENT, &ossFragment); + if (result == -1) { + close(pDevice->oss.fd); + return mal_post_error(pDevice, "[OSS] Failed to set fragment size and period count.", MAL_FORMAT_NOT_SUPPORTED); + } + + int actualFragmentSizeInBytes = 1 << (ossFragment & 0xFFFF); + pDevice->oss.fragmentSizeInFrames = actualFragmentSizeInBytes / mal_get_sample_size_in_bytes(pDevice->internalFormat) / pDevice->internalChannels; + + pDevice->periods = (mal_uint32)(ossFragment >> 16); + pDevice->bufferSizeInFrames = (mal_uint32)(pDevice->oss.fragmentSizeInFrames * pDevice->periods); + + + // Set the internal channel map. Not sure if this can be queried. For now just using our default assumptions. + mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); + + + // When not using MMAP mode, we need to use an intermediary buffer for the client <-> device transfer. We do + // everything by the size of a fragment. + pDevice->oss.pIntermediaryBuffer = mal_malloc(fragmentSizeInBytes); + if (pDevice->oss.pIntermediaryBuffer == NULL) { + close(pDevice->oss.fd); + return mal_post_error(pDevice, "[OSS] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY); + } + + return MAL_SUCCESS; +} + + +static mal_result mal_device__start_backend__oss(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + // The device is started by the next calls to read() and write(). For playback it's simple - just read + // data from the client, then write it to the device with write() which will in turn start the device. + // For capture it's a bit less intuitive - we do nothing (it'll be started automatically by the first + // call to read(). + if (pDevice->type == mal_device_type_playback) { + // Playback. + mal_device__read_frames_from_client(pDevice, pDevice->oss.fragmentSizeInFrames, pDevice->oss.pIntermediaryBuffer); + + int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); + if (bytesWritten == -1) { + return mal_post_error(pDevice, "[OSS] Failed to send initial chunk of data to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); + } + } else { + // Capture. Do nothing. + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__stop_backend__oss(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + // We want to use SNDCTL_DSP_HALT. From the documentation: + // + // In multithreaded applications SNDCTL_DSP_HALT (SNDCTL_DSP_RESET) must only be called by the thread + // that actually reads/writes the audio device. It must not be called by some master thread to kill the + // audio thread. The audio thread will not stop or get any kind of notification that the device was + // stopped by the master thread. The device gets stopped but the next read or write call will silently + // restart the device. + // + // This is actually safe in our case, because this function is only ever called from within our worker + // thread anyway. Just keep this in mind, though... + + int result = ioctl(pDevice->oss.fd, SNDCTL_DSP_HALT, 0); + if (result == -1) { + return mal_post_error(pDevice, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__break_main_loop__oss(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + pDevice->oss.breakFromMainLoop = MAL_TRUE; + return MAL_SUCCESS; +} + +static mal_result mal_device__main_loop__oss(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + pDevice->oss.breakFromMainLoop = MAL_FALSE; + while (!pDevice->oss.breakFromMainLoop) { + // Break from the main loop if the device isn't started anymore. Likely what's happened is the application + // has requested that the device be stopped. + if (!mal_device_is_started(pDevice)) { + break; + } + + if (pDevice->type == mal_device_type_playback) { + // Playback. + mal_device__read_frames_from_client(pDevice, pDevice->oss.fragmentSizeInFrames, pDevice->oss.pIntermediaryBuffer); + + int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); + if (bytesWritten < 0) { + return mal_post_error(pDevice, "[OSS] Failed to send data from the client to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); + } + } else { + // Capture. + int bytesRead = read(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * mal_get_sample_size_in_bytes(pDevice->internalFormat)); + if (bytesRead < 0) { + return mal_post_error(pDevice, "[OSS] Failed to read data from the device to be sent to the client.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE); + } + + mal_uint32 framesRead = (mal_uint32)bytesRead / pDevice->internalChannels / mal_get_sample_size_in_bytes(pDevice->internalFormat); + mal_device__send_frames_to_client(pDevice, framesRead, pDevice->oss.pIntermediaryBuffer); + } + } + + return MAL_SUCCESS; +} +#endif // OSS + + +/////////////////////////////////////////////////////////////////////////////// +// +// OpenSL|ES Backend +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_ENABLE_OPENSL +#include +#ifdef MAL_ANDROID +#include +#endif + +// Converts an individual OpenSL-style channel identifier (SL_SPEAKER_FRONT_LEFT, etc.) to mini_al. +static mal_uint8 mal_channel_id_to_mal__opensl(SLuint32 id) +{ + switch (id) + { + case SL_SPEAKER_FRONT_LEFT: return MAL_CHANNEL_FRONT_LEFT; + case SL_SPEAKER_FRONT_RIGHT: return MAL_CHANNEL_FRONT_RIGHT; + case SL_SPEAKER_FRONT_CENTER: return MAL_CHANNEL_FRONT_CENTER; + case SL_SPEAKER_LOW_FREQUENCY: return MAL_CHANNEL_LFE; + case SL_SPEAKER_BACK_LEFT: return MAL_CHANNEL_BACK_LEFT; + case SL_SPEAKER_BACK_RIGHT: return MAL_CHANNEL_BACK_RIGHT; + case SL_SPEAKER_FRONT_LEFT_OF_CENTER: return MAL_CHANNEL_FRONT_LEFT_CENTER; + case SL_SPEAKER_FRONT_RIGHT_OF_CENTER: return MAL_CHANNEL_FRONT_RIGHT_CENTER; + case SL_SPEAKER_BACK_CENTER: return MAL_CHANNEL_BACK_CENTER; + case SL_SPEAKER_SIDE_LEFT: return MAL_CHANNEL_SIDE_LEFT; + case SL_SPEAKER_SIDE_RIGHT: return MAL_CHANNEL_SIDE_RIGHT; + case SL_SPEAKER_TOP_CENTER: return MAL_CHANNEL_TOP_CENTER; + case SL_SPEAKER_TOP_FRONT_LEFT: return MAL_CHANNEL_TOP_FRONT_LEFT; + case SL_SPEAKER_TOP_FRONT_CENTER: return MAL_CHANNEL_TOP_FRONT_CENTER; + case SL_SPEAKER_TOP_FRONT_RIGHT: return MAL_CHANNEL_TOP_FRONT_RIGHT; + case SL_SPEAKER_TOP_BACK_LEFT: return MAL_CHANNEL_TOP_BACK_LEFT; + case SL_SPEAKER_TOP_BACK_CENTER: return MAL_CHANNEL_TOP_BACK_CENTER; + case SL_SPEAKER_TOP_BACK_RIGHT: return MAL_CHANNEL_TOP_BACK_RIGHT; + default: return 0; + } +} + +// Converts an individual mini_al channel identifier (MAL_CHANNEL_FRONT_LEFT, etc.) to OpenSL-style. +static SLuint32 mal_channel_id_to_opensl(mal_uint8 id) +{ + switch (id) + { + case MAL_CHANNEL_FRONT_LEFT: return SL_SPEAKER_FRONT_LEFT; + case MAL_CHANNEL_FRONT_RIGHT: return SL_SPEAKER_FRONT_RIGHT; + case MAL_CHANNEL_FRONT_CENTER: return SL_SPEAKER_FRONT_CENTER; + case MAL_CHANNEL_LFE: return SL_SPEAKER_LOW_FREQUENCY; + case MAL_CHANNEL_BACK_LEFT: return SL_SPEAKER_BACK_LEFT; + case MAL_CHANNEL_BACK_RIGHT: return SL_SPEAKER_BACK_RIGHT; + case MAL_CHANNEL_FRONT_LEFT_CENTER: return SL_SPEAKER_FRONT_LEFT_OF_CENTER; + case MAL_CHANNEL_FRONT_RIGHT_CENTER: return SL_SPEAKER_FRONT_RIGHT_OF_CENTER; + case MAL_CHANNEL_BACK_CENTER: return SL_SPEAKER_BACK_CENTER; + case MAL_CHANNEL_SIDE_LEFT: return SL_SPEAKER_SIDE_LEFT; + case MAL_CHANNEL_SIDE_RIGHT: return SL_SPEAKER_SIDE_RIGHT; + case MAL_CHANNEL_TOP_CENTER: return SL_SPEAKER_TOP_CENTER; + case MAL_CHANNEL_TOP_FRONT_LEFT: return SL_SPEAKER_TOP_FRONT_LEFT; + case MAL_CHANNEL_TOP_FRONT_CENTER: return SL_SPEAKER_TOP_FRONT_CENTER; + case MAL_CHANNEL_TOP_FRONT_RIGHT: return SL_SPEAKER_TOP_FRONT_RIGHT; + case MAL_CHANNEL_TOP_BACK_LEFT: return SL_SPEAKER_TOP_BACK_LEFT; + case MAL_CHANNEL_TOP_BACK_CENTER: return SL_SPEAKER_TOP_BACK_CENTER; + case MAL_CHANNEL_TOP_BACK_RIGHT: return SL_SPEAKER_TOP_BACK_RIGHT; + default: return 0; + } +} + +// Converts a channel mapping to an OpenSL-style channel mask. +static SLuint32 mal_channel_map_to_channel_mask__opensl(mal_uint8 channelMap[MAL_MAX_CHANNELS], mal_uint32 channels) +{ + SLuint32 channelMask = 0; + for (mal_uint32 iChannel = 0; iChannel < channels; ++iChannel) { + channelMask |= mal_channel_id_to_opensl(channelMap[iChannel]); + } + + return channelMask; +} + +// Converts an OpenSL-style channel mask to a mini_al channel map. +static void mal_channel_mask_to_channel_map__opensl(SLuint32 channelMask, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) +{ + if (channels == 2 && channelMask == 0) { + channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + } else { + // Just iterate over each bit. + mal_uint32 iChannel = 0; + for (mal_uint32 iBit = 0; iBit < 32; ++iBit) { + SLuint32 bitValue = (channelMask & (1 << iBit)); + if (bitValue != 0) { + // The bit is set. + channelMap[iChannel] = mal_channel_id_to_mal__opensl(bitValue); + iChannel += 1; + } + } + } +} + +SLuint32 mal_round_to_standard_sample_rate__opensl(SLuint32 samplesPerSec) +{ + if (samplesPerSec <= SL_SAMPLINGRATE_8) { + return SL_SAMPLINGRATE_8; + } + if (samplesPerSec <= SL_SAMPLINGRATE_11_025) { + return SL_SAMPLINGRATE_11_025; + } + if (samplesPerSec <= SL_SAMPLINGRATE_12) { + return SL_SAMPLINGRATE_12; + } + if (samplesPerSec <= SL_SAMPLINGRATE_16) { + return SL_SAMPLINGRATE_16; + } + if (samplesPerSec <= SL_SAMPLINGRATE_22_05) { + return SL_SAMPLINGRATE_22_05; + } + if (samplesPerSec <= SL_SAMPLINGRATE_24) { + return SL_SAMPLINGRATE_24; + } + if (samplesPerSec <= SL_SAMPLINGRATE_32) { + return SL_SAMPLINGRATE_32; + } + if (samplesPerSec <= SL_SAMPLINGRATE_44_1) { + return SL_SAMPLINGRATE_44_1; + } + if (samplesPerSec <= SL_SAMPLINGRATE_48) { + return SL_SAMPLINGRATE_48; + } + + // Android doesn't support more than 48000. +#ifndef MAL_ANDROID + if (samplesPerSec <= SL_SAMPLINGRATE_64) { + return SL_SAMPLINGRATE_64; + } + if (samplesPerSec <= SL_SAMPLINGRATE_88_2) { + return SL_SAMPLINGRATE_88_2; + } + if (samplesPerSec <= SL_SAMPLINGRATE_96) { + return SL_SAMPLINGRATE_96; + } + if (samplesPerSec <= SL_SAMPLINGRATE_192) { + return SL_SAMPLINGRATE_192; + } +#endif + + return SL_SAMPLINGRATE_16; +} + +mal_result mal_context_init__opensl(mal_context* pContext) +{ + mal_assert(pContext != NULL); + + (void)pContext; + return MAL_SUCCESS; +} + +mal_result mal_context_uninit__opensl(mal_context* pContext) +{ + mal_assert(pContext != NULL); + mal_assert(pContext->backend == mal_backend_opensl); + + (void)pContext; + return MAL_SUCCESS; +} + +mal_result mal_enumerate_devices__opensl(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) +{ + (void)pContext; + + mal_uint32 infoSize = *pCount; + *pCount = 0; + + SLObjectItf engineObj; + SLresult resultSL = slCreateEngine(&engineObj, 0, NULL, 0, NULL, NULL); + if (resultSL != SL_RESULT_SUCCESS) { + return MAL_NO_BACKEND; + } + + (*engineObj)->Realize(engineObj, SL_BOOLEAN_FALSE); + + // TODO: Test Me. + // + // This is currently untested, so for now we are just returning default devices. +#if 0 + SLuint32 pDeviceIDs[128]; + SLint32 deviceCount = sizeof(pDeviceIDs) / sizeof(pDeviceIDs[0]); + + SLAudioIODeviceCapabilitiesItf deviceCaps; + resultSL = (*engineObj)->GetInterface(engineObj, SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps); + if (resultSL != SL_RESULT_SUCCESS) { + // The interface may not be supported so just report a default device. + (*engineObj)->Destroy(engineObj); + goto return_default_device; + } + + if (type == mal_device_type_playback) { + resultSL = (*deviceCaps)->GetAvailableAudioOutputs(deviceCaps, &deviceCount, pDeviceIDs); + if (resultSL != SL_RESULT_SUCCESS) { + (*engineObj)->Destroy(engineObj); + return MAL_NO_DEVICE; + } + } else { + resultSL = (*deviceCaps)->GetAvailableAudioInputs(deviceCaps, &deviceCount, pDeviceIDs); + if (resultSL != SL_RESULT_SUCCESS) { + (*engineObj)->Destroy(engineObj); + return MAL_NO_DEVICE; + } + } + + for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) { + if (pInfo != NULL) { + if (infoSize > 0) { + mal_zero_object(pInfo); + pInfo->id.opensl = pDeviceIDs[iDevice]; + + mal_bool32 isValidDevice = MAL_TRUE; + if (type == mal_device_type_playback) { + SLAudioOutputDescriptor desc; + resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, pInfo->id.opensl, &desc); + if (resultSL != SL_RESULT_SUCCESS) { + isValidDevice = MAL_FALSE; + } + + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), (const char*)desc.pDeviceName, (size_t)-1); + } else { + SLAudioInputDescriptor desc; + resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, pInfo->id.opensl, &desc); + if (resultSL != SL_RESULT_SUCCESS) { + isValidDevice = MAL_FALSE; + } + + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), (const char*)desc.deviceName, (size_t)-1); + } + + if (isValidDevice) { + pInfo += 1; + infoSize -= 1; + *pCount += 1; + } + } + } else { + *pCount += 1; + } + } + + (*engineObj)->Destroy(engineObj); + return MAL_SUCCESS; +#else + (*engineObj)->Destroy(engineObj); + goto return_default_device; +#endif + +return_default_device: + *pCount = 1; + if (pInfo != NULL) { + if (infoSize > 0) { + if (type == mal_device_type_playback) { + pInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT; + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1); + } else { + pInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT; + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1); + } + } + } + + return MAL_SUCCESS; +} + + +// OpenSL|ES has one-per-application objects :( +static SLObjectItf g_malEngineObjectSL = NULL; +static SLEngineItf g_malEngineSL = NULL; +static mal_uint32 g_malOpenSLInitCounter = 0; + +#define MAL_OPENSL_OBJ(p) (*((SLObjectItf)(p))) +#define MAL_OPENSL_OUTPUTMIX(p) (*((SLOutputMixItf)(p))) +#define MAL_OPENSL_PLAY(p) (*((SLPlayItf)(p))) +#define MAL_OPENSL_RECORD(p) (*((SLRecordItf)(p))) + +#ifdef MAL_ANDROID +#define MAL_OPENSL_BUFFERQUEUE(p) (*((SLAndroidSimpleBufferQueueItf)(p))) +#else +#define MAL_OPENSL_BUFFERQUEUE(p) (*((SLBufferQueueItf)(p))) +#endif + +#ifdef MAL_ANDROID +//static void mal_buffer_queue_callback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, SLuint32 eventFlags, const void* pBuffer, SLuint32 bufferSize, SLuint32 dataUsed, void* pContext) +static void mal_buffer_queue_callback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData) +{ + (void)pBufferQueue; + + // For now, only supporting Android implementations of OpenSL|ES since that's the only one I've + // been able to test with and I currently depend on Android-specific extensions (simple buffer + // queues). +#ifndef MAL_ANDROID + return MAL_NO_BACKEND; +#endif + + mal_device* pDevice = (mal_device*)pUserData; + mal_assert(pDevice != NULL); + + // For now, don't do anything unless the buffer was fully processed. From what I can tell, it looks like + // OpenSL|ES 1.1 improves on buffer queues to the point that we could much more intelligently handle this, + // but unfortunately it looks like Android is only supporting OpenSL|ES 1.0.1 for now :( + if (pDevice->state != MAL_STATE_STARTED) { + return; + } + + size_t periodSizeInBytes = pDevice->opensl.periodSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); + mal_uint8* pBuffer = pDevice->opensl.pBuffer + (pDevice->opensl.currentBufferIndex * periodSizeInBytes); + + if (pDevice->type == mal_device_type_playback) { + if (pDevice->state != MAL_STATE_STARTED) { + return; + } + + mal_device__read_frames_from_client(pDevice, pDevice->opensl.periodSizeInFrames, pBuffer); + + SLresult resultSL = MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, pBuffer, periodSizeInBytes); + if (resultSL != SL_RESULT_SUCCESS) { + return; + } + } else { + mal_device__send_frames_to_client(pDevice, pDevice->opensl.periodSizeInFrames, pBuffer); + + SLresult resultSL = MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, pBuffer, periodSizeInBytes); + if (resultSL != SL_RESULT_SUCCESS) { + return; + } + } + + pDevice->opensl.currentBufferIndex = (pDevice->opensl.currentBufferIndex + 1) % pDevice->periods; +} +#endif + +static void mal_device_uninit__opensl(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + // Uninit device. + if (pDevice->type == mal_device_type_playback) { + if (pDevice->opensl.pAudioPlayerObj) MAL_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioPlayerObj); + if (pDevice->opensl.pOutputMixObj) MAL_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Destroy((SLObjectItf)pDevice->opensl.pOutputMixObj); + } else { + if (pDevice->opensl.pAudioRecorderObj) MAL_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioRecorderObj); + } + + mal_free(pDevice->opensl.pBuffer); + + + // Uninit global data. + if (g_malOpenSLInitCounter > 0) { + if (mal_atomic_decrement_32(&g_malOpenSLInitCounter) == 0) { + (*g_malEngineObjectSL)->Destroy(g_malEngineObjectSL); + } + } +} + +static mal_result mal_device_init__opensl(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) +{ + (void)pContext; + + // For now, only supporting Android implementations of OpenSL|ES since that's the only one I've + // been able to test with and I currently depend on Android-specific extensions (simple buffer + // queues). +#ifndef MAL_ANDROID + return MAL_NO_BACKEND; +#endif + + // Use s32 as the internal format for when floating point is specified. + if (pConfig->format == mal_format_f32) { + pDevice->internalFormat = mal_format_s32; + } + + // Initialize global data first if applicable. + if (mal_atomic_increment_32(&g_malOpenSLInitCounter) == 1) { + SLresult resultSL = slCreateEngine(&g_malEngineObjectSL, 0, NULL, 0, NULL, NULL); + if (resultSL != SL_RESULT_SUCCESS) { + mal_atomic_decrement_32(&g_malOpenSLInitCounter); + return mal_post_error(pDevice, "[OpenSL] slCreateEngine() failed.", MAL_NO_BACKEND); + } + + (*g_malEngineObjectSL)->Realize(g_malEngineObjectSL, SL_BOOLEAN_FALSE); + + resultSL = (*g_malEngineObjectSL)->GetInterface(g_malEngineObjectSL, SL_IID_ENGINE, &g_malEngineSL); + if (resultSL != SL_RESULT_SUCCESS) { + (*g_malEngineObjectSL)->Destroy(g_malEngineObjectSL); + mal_atomic_decrement_32(&g_malOpenSLInitCounter); + return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_ENGINE interface.", MAL_NO_BACKEND); + } + } + + + // Now we can start initializing the device properly. + mal_assert(pDevice != NULL); + mal_zero_object(&pDevice->opensl); + + pDevice->opensl.currentBufferIndex = 0; + pDevice->opensl.periodSizeInFrames = pDevice->bufferSizeInFrames / pConfig->periods; + pDevice->bufferSizeInFrames = pDevice->opensl.periodSizeInFrames * pConfig->periods; + + SLDataLocator_AndroidSimpleBufferQueue queue; + queue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; + queue.numBuffers = pConfig->periods; + + SLDataFormat_PCM* pFormat = NULL; + +#if defined(MAL_ANDROID) && __ANDROID_API__ >= 21 + SLAndroidDataFormat_PCM_EX pcmEx; + if (pDevice->format == mal_format_f32 /*|| pDevice->format == mal_format_f64*/) { + pcmEx.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; + pcmEx.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT; + } else { + pcmEx.formatType = SL_DATAFORMAT_PCM; + } + pFormat = (SLDataFormat_PCM*)&pcmEx; +#else + SLDataFormat_PCM pcm; + pcm.formatType = SL_DATAFORMAT_PCM; + pFormat = &pcm; +#endif + + pFormat->numChannels = pDevice->channels; + pFormat->samplesPerSec = mal_round_to_standard_sample_rate__opensl(pDevice->sampleRate * 1000); // In millihertz. + pFormat->bitsPerSample = mal_get_sample_size_in_bytes(pDevice->format)*8; + pFormat->containerSize = pFormat->bitsPerSample; // Always tightly packed for now. + pFormat->channelMask = mal_channel_map_to_channel_mask__opensl(pConfig->channelMap, pFormat->numChannels); + pFormat->endianness = SL_BYTEORDER_LITTLEENDIAN; + + // Android has a few restrictions on the format as documented here: https://developer.android.com/ndk/guides/audio/opensl-for-android.html + // - Only mono and stereo is supported. + // - Only u8 and s16 formats are supported. + // - Limited to a sample rate of 48000. +#ifdef MAL_ANDROID + if (pFormat->numChannels > 2) { + pFormat->numChannels = 2; + } +#if __ANDROID_API__ >= 21 + if (pFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) { + // It's floating point. + mal_assert(pcmEx.representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT); + if (pFormat->bitsPerSample > 32) { + pFormat->bitsPerSample = 32; + } + } else { + if (pFormat->bitsPerSample > 16) { + pFormat->bitsPerSample = 16; + } + } +#else + if (pFormat->bitsPerSample > 16) { + pFormat->bitsPerSample = 16; + } +#endif + pFormat->containerSize = pFormat->bitsPerSample; // Always tightly packed for now. + + if (pFormat->samplesPerSec > SL_SAMPLINGRATE_48) { + pFormat->samplesPerSec = SL_SAMPLINGRATE_48; + } +#endif + + if (type == mal_device_type_playback) { + SLresult resultSL = (*g_malEngineSL)->CreateOutputMix(g_malEngineSL, (SLObjectItf*)&pDevice->opensl.pOutputMixObj, 0, NULL, NULL); + if (resultSL != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to create output mix.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + if (MAL_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Realize((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_BOOLEAN_FALSE)) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to realize output mix object.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + if (MAL_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->GetInterface((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_IID_OUTPUTMIX, &pDevice->opensl.pOutputMix) != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + // Set the output device. + if (pDeviceID != NULL) { + MAL_OPENSL_OUTPUTMIX(pDevice->opensl.pOutputMix)->ReRoute((SLOutputMixItf)pDevice->opensl.pOutputMix, 1, &pDeviceID->opensl); + } + + SLDataSource source; + source.pLocator = &queue; + source.pFormat = pFormat; + + SLDataLocator_OutputMix outmixLocator; + outmixLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX; + outmixLocator.outputMix = (SLObjectItf)pDevice->opensl.pOutputMixObj; + + SLDataSink sink; + sink.pLocator = &outmixLocator; + sink.pFormat = NULL; + + const SLInterfaceID itfIDs1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; + const SLboolean itfIDsRequired1[] = {SL_BOOLEAN_TRUE}; + resultSL = (*g_malEngineSL)->CreateAudioPlayer(g_malEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); + if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { + // Unsupported format. Fall back to something safer and try again. If this fails, just abort. + pFormat->formatType = SL_DATAFORMAT_PCM; + pFormat->numChannels = 2; + pFormat->samplesPerSec = SL_SAMPLINGRATE_16; + pFormat->bitsPerSample = 16; + pFormat->containerSize = pFormat->bitsPerSample; // Always tightly packed for now. + pFormat->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; + resultSL = (*g_malEngineSL)->CreateAudioPlayer(g_malEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); + } + + if (resultSL != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to create audio player.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + + if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Realize((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_BOOLEAN_FALSE) != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to realize audio player.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_IID_PLAY, &pDevice->opensl.pAudioPlayer) != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueue) != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + if (MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, mal_buffer_queue_callback__opensl_android, pDevice) != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to register buffer queue callback.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + } else { + SLDataLocator_IODevice locatorDevice; + locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE; + locatorDevice.deviceType = SL_IODEVICE_AUDIOINPUT; + locatorDevice.deviceID = (pDeviceID == NULL) ? SL_DEFAULTDEVICEID_AUDIOINPUT : pDeviceID->opensl; + locatorDevice.device = NULL; + + SLDataSource source; + source.pLocator = &locatorDevice; + source.pFormat = NULL; + + SLDataSink sink; + sink.pLocator = &queue; + sink.pFormat = pFormat; + + const SLInterfaceID itfIDs1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; + const SLboolean itfIDsRequired1[] = {SL_BOOLEAN_TRUE}; + SLresult resultSL = (*g_malEngineSL)->CreateAudioRecorder(g_malEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); + if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { + // Unsupported format. Fall back to something safer and try again. If this fails, just abort. + pFormat->formatType = SL_DATAFORMAT_PCM; + pFormat->numChannels = 1; + pFormat->samplesPerSec = SL_SAMPLINGRATE_16; + pFormat->bitsPerSample = 16; + pFormat->containerSize = pFormat->bitsPerSample; // Always tightly packed for now. + pFormat->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; + resultSL = (*g_malEngineSL)->CreateAudioRecorder(g_malEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); + } + + if (resultSL != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to create audio recorder.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Realize((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_BOOLEAN_FALSE) != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to realize audio recorder.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_IID_RECORD, &pDevice->opensl.pAudioRecorder) != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueue) != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + + if (MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, mal_buffer_queue_callback__opensl_android, pDevice) != SL_RESULT_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to register buffer queue callback.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + } + + + // The internal format is determined by the pFormat object. + mal_bool32 isFloatingPoint = MAL_FALSE; +#if defined(MAL_ANDROID) && __ANDROID_API__ >= 21 + if (pFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) { + mal_assert(pcmEx.representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT); + isFloatingPoint = MAL_TRUE; + } +#endif + if (isFloatingPoint) { + if (pFormat->bitsPerSample == 32) { + pDevice->internalFormat = mal_format_f32; + } +#if 0 + if (pFormat->bitsPerSample == 64) { + pDevice->internalFormat = mal_format_f64; + } +#endif + } else { + if (pFormat->bitsPerSample == 8) { + pDevice->internalFormat = mal_format_u8; + } else if (pFormat->bitsPerSample == 16) { + pDevice->internalFormat = mal_format_s16; + } else if (pFormat->bitsPerSample == 24) { + pDevice->internalFormat = mal_format_s24; + } else if (pFormat->bitsPerSample == 32) { + pDevice->internalFormat = mal_format_s32; + } + } + + pDevice->internalChannels = pFormat->numChannels; + pDevice->internalSampleRate = pFormat->samplesPerSec / 1000; + mal_channel_mask_to_channel_map__opensl(pFormat->channelMask, pDevice->internalChannels, pDevice->internalChannelMap); + + + size_t bufferSizeInBytes = pDevice->bufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); + pDevice->opensl.pBuffer = (mal_uint8*)mal_malloc(bufferSizeInBytes); + if (pDevice->opensl.pBuffer == NULL) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, "[OpenSL] Failed to allocate memory for data buffer.", MAL_OUT_OF_MEMORY); + } + + mal_zero_memory(pDevice->opensl.pBuffer, bufferSizeInBytes); + + return MAL_SUCCESS; +} + +static mal_result mal_device__start_backend__opensl(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->type == mal_device_type_playback) { + SLresult resultSL = MAL_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_PLAYING); + if (resultSL != SL_RESULT_SUCCESS) { + return mal_post_error(pDevice, "[OpenSL] Failed to start internal playback device.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + + // We need to enqueue a buffer for each period. + mal_device__read_frames_from_client(pDevice, pDevice->bufferSizeInFrames, pDevice->opensl.pBuffer); + + size_t periodSizeInBytes = pDevice->opensl.periodSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); + for (mal_uint32 iPeriod = 0; iPeriod < pDevice->periods; ++iPeriod) { + resultSL = MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, pDevice->opensl.pBuffer + (periodSizeInBytes * iPeriod), periodSizeInBytes); + if (resultSL != SL_RESULT_SUCCESS) { + MAL_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED); + return mal_post_error(pDevice, "[OpenSL] Failed to enqueue buffer for playback device.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + } + } else { + SLresult resultSL = MAL_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_RECORDING); + if (resultSL != SL_RESULT_SUCCESS) { + return mal_post_error(pDevice, "[OpenSL] Failed to start internal capture device.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + + size_t periodSizeInBytes = pDevice->opensl.periodSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); + for (mal_uint32 iPeriod = 0; iPeriod < pDevice->periods; ++iPeriod) { + resultSL = MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, pDevice->opensl.pBuffer + (periodSizeInBytes * iPeriod), periodSizeInBytes); + if (resultSL != SL_RESULT_SUCCESS) { + MAL_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED); + return mal_post_error(pDevice, "[OpenSL] Failed to enqueue buffer for capture device.", MAL_FAILED_TO_START_BACKEND_DEVICE); + } + } + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__stop_backend__opensl(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->type == mal_device_type_playback) { + SLresult resultSL = MAL_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED); + if (resultSL != SL_RESULT_SUCCESS) { + return mal_post_error(pDevice, "[OpenSL] Failed to stop internal playback device.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); + } + } else { + SLresult resultSL = MAL_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED); + if (resultSL != SL_RESULT_SUCCESS) { + return mal_post_error(pDevice, "[OpenSL] Failed to stop internal capture device.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); + } + } + + // Make sure any queued buffers are cleared. + MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue); + + // Make sure the client is aware that the device has stopped. There may be an OpenSL|ES callback for this, but I haven't found it. + mal_device__set_state(pDevice, MAL_STATE_STOPPED); + if (pDevice->onStop) { + pDevice->onStop(pDevice); + } + + return MAL_SUCCESS; +} +#endif // OpenSL|ES + +/////////////////////////////////////////////////////////////////////////////// +// +// OpenAL Backend +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_ENABLE_OPENAL +#ifdef MAL_WIN32 +#define MAL_AL_APIENTRY __cdecl +#else +#define MAL_AL_APIENTRY +#endif + +typedef struct mal_ALCdevice_struct mal_ALCdevice; +typedef struct mal_ALCcontext_struct mal_ALCcontext; +typedef char mal_ALCboolean; +typedef char mal_ALCchar; +typedef signed char mal_ALCbyte; +typedef unsigned char mal_ALCubyte; +typedef short mal_ALCshort; +typedef unsigned short mal_ALCushort; +typedef int mal_ALCint; +typedef unsigned int mal_ALCuint; +typedef int mal_ALCsizei; +typedef int mal_ALCenum; +typedef float mal_ALCfloat; +typedef double mal_ALCdouble; +typedef void mal_ALCvoid; + +typedef mal_ALCboolean mal_ALboolean; +typedef mal_ALCchar mal_ALchar; +typedef mal_ALCbyte mal_ALbyte; +typedef mal_ALCubyte mal_ALubyte; +typedef mal_ALCshort mal_ALshort; +typedef mal_ALCushort mal_ALushort; +typedef mal_ALCint mal_ALint; +typedef mal_ALCuint mal_ALuint; +typedef mal_ALCsizei mal_ALsizei; +typedef mal_ALCenum mal_ALenum; +typedef mal_ALCfloat mal_ALfloat; +typedef mal_ALCdouble mal_ALdouble; +typedef mal_ALCvoid mal_ALvoid; + +#define MAL_ALC_DEVICE_SPECIFIER 0x1005 +#define MAL_ALC_CAPTURE_DEVICE_SPECIFIER 0x310 +#define MAL_ALC_CAPTURE_SAMPLES 0x312 + +#define MAL_AL_SOURCE_STATE 0x1010 +#define MAL_AL_INITIAL 0x1011 +#define MAL_AL_PLAYING 0x1012 +#define MAL_AL_PAUSED 0x1013 +#define MAL_AL_STOPPED 0x1014 +#define MAL_AL_BUFFERS_PROCESSED 0x1016 + +#define MAL_AL_FORMAT_MONO8 0x1100 +#define MAL_AL_FORMAT_MONO16 0x1101 +#define MAL_AL_FORMAT_STEREO8 0x1102 +#define MAL_AL_FORMAT_STEREO16 0x1103 +#define MAL_AL_FORMAT_MONO_FLOAT32 0x10010 +#define MAL_AL_FORMAT_STEREO_FLOAT32 0x10011 +#define MAL_AL_FORMAT_51CHN16 0x120B +#define MAL_AL_FORMAT_51CHN32 0x120C +#define MAL_AL_FORMAT_51CHN8 0x120A +#define MAL_AL_FORMAT_61CHN16 0x120E +#define MAL_AL_FORMAT_61CHN32 0x120F +#define MAL_AL_FORMAT_61CHN8 0x120D +#define MAL_AL_FORMAT_71CHN16 0x1211 +#define MAL_AL_FORMAT_71CHN32 0x1212 +#define MAL_AL_FORMAT_71CHN8 0x1210 +#define MAL_AL_FORMAT_QUAD16 0x1205 +#define MAL_AL_FORMAT_QUAD32 0x1206 +#define MAL_AL_FORMAT_QUAD8 0x1204 +#define MAL_AL_FORMAT_REAR16 0x1208 +#define MAL_AL_FORMAT_REAR32 0x1209 +#define MAL_AL_FORMAT_REAR8 0x1207 + +typedef mal_ALCcontext* (MAL_AL_APIENTRY * MAL_LPALCCREATECONTEXT) (mal_ALCdevice *device, const mal_ALCint *attrlist); +typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCMAKECONTEXTCURRENT) (mal_ALCcontext *context); +typedef void (MAL_AL_APIENTRY * MAL_LPALCPROCESSCONTEXT) (mal_ALCcontext *context); +typedef void (MAL_AL_APIENTRY * MAL_LPALCSUSPENDCONTEXT) (mal_ALCcontext *context); +typedef void (MAL_AL_APIENTRY * MAL_LPALCDESTROYCONTEXT) (mal_ALCcontext *context); +typedef mal_ALCcontext* (MAL_AL_APIENTRY * MAL_LPALCGETCURRENTCONTEXT) (void); +typedef mal_ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCGETCONTEXTSDEVICE) (mal_ALCcontext *context); +typedef mal_ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCOPENDEVICE) (const mal_ALCchar *devicename); +typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCLOSEDEVICE) (mal_ALCdevice *device); +typedef mal_ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETERROR) (mal_ALCdevice *device); +typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCISEXTENSIONPRESENT) (mal_ALCdevice *device, const mal_ALCchar *extname); +typedef void* (MAL_AL_APIENTRY * MAL_LPALCGETPROCADDRESS) (mal_ALCdevice *device, const mal_ALCchar *funcname); +typedef mal_ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETENUMVALUE) (mal_ALCdevice *device, const mal_ALCchar *enumname); +typedef const mal_ALCchar* (MAL_AL_APIENTRY * MAL_LPALCGETSTRING) (mal_ALCdevice *device, mal_ALCenum param); +typedef void (MAL_AL_APIENTRY * MAL_LPALCGETINTEGERV) (mal_ALCdevice *device, mal_ALCenum param, mal_ALCsizei size, mal_ALCint *values); +typedef mal_ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCCAPTUREOPENDEVICE) (const mal_ALCchar *devicename, mal_ALCuint frequency, mal_ALCenum format, mal_ALCsizei buffersize); +typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCAPTURECLOSEDEVICE) (mal_ALCdevice *device); +typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTART) (mal_ALCdevice *device); +typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTOP) (mal_ALCdevice *device); +typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESAMPLES) (mal_ALCdevice *device, mal_ALCvoid *buffer, mal_ALCsizei samples); + +typedef void (MAL_AL_APIENTRY * MAL_LPALENABLE) (mal_ALenum capability); +typedef void (MAL_AL_APIENTRY * MAL_LPALDISABLE) (mal_ALenum capability); +typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISENABLED) (mal_ALenum capability); +typedef const mal_ALchar* (MAL_AL_APIENTRY * MAL_LPALGETSTRING) (mal_ALenum param); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETBOOLEANV) (mal_ALenum param, mal_ALboolean *values); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETINTEGERV) (mal_ALenum param, mal_ALint *values); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETFLOATV) (mal_ALenum param, mal_ALfloat *values); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETDOUBLEV) (mal_ALenum param, mal_ALdouble *values); +typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALGETBOOLEAN) (mal_ALenum param); +typedef mal_ALint (MAL_AL_APIENTRY * MAL_LPALGETINTEGER) (mal_ALenum param); +typedef mal_ALfloat (MAL_AL_APIENTRY * MAL_LPALGETFLOAT) (mal_ALenum param); +typedef mal_ALdouble (MAL_AL_APIENTRY * MAL_LPALGETDOUBLE) (mal_ALenum param); +typedef mal_ALenum (MAL_AL_APIENTRY * MAL_LPALGETERROR) (void); +typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISEXTENSIONPRESENT) (const mal_ALchar *extname); +typedef void* (MAL_AL_APIENTRY * MAL_LPALGETPROCADDRESS) (const mal_ALchar *fname); +typedef mal_ALenum (MAL_AL_APIENTRY * MAL_LPALGETENUMVALUE) (const mal_ALchar *ename); +typedef void (MAL_AL_APIENTRY * MAL_LPALGENSOURCES) (mal_ALsizei n, mal_ALuint *sources); +typedef void (MAL_AL_APIENTRY * MAL_LPALDELETESOURCES) (mal_ALsizei n, const mal_ALuint *sources); +typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISSOURCE) (mal_ALuint source); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEF) (mal_ALuint source, mal_ALenum param, mal_ALfloat value); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCE3F) (mal_ALuint source, mal_ALenum param, mal_ALfloat value1, mal_ALfloat value2, mal_ALfloat value3); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEFV) (mal_ALuint source, mal_ALenum param, const mal_ALfloat *values); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEI) (mal_ALuint source, mal_ALenum param, mal_ALint value); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCE3I) (mal_ALuint source, mal_ALenum param, mal_ALint value1, mal_ALint value2, mal_ALint value3); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEIV) (mal_ALuint source, mal_ALenum param, const mal_ALint *values); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEF) (mal_ALuint source, mal_ALenum param, mal_ALfloat *value); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCE3F) (mal_ALuint source, mal_ALenum param, mal_ALfloat *value1, mal_ALfloat *value2, mal_ALfloat *value3); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEFV) (mal_ALuint source, mal_ALenum param, mal_ALfloat *values); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEI) (mal_ALuint source, mal_ALenum param, mal_ALint *value); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCE3I) (mal_ALuint source, mal_ALenum param, mal_ALint *value1, mal_ALint *value2, mal_ALint *value3); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEIV) (mal_ALuint source, mal_ALenum param, mal_ALint *values); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPLAYV) (mal_ALsizei n, const mal_ALuint *sources); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCESTOPV) (mal_ALsizei n, const mal_ALuint *sources); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEREWINDV) (mal_ALsizei n, const mal_ALuint *sources); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPAUSEV) (mal_ALsizei n, const mal_ALuint *sources); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPLAY) (mal_ALuint source); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCESTOP) (mal_ALuint source); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEREWIND) (mal_ALuint source); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPAUSE) (mal_ALuint source); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEQUEUEBUFFERS) (mal_ALuint source, mal_ALsizei nb, const mal_ALuint *buffers); +typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEUNQUEUEBUFFERS)(mal_ALuint source, mal_ALsizei nb, mal_ALuint *buffers); +typedef void (MAL_AL_APIENTRY * MAL_LPALGENBUFFERS) (mal_ALsizei n, mal_ALuint *buffers); +typedef void (MAL_AL_APIENTRY * MAL_LPALDELETEBUFFERS) (mal_ALsizei n, const mal_ALuint *buffers); +typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISBUFFER) (mal_ALuint buffer); +typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERDATA) (mal_ALuint buffer, mal_ALenum format, const mal_ALvoid *data, mal_ALsizei size, mal_ALsizei freq); +typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERF) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat value); +typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFER3F) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat value1, mal_ALfloat value2, mal_ALfloat value3); +typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERFV) (mal_ALuint buffer, mal_ALenum param, const mal_ALfloat *values); +typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERI) (mal_ALuint buffer, mal_ALenum param, mal_ALint value); +typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFER3I) (mal_ALuint buffer, mal_ALenum param, mal_ALint value1, mal_ALint value2, mal_ALint value3); +typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERIV) (mal_ALuint buffer, mal_ALenum param, const mal_ALint *values); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERF) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat *value); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFER3F) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat *value1, mal_ALfloat *value2, mal_ALfloat *value3); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERFV) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat *values); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERI) (mal_ALuint buffer, mal_ALenum param, mal_ALint *value); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFER3I) (mal_ALuint buffer, mal_ALenum param, mal_ALint *value1, mal_ALint *value2, mal_ALint *value3); +typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERIV) (mal_ALuint buffer, mal_ALenum param, mal_ALint *values); + +mal_result mal_context_init__openal(mal_context* pContext) +{ + mal_assert(pContext != NULL); + + const char* libName = NULL; +#ifdef MAL_WIN32 + libName = "OpenAL32.dll"; +#endif +#if defined(MAL_UNIX) && !defined(MAL_APPLE) + libName = "libopenal.so"; +#endif +#ifdef MAL_APPLE + // I don't own a Mac so a contribution here would be much appreciated! Just don't know what the library is called... +#endif + if (libName == NULL) { + return MAL_NO_BACKEND; // Don't know what the library name is called. + } + + + pContext->openal.hOpenAL = mal_dlopen(libName); + +#ifdef MAL_WIN32 + // Special case for Win32 - try "soft_oal.dll" for OpenAL-Soft drop-ins. + if (pContext->openal.hOpenAL == NULL) { + pContext->openal.hOpenAL = mal_dlopen("soft_oal.dll"); + } +#endif + + if (pContext->openal.hOpenAL == NULL) { + return MAL_FAILED_TO_INIT_BACKEND; + } + + pContext->openal.alcCreateContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCreateContext"); + pContext->openal.alcMakeContextCurrent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcMakeContextCurrent"); + pContext->openal.alcProcessContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcProcessContext"); + pContext->openal.alcSuspendContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcSuspendContext"); + pContext->openal.alcDestroyContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcDestroyContext"); + pContext->openal.alcGetCurrentContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetCurrentContext"); + pContext->openal.alcGetContextsDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetContextsDevice"); + pContext->openal.alcOpenDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcOpenDevice"); + pContext->openal.alcCloseDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCloseDevice"); + pContext->openal.alcGetError = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetError"); + pContext->openal.alcIsExtensionPresent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcIsExtensionPresent"); + pContext->openal.alcGetProcAddress = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetProcAddress"); + pContext->openal.alcGetEnumValue = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetEnumValue"); + pContext->openal.alcGetString = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetString"); + pContext->openal.alcGetIntegerv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetIntegerv"); + pContext->openal.alcCaptureOpenDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureOpenDevice"); + pContext->openal.alcCaptureCloseDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureCloseDevice"); + pContext->openal.alcCaptureStart = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureStart"); + pContext->openal.alcCaptureStop = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureStop"); + pContext->openal.alcCaptureSamples = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureSamples"); + + pContext->openal.alEnable = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alEnable"); + pContext->openal.alDisable = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDisable"); + pContext->openal.alIsEnabled = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsEnabled"); + pContext->openal.alGetString = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetString"); + pContext->openal.alGetBooleanv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBooleanv"); + pContext->openal.alGetIntegerv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetIntegerv"); + pContext->openal.alGetFloatv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetFloatv"); + pContext->openal.alGetDoublev = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetDoublev"); + pContext->openal.alGetBoolean = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBoolean"); + pContext->openal.alGetInteger = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetInteger"); + pContext->openal.alGetFloat = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetFloat"); + pContext->openal.alGetDouble = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetDouble"); + pContext->openal.alGetError = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetError"); + pContext->openal.alIsExtensionPresent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsExtensionPresent"); + pContext->openal.alGetProcAddress = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetProcAddress"); + pContext->openal.alGetEnumValue = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetEnumValue"); + pContext->openal.alGenSources = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGenSources"); + pContext->openal.alDeleteSources = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDeleteSources"); + pContext->openal.alIsSource = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsSource"); + pContext->openal.alSourcef = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcef"); + pContext->openal.alSource3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSource3f"); + pContext->openal.alSourcefv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcefv"); + pContext->openal.alSourcei = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcei"); + pContext->openal.alSource3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSource3i"); + pContext->openal.alSourceiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceiv"); + pContext->openal.alGetSourcef = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcef"); + pContext->openal.alGetSource3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSource3f"); + pContext->openal.alGetSourcefv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcefv"); + pContext->openal.alGetSourcei = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcei"); + pContext->openal.alGetSource3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSource3i"); + pContext->openal.alGetSourceiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourceiv"); + pContext->openal.alSourcePlayv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePlayv"); + pContext->openal.alSourceStopv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceStopv"); + pContext->openal.alSourceRewindv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceRewindv"); + pContext->openal.alSourcePausev = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePausev"); + pContext->openal.alSourcePlay = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePlay"); + pContext->openal.alSourceStop = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceStop"); + pContext->openal.alSourceRewind = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceRewind"); + pContext->openal.alSourcePause = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePause"); + pContext->openal.alSourceQueueBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceQueueBuffers"); + pContext->openal.alSourceUnqueueBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceUnqueueBuffers"); + pContext->openal.alGenBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGenBuffers"); + pContext->openal.alDeleteBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDeleteBuffers"); + pContext->openal.alIsBuffer = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsBuffer"); + pContext->openal.alBufferData = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferData"); + pContext->openal.alBufferf = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferf"); + pContext->openal.alBuffer3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBuffer3f"); + pContext->openal.alBufferfv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferfv"); + pContext->openal.alBufferi = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferi"); + pContext->openal.alBuffer3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBuffer3i"); + pContext->openal.alBufferiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferiv"); + pContext->openal.alGetBufferf = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferf"); + pContext->openal.alGetBuffer3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBuffer3f"); + pContext->openal.alGetBufferfv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferfv"); + pContext->openal.alGetBufferi = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferi"); + pContext->openal.alGetBuffer3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBuffer3i"); + pContext->openal.alGetBufferiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferiv"); + + // We depend on the ALC_ENUMERATION_EXT extension. + if (!((MAL_LPALCISEXTENSIONPRESENT)pContext->openal.alcIsExtensionPresent)(NULL, "ALC_ENUMERATION_EXT")) { + mal_dlclose(pContext->openal.hOpenAL); + return MAL_FAILED_TO_INIT_BACKEND; + } + + pContext->openal.isFloat32Supported = ((MAL_LPALISEXTENSIONPRESENT)pContext->openal.alIsExtensionPresent)("AL_EXT_float32"); + pContext->openal.isMCFormatsSupported = ((MAL_LPALISEXTENSIONPRESENT)pContext->openal.alIsExtensionPresent)("AL_EXT_MCFORMATS"); + + return MAL_SUCCESS; +} + +mal_result mal_context_uninit__openal(mal_context* pContext) +{ + mal_assert(pContext != NULL); + mal_assert(pContext->backend == mal_backend_openal); + + mal_dlclose(pContext->openal.hOpenAL); + return MAL_SUCCESS; +} + +mal_result mal_enumerate_devices__openal(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) +{ + mal_uint32 infoSize = *pCount; + *pCount = 0; + + const mal_ALCchar* pDeviceNames = ((MAL_LPALCGETSTRING)pContext->openal.alcGetString)(NULL, (type == mal_device_type_playback) ? MAL_ALC_DEVICE_SPECIFIER : MAL_ALC_CAPTURE_DEVICE_SPECIFIER); + if (pDeviceNames == NULL) { + return MAL_NO_DEVICE; + } + + // Each device is stored in pDeviceNames, separated by a null-terminator. The string itself is double-null-terminated. + const mal_ALCchar* pNextDeviceName = pDeviceNames; + while (pNextDeviceName[0] != '\0') { + if (pInfo != NULL) { + if (infoSize > 0) { + mal_strncpy_s(pInfo->id.openal, sizeof(pInfo->id.openal), (const char*)pNextDeviceName, (size_t)-1); + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), (const char*)pNextDeviceName, (size_t)-1); + + pInfo += 1; + infoSize -= 1; + *pCount += 1; + } + } else { + *pCount += 1; + } + + // Move to the next device name. + while (*pNextDeviceName != '\0') { + pNextDeviceName += 1; + } + + // Skip past the null terminator. + pNextDeviceName += 1; + }; + + return MAL_SUCCESS; +} + +static void mal_device_uninit__openal(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)(NULL); + ((MAL_LPALCDESTROYCONTEXT)pDevice->pContext->openal.alcDestroyContext)((mal_ALCcontext*)pDevice->openal.pContextALC); + + if (pDevice->type == mal_device_type_playback) { + ((MAL_LPALCCLOSEDEVICE)pDevice->pContext->openal.alcCloseDevice)((mal_ALCdevice*)pDevice->openal.pDeviceALC); + } else { + ((MAL_LPALCCAPTURECLOSEDEVICE)pDevice->pContext->openal.alcCaptureCloseDevice)((mal_ALCdevice*)pDevice->openal.pDeviceALC); + } + + mal_free(pDevice->openal.pIntermediaryBuffer); +} + +static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) +{ + if (pDevice->periods > MAL_MAX_PERIODS_OPENAL) { + pDevice->periods = MAL_MAX_PERIODS_OPENAL; + } + + // OpenAL has bad latency in my testing :( + if (pDevice->usingDefaultBufferSize) { + pDevice->bufferSizeInFrames *= 4; + } + + mal_ALCsizei bufferSizeInSamplesAL = pDevice->bufferSizeInFrames; + mal_ALCuint frequencyAL = pConfig->sampleRate; + + mal_uint32 channelsAL = 0; + + // OpenAL currently only supports only mono and stereo. TODO: Check for the AL_EXT_MCFORMATS extension and use one of those formats for quad, 5.1, etc. + mal_ALCenum formatAL = 0; + if (pConfig->channels == 1) { + // Mono. + channelsAL = 1; + if (pConfig->format == mal_format_f32) { + if (pContext->openal.isFloat32Supported) { + formatAL = MAL_AL_FORMAT_MONO_FLOAT32; + } else { + formatAL = MAL_AL_FORMAT_MONO16; + } + } else if (pConfig->format == mal_format_s32) { + formatAL = MAL_AL_FORMAT_MONO16; + } else if (pConfig->format == mal_format_s24) { + formatAL = MAL_AL_FORMAT_MONO16; + } else if (pConfig->format == mal_format_s16) { + formatAL = MAL_AL_FORMAT_MONO16; + } else if (pConfig->format == mal_format_u8) { + formatAL = MAL_AL_FORMAT_MONO8; + } + } else { + // Stereo. + channelsAL = 2; + if (pConfig->format == mal_format_f32) { + if (pContext->openal.isFloat32Supported) { + formatAL = MAL_AL_FORMAT_STEREO_FLOAT32; + } else { + formatAL = MAL_AL_FORMAT_STEREO16; + } + } else if (pConfig->format == mal_format_s32) { + formatAL = MAL_AL_FORMAT_STEREO16; + } else if (pConfig->format == mal_format_s24) { + formatAL = MAL_AL_FORMAT_STEREO16; + } else if (pConfig->format == mal_format_s16) { + formatAL = MAL_AL_FORMAT_STEREO16; + } else if (pConfig->format == mal_format_u8) { + formatAL = MAL_AL_FORMAT_STEREO8; + } + } + + if (formatAL == 0) { + return MAL_FORMAT_NOT_SUPPORTED; + } + + bufferSizeInSamplesAL *= channelsAL; + + + // OpenAL feels a bit unintuitive to me... The global object is a device, and it would appear that each device can have + // many context's... + mal_ALCdevice* pDeviceALC = NULL; + if (type == mal_device_type_playback) { + pDeviceALC = ((MAL_LPALCOPENDEVICE)pContext->openal.alcOpenDevice)((pDeviceID == NULL) ? NULL : pDeviceID->openal); + } else { + pDeviceALC = ((MAL_LPALCCAPTUREOPENDEVICE)pContext->openal.alcCaptureOpenDevice)((pDeviceID == NULL) ? NULL : pDeviceID->openal, frequencyAL, formatAL, bufferSizeInSamplesAL); + } + + if (pDeviceALC == NULL) { + return mal_context_post_error(pContext, NULL, "[OpenAL] Failed to open device.", MAL_FAILED_TO_INIT_BACKEND); + } + + // A context is only required for playback. + mal_ALCcontext* pContextALC = NULL; + if (pDevice->type == mal_device_type_playback) { + pContextALC = ((MAL_LPALCCREATECONTEXT)pContext->openal.alcCreateContext)(pDeviceALC, NULL); + if (pContextALC == NULL) { + ((MAL_LPALCCLOSEDEVICE)pDevice->pContext->openal.alcCloseDevice)(pDeviceALC); + return mal_context_post_error(pContext, NULL, "[OpenAL] Failed to open OpenAL context.", MAL_FAILED_TO_INIT_BACKEND); + } + + ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)(pContextALC); + + mal_ALuint sourceAL; + ((MAL_LPALGENSOURCES)pDevice->pContext->openal.alGenSources)(1, &sourceAL); + pDevice->openal.sourceAL = sourceAL; + + // We create the buffers, but only fill and queue them when the device is started. + mal_ALuint buffersAL[MAL_MAX_PERIODS_OPENAL]; + ((MAL_LPALGENBUFFERS)pDevice->pContext->openal.alGenBuffers)(pDevice->periods, buffersAL); + for (mal_uint32 i = 0; i < pDevice->periods; ++i) { + pDevice->openal.buffersAL[i] = buffersAL[i]; + } + } + + pDevice->internalChannels = channelsAL; + pDevice->internalSampleRate = frequencyAL; + + // The internal format is a little bit straight with OpenAL. + switch (formatAL) + { + case MAL_AL_FORMAT_MONO8: + case MAL_AL_FORMAT_STEREO8: + case MAL_AL_FORMAT_REAR8: + case MAL_AL_FORMAT_QUAD8: + case MAL_AL_FORMAT_51CHN8: + case MAL_AL_FORMAT_61CHN8: + case MAL_AL_FORMAT_71CHN8: + { + pDevice->internalFormat = mal_format_u8; + } break; + + case MAL_AL_FORMAT_MONO16: + case MAL_AL_FORMAT_STEREO16: + case MAL_AL_FORMAT_REAR16: + case MAL_AL_FORMAT_QUAD16: + case MAL_AL_FORMAT_51CHN16: + case MAL_AL_FORMAT_61CHN16: + case MAL_AL_FORMAT_71CHN16: + { + pDevice->internalFormat = mal_format_s16; + } break; + + case MAL_AL_FORMAT_REAR32: + case MAL_AL_FORMAT_QUAD32: + case MAL_AL_FORMAT_51CHN32: + case MAL_AL_FORMAT_61CHN32: + case MAL_AL_FORMAT_71CHN32: + { + pDevice->internalFormat = mal_format_s32; + } break; + + case MAL_AL_FORMAT_MONO_FLOAT32: + case MAL_AL_FORMAT_STEREO_FLOAT32: + { + pDevice->internalFormat = mal_format_f32; + } break; + } + + // From what I can tell, the ordering of channels is fixed for OpenAL. + switch (formatAL) + { + case MAL_AL_FORMAT_MONO8: + case MAL_AL_FORMAT_MONO16: + case MAL_AL_FORMAT_MONO_FLOAT32: + { + pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_CENTER; + } break; + + case MAL_AL_FORMAT_STEREO8: + case MAL_AL_FORMAT_STEREO16: + case MAL_AL_FORMAT_STEREO_FLOAT32: + { + pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT; + pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + } break; + + case MAL_AL_FORMAT_REAR8: + case MAL_AL_FORMAT_REAR16: + case MAL_AL_FORMAT_REAR32: + { + pDevice->internalChannelMap[0] = MAL_CHANNEL_BACK_LEFT; + pDevice->internalChannelMap[1] = MAL_CHANNEL_BACK_RIGHT; + } break; + + case MAL_AL_FORMAT_QUAD8: + case MAL_AL_FORMAT_QUAD16: + case MAL_AL_FORMAT_QUAD32: + { + pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT; + pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + pDevice->internalChannelMap[2] = MAL_CHANNEL_BACK_LEFT; + pDevice->internalChannelMap[3] = MAL_CHANNEL_BACK_RIGHT; + } break; + + case MAL_AL_FORMAT_51CHN8: + case MAL_AL_FORMAT_51CHN16: + case MAL_AL_FORMAT_51CHN32: + { + pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT; + pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + pDevice->internalChannelMap[2] = MAL_CHANNEL_FRONT_CENTER; + pDevice->internalChannelMap[3] = MAL_CHANNEL_LFE; + pDevice->internalChannelMap[4] = MAL_CHANNEL_BACK_LEFT; + pDevice->internalChannelMap[5] = MAL_CHANNEL_BACK_RIGHT; + } break; + + case MAL_AL_FORMAT_61CHN8: + case MAL_AL_FORMAT_61CHN16: + case MAL_AL_FORMAT_61CHN32: + { + pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT; + pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + pDevice->internalChannelMap[2] = MAL_CHANNEL_FRONT_CENTER; + pDevice->internalChannelMap[3] = MAL_CHANNEL_LFE; + pDevice->internalChannelMap[4] = MAL_CHANNEL_BACK_CENTER; + pDevice->internalChannelMap[5] = MAL_CHANNEL_SIDE_LEFT; + pDevice->internalChannelMap[6] = MAL_CHANNEL_SIDE_RIGHT; + } break; + + case MAL_AL_FORMAT_71CHN8: + case MAL_AL_FORMAT_71CHN16: + case MAL_AL_FORMAT_71CHN32: + { + pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT; + pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + pDevice->internalChannelMap[2] = MAL_CHANNEL_FRONT_CENTER; + pDevice->internalChannelMap[3] = MAL_CHANNEL_LFE; + pDevice->internalChannelMap[4] = MAL_CHANNEL_BACK_LEFT; + pDevice->internalChannelMap[5] = MAL_CHANNEL_BACK_RIGHT; + pDevice->internalChannelMap[6] = MAL_CHANNEL_SIDE_LEFT; + pDevice->internalChannelMap[7] = MAL_CHANNEL_SIDE_RIGHT; + } break; + + default: break; + } + + pDevice->openal.pDeviceALC = pDeviceALC; + pDevice->openal.pContextALC = pContextALC; + pDevice->openal.formatAL = formatAL; + pDevice->openal.subBufferSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods; + pDevice->openal.pIntermediaryBuffer = (mal_uint8*)mal_malloc(pDevice->openal.subBufferSizeInFrames * channelsAL * mal_get_sample_size_in_bytes(pDevice->internalFormat)); + if (pDevice->openal.pIntermediaryBuffer == NULL) { + mal_device_uninit__openal(pDevice); + return mal_context_post_error(pContext, NULL, "[OpenAL] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY); + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__start_backend__openal(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->type == mal_device_type_playback) { + // Playback. + // + // When starting playback we want to ensure each buffer is filled and queued before playing the source. + pDevice->openal.iNextBuffer = 0; + + ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC); + + for (mal_uint32 i = 0; i < pDevice->periods; ++i) { + mal_device__read_frames_from_client(pDevice, pDevice->openal.subBufferSizeInFrames, pDevice->openal.pIntermediaryBuffer); + + mal_ALuint bufferAL = pDevice->openal.buffersAL[i]; + ((MAL_LPALBUFFERDATA)pDevice->pContext->openal.alBufferData)(bufferAL, pDevice->openal.formatAL, pDevice->openal.pIntermediaryBuffer, pDevice->openal.subBufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat), pDevice->internalSampleRate); + ((MAL_LPALSOURCEQUEUEBUFFERS)pDevice->pContext->openal.alSourceQueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL); + } + + // Start the source only after filling and queueing each buffer. + ((MAL_LPALSOURCEPLAY)pDevice->pContext->openal.alSourcePlay)(pDevice->openal.sourceAL); + } else { + // Capture. + ((MAL_LPALCCAPTURESTART)pDevice->pContext->openal.alcCaptureStart)((mal_ALCdevice*)pDevice->openal.pDeviceALC); + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__stop_backend__openal(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->type == mal_device_type_playback) { + ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC); + ((MAL_LPALSOURCESTOP)pDevice->pContext->openal.alSourceStop)(pDevice->openal.sourceAL); + } else { + ((MAL_LPALCCAPTURESTOP)pDevice->pContext->openal.alcCaptureStop)((mal_ALCdevice*)pDevice->openal.pDeviceALC); + } + + return MAL_SUCCESS; +} + +static mal_result mal_device__break_main_loop__openal(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + pDevice->openal.breakFromMainLoop = MAL_TRUE; + return MAL_SUCCESS; +} + +static mal_uint32 mal_device__get_available_frames__openal(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + if (pDevice->type == mal_device_type_playback) { + ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC); + + mal_ALint processedBufferCount = 0; + ((MAL_LPALGETSOURCEI)pDevice->pContext->openal.alGetSourcei)(pDevice->openal.sourceAL, MAL_AL_BUFFERS_PROCESSED, &processedBufferCount); + + return processedBufferCount * pDevice->openal.subBufferSizeInFrames; + } else { + mal_ALint samplesAvailable = 0; + ((MAL_LPALCGETINTEGERV)pDevice->pContext->openal.alcGetIntegerv)((mal_ALCdevice*)pDevice->openal.pDeviceALC, MAL_ALC_CAPTURE_SAMPLES, 1, &samplesAvailable); + + return samplesAvailable / pDevice->channels; + } +} + +static mal_uint32 mal_device__wait_for_frames__openal(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + while (!pDevice->openal.breakFromMainLoop) { + mal_uint32 framesAvailable = mal_device__get_available_frames__openal(pDevice); + if (framesAvailable > 0) { + return framesAvailable; + } + + mal_sleep(1); + } + + // We'll get here if the loop was terminated. When capturing we want to return whatever is available. For playback we just drop it. + if (pDevice->type == mal_device_type_playback) { + return 0; + } else { + return mal_device__get_available_frames__openal(pDevice); + } +} + +static mal_result mal_device__main_loop__openal(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + pDevice->openal.breakFromMainLoop = MAL_FALSE; + while (!pDevice->openal.breakFromMainLoop) { + mal_uint32 framesAvailable = mal_device__wait_for_frames__openal(pDevice); + if (framesAvailable == 0) { + continue; + } + + // If it's a playback device, don't bother grabbing more data if the device is being stopped. + if (pDevice->openal.breakFromMainLoop && pDevice->type == mal_device_type_playback) { + return MAL_FALSE; + } + + if (pDevice->type == mal_device_type_playback) { + while (framesAvailable > 0) { + mal_uint32 framesToRead = (framesAvailable > pDevice->openal.subBufferSizeInFrames) ? pDevice->openal.subBufferSizeInFrames : framesAvailable; + + mal_ALuint bufferAL = pDevice->openal.buffersAL[pDevice->openal.iNextBuffer]; + pDevice->openal.iNextBuffer = (pDevice->openal.iNextBuffer + 1) % pDevice->periods; + + mal_device__read_frames_from_client(pDevice, framesToRead, pDevice->openal.pIntermediaryBuffer); + + ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC); + ((MAL_LPALSOURCEUNQUEUEBUFFERS)pDevice->pContext->openal.alSourceUnqueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL); + ((MAL_LPALBUFFERDATA)pDevice->pContext->openal.alBufferData)(bufferAL, pDevice->openal.formatAL, pDevice->openal.pIntermediaryBuffer, pDevice->openal.subBufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat), pDevice->internalSampleRate); + ((MAL_LPALSOURCEQUEUEBUFFERS)pDevice->pContext->openal.alSourceQueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL); + + framesAvailable -= framesToRead; + } + + + // There's a chance the source has stopped playing due to there not being any buffer's queue. Make sure it's restarted. + mal_ALenum state; + ((MAL_LPALGETSOURCEI)pDevice->pContext->openal.alGetSourcei)(pDevice->openal.sourceAL, MAL_AL_SOURCE_STATE, &state); + + if (state != MAL_AL_PLAYING) { + ((MAL_LPALSOURCEPLAY)pDevice->pContext->openal.alSourcePlay)(pDevice->openal.sourceAL); + } + } else { + while (framesAvailable > 0) { + mal_uint32 framesToSend = (framesAvailable > pDevice->openal.subBufferSizeInFrames) ? pDevice->openal.subBufferSizeInFrames : framesAvailable; + ((MAL_LPALCCAPTURESAMPLES)pDevice->pContext->openal.alcCaptureSamples)((mal_ALCdevice*)pDevice->openal.pDeviceALC, pDevice->openal.pIntermediaryBuffer, framesToSend); + + mal_device__send_frames_to_client(pDevice, framesToSend, pDevice->openal.pIntermediaryBuffer); + framesAvailable -= framesToSend; + } + } + } + + return MAL_SUCCESS; +} +#endif // OpenAL + + +mal_bool32 mal__is_channel_map_valid(const mal_channel* channelMap, mal_uint32 channels) +{ + mal_assert(channels > 0); + + // A channel cannot be present in the channel map more than once. + for (mal_uint32 iChannel = 0; iChannel < channels; ++iChannel) { + for (mal_uint32 jChannel = iChannel + 1; jChannel < channels; ++jChannel) { + if (channelMap[iChannel] == channelMap[jChannel]) { + return MAL_FALSE; + } + } + } + + return MAL_TRUE; +} + + +static mal_result mal_device__start_backend(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + mal_result result = MAL_NO_BACKEND; +#ifdef MAL_ENABLE_WASAPI + if (pDevice->pContext->backend == mal_backend_wasapi) { + result = mal_device__start_backend__wasapi(pDevice); + } +#endif +#ifdef MAL_ENABLE_DSOUND + if (pDevice->pContext->backend == mal_backend_dsound) { + result = mal_device__start_backend__dsound(pDevice); + } +#endif +#ifdef MAL_ENABLE_WINMM + if (pDevice->pContext->backend == mal_backend_winmm) { + result = mal_device__start_backend__winmm(pDevice); + } +#endif +#ifdef MAL_ENABLE_ALSA + if (pDevice->pContext->backend == mal_backend_alsa) { + result = mal_device__start_backend__alsa(pDevice); + } +#endif +#ifdef MAL_ENABLE_OSS + if (pDevice->pContext->backend == mal_backend_oss) { + result = mal_device__start_backend__oss(pDevice); + } +#endif +#ifdef MAL_ENABLE_OPENAL + if (pDevice->pContext->backend == mal_backend_openal) { + result = mal_device__start_backend__openal(pDevice); + } +#endif +#ifdef MAL_ENABLE_NULL + if (pDevice->pContext->backend == mal_backend_null) { + result = mal_device__start_backend__null(pDevice); + } +#endif + + return result; +} + +static mal_result mal_device__stop_backend(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + mal_result result = MAL_NO_BACKEND; +#ifdef MAL_ENABLE_WASAPI + if (pDevice->pContext->backend == mal_backend_wasapi) { + result = mal_device__stop_backend__wasapi(pDevice); + } +#endif +#ifdef MAL_ENABLE_DSOUND + if (pDevice->pContext->backend == mal_backend_dsound) { + result = mal_device__stop_backend__dsound(pDevice); + } +#endif +#ifdef MAL_ENABLE_WINMM + if (pDevice->pContext->backend == mal_backend_winmm) { + result = mal_device__stop_backend__winmm(pDevice); + } +#endif +#ifdef MAL_ENABLE_ALSA + if (pDevice->pContext->backend == mal_backend_alsa) { + result = mal_device__stop_backend__alsa(pDevice); + } +#endif +#ifdef MAL_ENABLE_OSS + if (pDevice->pContext->backend == mal_backend_oss) { + result = mal_device__stop_backend__oss(pDevice); + } +#endif +#ifdef MAL_ENABLE_OPENAL + if (pDevice->pContext->backend == mal_backend_openal) { + result = mal_device__stop_backend__openal(pDevice); + } +#endif +#ifdef MAL_ENABLE_NULL + if (pDevice->pContext->backend == mal_backend_null) { + result = mal_device__stop_backend__null(pDevice); + } +#endif + + return result; +} + +static mal_result mal_device__break_main_loop(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + mal_result result = MAL_NO_BACKEND; +#ifdef MAL_ENABLE_WASAPI + if (pDevice->pContext->backend == mal_backend_wasapi) { + result = mal_device__break_main_loop__wasapi(pDevice); + } +#endif +#ifdef MAL_ENABLE_DSOUND + if (pDevice->pContext->backend == mal_backend_dsound) { + result = mal_device__break_main_loop__dsound(pDevice); + } +#endif +#ifdef MAL_ENABLE_WINMM + if (pDevice->pContext->backend == mal_backend_winmm) { + result = mal_device__break_main_loop__winmm(pDevice); + } +#endif +#ifdef MAL_ENABLE_ALSA + if (pDevice->pContext->backend == mal_backend_alsa) { + result = mal_device__break_main_loop__alsa(pDevice); + } +#endif +#ifdef MAL_ENABLE_OSS + if (pDevice->pContext->backend == mal_backend_oss) { + result = mal_device__break_main_loop__oss(pDevice); + } +#endif +#ifdef MAL_ENABLE_OPENAL + if (pDevice->pContext->backend == mal_backend_openal) { + result = mal_device__break_main_loop__openal(pDevice); + } +#endif +#ifdef MAL_ENABLE_NULL + if (pDevice->pContext->backend == mal_backend_null) { + result = mal_device__break_main_loop__null(pDevice); + } +#endif + + return result; +} + +static mal_result mal_device__main_loop(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + + mal_result result = MAL_NO_BACKEND; +#ifdef MAL_ENABLE_WASAPI + if (pDevice->pContext->backend == mal_backend_wasapi) { + result = mal_device__main_loop__wasapi(pDevice); + } +#endif +#ifdef MAL_ENABLE_DSOUND + if (pDevice->pContext->backend == mal_backend_dsound) { + result = mal_device__main_loop__dsound(pDevice); + } +#endif +#ifdef MAL_ENABLE_WINMM + if (pDevice->pContext->backend == mal_backend_winmm) { + result = mal_device__main_loop__winmm(pDevice); + } +#endif +#ifdef MAL_ENABLE_ALSA + if (pDevice->pContext->backend == mal_backend_alsa) { + result = mal_device__main_loop__alsa(pDevice); + } +#endif +#ifdef MAL_ENABLE_OSS + if (pDevice->pContext->backend == mal_backend_oss) { + result = mal_device__main_loop__oss(pDevice); + } +#endif +#ifdef MAL_ENABLE_OPENAL + if (pDevice->pContext->backend == mal_backend_openal) { + result = mal_device__main_loop__openal(pDevice); + } +#endif +#ifdef MAL_ENABLE_NULL + if (pDevice->pContext->backend == mal_backend_null) { + result = mal_device__main_loop__null(pDevice); + } +#endif + + return result; +} + +mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData) +{ + mal_device* pDevice = (mal_device*)pData; + mal_assert(pDevice != NULL); + +#ifdef MAL_WIN32 + mal_CoInitializeEx(pDevice->pContext, NULL, 0); // 0 = COINIT_MULTITHREADED +#endif + + // This is only used to prevent posting onStop() when the device is first initialized. + mal_bool32 skipNextStopEvent = MAL_TRUE; + + for (;;) { + // At the start of iteration the device is stopped - we must explicitly mark it as such. + mal_device__stop_backend(pDevice); + + if (!skipNextStopEvent) { + mal_stop_proc onStop = pDevice->onStop; + if (onStop) { + onStop(pDevice); + } + } else { + skipNextStopEvent = MAL_FALSE; + } + + + // Let the other threads know that the device has stopped. + mal_device__set_state(pDevice, MAL_STATE_STOPPED); + mal_event_signal(pDevice->pContext, &pDevice->stopEvent); + + // We use an event to wait for a request to wake up. + mal_event_wait(pDevice->pContext, &pDevice->wakeupEvent); + + // Default result code. + pDevice->workResult = MAL_SUCCESS; + + // Just break if we're terminating. + if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) { + break; + } + + + // Getting here means we just started the device and we need to wait for the device to + // either deliver us data (recording) or request more data (playback). + mal_assert(mal_device__get_state(pDevice) == MAL_STATE_STARTING); + + pDevice->workResult = mal_device__start_backend(pDevice); + if (pDevice->workResult != MAL_SUCCESS) { + mal_event_signal(pDevice->pContext, &pDevice->startEvent); + continue; + } + + // The thread that requested the device to start playing is waiting for this thread to start the + // device for real, which is now. + mal_device__set_state(pDevice, MAL_STATE_STARTED); + mal_event_signal(pDevice->pContext, &pDevice->startEvent); + + // Now we just enter the main loop. The main loop can be broken with mal_device__break_main_loop(). + mal_device__main_loop(pDevice); + } + + // Make sure we aren't continuously waiting on a stop event. + mal_event_signal(pDevice->pContext, &pDevice->stopEvent); // <-- Is this still needed? + +#ifdef MAL_WIN32 + mal_CoUninitialize(pDevice->pContext); +#endif + + return (mal_thread_result)0; +} + + +// Helper for determining whether or not the given device is initialized. +mal_bool32 mal_device__is_initialized(mal_device* pDevice) +{ + if (pDevice == NULL) return MAL_FALSE; + return mal_device__get_state(pDevice) != MAL_STATE_UNINITIALIZED; +} + + +#ifdef MAL_WIN32 +mal_result mal_context_uninit_backend_apis__win32(mal_context* pContext) +{ + mal_CoUninitialize(pContext); + mal_dlclose(pContext->win32.hUser32DLL); + mal_dlclose(pContext->win32.hOle32DLL); + + return MAL_SUCCESS; +} + +mal_result mal_context_init_backend_apis__win32(mal_context* pContext) +{ +#ifdef MAL_WIN32_DESKTOP + // Ole32.dll + pContext->win32.hOle32DLL = mal_dlopen("ole32.dll"); + if (pContext->win32.hOle32DLL == NULL) { + return MAL_FAILED_TO_INIT_BACKEND; + } + + pContext->win32.CoInitializeEx = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoInitializeEx"); + pContext->win32.CoUninitialize = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoUninitialize"); + pContext->win32.CoCreateInstance = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoCreateInstance"); + pContext->win32.CoTaskMemFree = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoTaskMemFree"); + pContext->win32.PropVariantClear = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "PropVariantClear"); + + + // User32.dll + pContext->win32.hUser32DLL = mal_dlopen("user32.dll"); + if (pContext->win32.hUser32DLL == NULL) { + return MAL_FAILED_TO_INIT_BACKEND; + } + + pContext->win32.GetForegroundWindow = (mal_proc)mal_dlsym(pContext->win32.hUser32DLL, "GetForegroundWindow"); + pContext->win32.GetDesktopWindow = (mal_proc)mal_dlsym(pContext->win32.hUser32DLL, "GetDesktopWindow"); +#endif + + mal_CoInitializeEx(pContext, NULL, 0); // 0 = COINIT_MULTITHREADED + return MAL_SUCCESS; +} +#else +mal_result mal_context_uninit_backend_apis__nix(mal_context* pContext) +{ + mal_dlclose(pContext->posix.pthreadSO); + + return MAL_SUCCESS; +} + +mal_result mal_context_init_backend_apis__nix(mal_context* pContext) +{ + // pthread + const char* libpthreadFileNames[] = { + "libpthread.so", + "libpthread.so.0" + }; + + for (size_t i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) { + pContext->posix.pthreadSO = mal_dlopen(libpthreadFileNames[i]); + if (pContext->posix.pthreadSO != NULL) { + break; + } + } + + if (pContext->posix.pthreadSO == NULL) { + return MAL_FAILED_TO_INIT_BACKEND; + } + + pContext->posix.pthread_create = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_create"); + pContext->posix.pthread_join = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_join"); + pContext->posix.pthread_mutex_init = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_init"); + pContext->posix.pthread_mutex_destroy = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_destroy"); + pContext->posix.pthread_mutex_lock = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_lock"); + pContext->posix.pthread_mutex_unlock = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_unlock"); + pContext->posix.pthread_cond_init = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_init"); + pContext->posix.pthread_cond_destroy = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_destroy"); + pContext->posix.pthread_cond_wait = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_wait"); + pContext->posix.pthread_cond_signal = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_signal"); + + return MAL_SUCCESS; +} +#endif + +mal_result mal_context_init_backend_apis(mal_context* pContext) +{ + mal_result result = MAL_NO_BACKEND; +#ifdef MAL_WIN32 + result = mal_context_init_backend_apis__win32(pContext); +#else + result = mal_context_init_backend_apis__nix(pContext); +#endif + + return result; +} + +mal_result mal_context_uninit_backend_apis(mal_context* pContext) +{ + mal_result result = MAL_NO_BACKEND; +#ifdef MAL_WIN32 + result = mal_context_uninit_backend_apis__win32(pContext); +#else + result = mal_context_uninit_backend_apis__nix(pContext); +#endif + + return result; +} + +mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, const mal_context_config* pConfig, mal_context* pContext) +{ + if (pContext == NULL) return MAL_INVALID_ARGS; + mal_zero_object(pContext); + + // Always make sure the config is set first to ensure properties are available as soon as possible. + if (pConfig != NULL) { + pContext->config = *pConfig; + } else { + pContext->config = mal_context_config_init(NULL); + } + + // Backend APIs need to be initialized first. This is where external libraries will be loaded and linked. + mal_result result = mal_context_init_backend_apis(pContext); + if (result != MAL_SUCCESS) { + return result; + } + + static mal_backend defaultBackends[] = { + mal_backend_wasapi, + mal_backend_dsound, + mal_backend_winmm, + mal_backend_alsa, + mal_backend_oss, + mal_backend_opensl, + mal_backend_openal, + mal_backend_null + }; + + if (backends == NULL) { + backends = defaultBackends; + backendCount = sizeof(defaultBackends) / sizeof(defaultBackends[0]); + } + + mal_assert(backends != NULL); + + for (mal_uint32 iBackend = 0; iBackend < backendCount; ++iBackend) { + mal_backend backend = backends[iBackend]; + + result = MAL_NO_BACKEND; + switch (backend) { + #ifdef MAL_ENABLE_WASAPI + case mal_backend_wasapi: + { + result = mal_context_init__wasapi(pContext); + } break; + #endif + #ifdef MAL_ENABLE_DSOUND + case mal_backend_dsound: + { + result = mal_context_init__dsound(pContext); + } break; + #endif + #ifdef MAL_ENABLE_WINMM + case mal_backend_winmm: + { + result = mal_context_init__winmm(pContext); + } break; + #endif + #ifdef MAL_ENABLE_ALSA + case mal_backend_alsa: + { + result = mal_context_init__alsa(pContext); + } break; + #endif + #ifdef MAL_ENABLE_OSS + case mal_backend_oss: + { + result = mal_context_init__oss(pContext); + } break; + #endif + #ifdef MAL_ENABLE_OPENSL + case mal_backend_opensl: + { + result = mal_context_init__opensl(pContext); + } break; + #endif + #ifdef MAL_ENABLE_OPENAL + case mal_backend_openal: + { + result = mal_context_init__openal(pContext); + } break; + #endif + #ifdef MAL_ENABLE_NULL + case mal_backend_null: + { + result = mal_context_init__null(pContext); + } break; + #endif + + default: break; + } + + // If this iteration was successful, return. + if (result == MAL_SUCCESS) { + pContext->backend = backend; + return result; + } + } + + mal_zero_object(pContext); // Safety. + return MAL_NO_BACKEND; +} + +mal_result mal_context_uninit(mal_context* pContext) +{ + if (pContext == NULL) return MAL_INVALID_ARGS; + + switch (pContext->backend) { + #ifdef MAL_ENABLE_WASAPI + case mal_backend_wasapi: + { + return mal_context_uninit__wasapi(pContext); + } break; + #endif + #ifdef MAL_ENABLE_DSOUND + case mal_backend_dsound: + { + return mal_context_uninit__dsound(pContext); + } break; + #endif + #ifdef MAL_ENABLE_WINMM + case mal_backend_winmm: + { + return mal_context_uninit__winmm(pContext); + } break; + #endif + #ifdef MAL_ENABLE_ALSA + case mal_backend_alsa: + { + return mal_context_uninit__alsa(pContext); + } break; + #endif + #ifdef MAL_ENABLE_OSS + case mal_backend_oss: + { + return mal_context_uninit__oss(pContext); + } break; + #endif + #ifdef MAL_ENABLE_OPENSL + case mal_backend_opensl: + { + return mal_context_uninit__opensl(pContext); + } break; + #endif + #ifdef MAL_ENABLE_OPENAL + case mal_backend_openal: + { + return mal_context_uninit__openal(pContext); + } break; + #endif + #ifdef MAL_ENABLE_NULL + case mal_backend_null: + { + return mal_context_uninit__null(pContext); + } break; + #endif + + default: break; + } + + mal_context_uninit_backend_apis(pContext); + + mal_assert(MAL_FALSE); + return MAL_NO_BACKEND; +} + + +mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) +{ + if (pCount == NULL) return mal_post_error(NULL, "mal_enumerate_devices() called with invalid arguments (pCount == 0).", MAL_INVALID_ARGS); + + switch (pContext->backend) + { + #ifdef MAL_ENABLE_WASAPI + case mal_backend_wasapi: + { + return mal_enumerate_devices__wasapi(pContext, type, pCount, pInfo); + } break; + #endif + #ifdef MAL_ENABLE_DSOUND + case mal_backend_dsound: + { + return mal_enumerate_devices__dsound(pContext, type, pCount, pInfo); + } break; + #endif + #ifdef MAL_ENABLE_WINMM + case mal_backend_winmm: + { + return mal_enumerate_devices__winmm(pContext, type, pCount, pInfo); + } break; + #endif + #ifdef MAL_ENABLE_ALSA + case mal_backend_alsa: + { + return mal_enumerate_devices__alsa(pContext, type, pCount, pInfo); + } break; + #endif + #ifdef MAL_ENABLE_OSS + case mal_backend_oss: + { + return mal_enumerate_devices__oss(pContext, type, pCount, pInfo); + } break; + #endif + #ifdef MAL_ENABLE_OPENSL + case mal_backend_opensl: + { + return mal_enumerate_devices__opensl(pContext, type, pCount, pInfo); + } break; + #endif + #ifdef MAL_ENABLE_OPENAL + case mal_backend_openal: + { + return mal_enumerate_devices__openal(pContext, type, pCount, pInfo); + } break; + #endif + #ifdef MAL_ENABLE_NULL + case mal_backend_null: + { + return mal_enumerate_devices__null(pContext, type, pCount, pInfo); + } break; + #endif + + default: break; + } + + mal_assert(MAL_FALSE); + return MAL_NO_BACKEND; +} + +mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, void* pUserData, mal_device* pDevice) +{ + if (pDevice == NULL) { + return mal_post_error(pDevice, "mal_device_init() called with invalid arguments (pDevice == NULL).", MAL_INVALID_ARGS); + } + if (pConfig == NULL) { + return mal_post_error(pDevice, "mal_device_init() called with invalid arguments (pConfig == NULL).", MAL_INVALID_ARGS); + } + + // Make a copy of the config to ensure we don't override the caller's object. + mal_device_config config = *pConfig; + + mal_zero_object(pDevice); + pDevice->pContext = pContext; + + // Set the user data and log callback ASAP to ensure it is available for the entire initialization process. + pDevice->pUserData = pUserData; + pDevice->onStop = config.onStopCallback; + pDevice->onSend = config.onSendCallback; + pDevice->onRecv = config.onRecvCallback; + + if (((mal_uint64)pDevice % sizeof(pDevice)) != 0) { + if (pContext->config.onLog) { + pContext->config.onLog(pContext, pDevice, "WARNING: mal_device_init() called for a device that is not properly aligned. Thread safety is not supported."); + } + } + + + if (pContext == NULL) { + return mal_post_error(pDevice, "mal_device_init() called with invalid arguments (pContext == NULL).", MAL_INVALID_ARGS); + } + + + // Basic config validation. + if (config.channels == 0) { + return mal_post_error(pDevice, "mal_device_init() called with an invalid config. Channel count must be greater than 0.", MAL_INVALID_DEVICE_CONFIG); + } + if (config.channels > MAL_MAX_CHANNELS) { + return mal_post_error(pDevice, "mal_device_init() called with an invalid config. Channel count cannot exceed 18.", MAL_INVALID_DEVICE_CONFIG); + } + + if (config.sampleRate == 0) { + return mal_post_error(pDevice, "mal_device_init() called with an invalid config. Sample rate must be greater than 0.", MAL_INVALID_DEVICE_CONFIG); + } + + if (!mal__is_channel_map_valid(pConfig->channelMap, pConfig->channels)) { + return mal_post_error(pDevice, "mal_device_init() called with invalid arguments. Channel map is invalid.", MAL_INVALID_DEVICE_CONFIG); + } + + + // Default buffer size and periods. + if (config.bufferSizeInFrames == 0) { + config.bufferSizeInFrames = (config.sampleRate/1000) * MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS; + pDevice->usingDefaultBufferSize = MAL_TRUE; + } + if (config.periods == 0) { + config.periods = MAL_DEFAULT_PERIODS; + pDevice->usingDefaultPeriods = MAL_TRUE; + } + + pDevice->type = type; + pDevice->format = config.format; + pDevice->channels = config.channels; + mal_copy_memory(config.channelMap, config.channelMap, sizeof(config.channelMap[0]) * config.channels); + pDevice->sampleRate = config.sampleRate; + pDevice->bufferSizeInFrames = config.bufferSizeInFrames; + pDevice->periods = config.periods; + + // The internal format, channel count and sample rate can be modified by the backend. + pDevice->internalFormat = pDevice->format; + pDevice->internalChannels = pDevice->channels; + pDevice->internalSampleRate = pDevice->sampleRate; + mal_copy_memory(pDevice->internalChannelMap, pDevice->channelMap, sizeof(pDevice->channelMap)); + + if (!mal_mutex_create(pContext, &pDevice->lock)) { + return mal_post_error(pDevice, "Failed to create mutex.", MAL_FAILED_TO_CREATE_MUTEX); + } + + // When the device is started, the worker thread is the one that does the actual startup of the backend device. We + // use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device. + // + // Each of these semaphores is released internally by the worker thread when the work is completed. The start + // semaphore is also used to wake up the worker thread. + if (!mal_event_create(pContext, &pDevice->wakeupEvent)) { + mal_mutex_delete(pContext, &pDevice->lock); + return mal_post_error(pDevice, "Failed to create worker thread wakeup event.", MAL_FAILED_TO_CREATE_EVENT); + } + if (!mal_event_create(pContext, &pDevice->startEvent)) { + mal_event_delete(pContext, &pDevice->wakeupEvent); + mal_mutex_delete(pContext, &pDevice->lock); + return mal_post_error(pDevice, "Failed to create worker thread start event.", MAL_FAILED_TO_CREATE_EVENT); + } + if (!mal_event_create(pContext, &pDevice->stopEvent)) { + mal_event_delete(pContext, &pDevice->startEvent); + mal_event_delete(pContext, &pDevice->wakeupEvent); + mal_mutex_delete(pContext, &pDevice->lock); + return mal_post_error(pDevice, "Failed to create worker thread stop event.", MAL_FAILED_TO_CREATE_EVENT); + } + + + mal_result result = MAL_NO_BACKEND; + switch (pContext->backend) + { + #ifdef MAL_ENABLE_WASAPI + case mal_backend_wasapi: + { + result = mal_device_init__wasapi(pContext, type, pDeviceID, &config, pDevice); + } break; + #endif + #ifdef MAL_ENABLE_DSOUND + case mal_backend_dsound: + { + result = mal_device_init__dsound(pContext, type, pDeviceID, &config, pDevice); + } break; + #endif + #ifdef MAL_ENABLE_WINMM + case mal_backend_winmm: + { + result = mal_device_init__winmm(pContext, type, pDeviceID, &config, pDevice); + } break; + #endif + #ifdef MAL_ENABLE_ALSA + case mal_backend_alsa: + { + result = mal_device_init__alsa(pContext, type, pDeviceID, &config, pDevice); + } break; + #endif + #ifdef MAL_ENABLE_OSS + case mal_backend_oss: + { + result = mal_device_init__oss(pContext, type, pDeviceID, &config, pDevice); + } break; + #endif + #ifdef MAL_ENABLE_OPENSL + case mal_backend_opensl: + { + result = mal_device_init__opensl(pContext, type, pDeviceID, &config, pDevice); + } break; + #endif + #ifdef MAL_ENABLE_OPENAL + case mal_backend_openal: + { + result = mal_device_init__openal(pContext, type, pDeviceID, &config, pDevice); + } break; + #endif + #ifdef MAL_ENABLE_NULL + case mal_backend_null: + { + result = mal_device_init__null(pContext, type, pDeviceID, &config, pDevice); + } break; + #endif + + default: break; + } + + if (result != MAL_SUCCESS) { + return MAL_NO_BACKEND; // The error message will have been posted with mal_post_error() by the source of the error so don't bother calling it here. + } + + + // We need a DSP object which is where samples are moved through in order to convert them to the + // format required by the backend. + mal_dsp_config dspConfig; + dspConfig.cacheSizeInFrames = pDevice->bufferSizeInFrames; + if (type == mal_device_type_playback) { + dspConfig.formatIn = pDevice->format; + dspConfig.channelsIn = pDevice->channels; + dspConfig.sampleRateIn = pDevice->sampleRate; + mal_copy_memory(dspConfig.channelMapIn, pDevice->channelMap, sizeof(dspConfig.channelMapIn)); + dspConfig.formatOut = pDevice->internalFormat; + dspConfig.channelsOut = pDevice->internalChannels; + dspConfig.sampleRateOut = pDevice->internalSampleRate; + mal_copy_memory(dspConfig.channelMapOut, pDevice->internalChannelMap, sizeof(dspConfig.channelMapOut)); + mal_dsp_init(&dspConfig, mal_device__on_read_from_client, pDevice, &pDevice->dsp); + } else { + dspConfig.formatIn = pDevice->internalFormat; + dspConfig.channelsIn = pDevice->internalChannels; + dspConfig.sampleRateIn = pDevice->internalSampleRate; + mal_copy_memory(dspConfig.channelMapIn, pDevice->internalChannelMap, sizeof(dspConfig.channelMapIn)); + dspConfig.formatOut = pDevice->format; + dspConfig.channelsOut = pDevice->channels; + dspConfig.sampleRateOut = pDevice->sampleRate; + mal_copy_memory(dspConfig.channelMapOut, pDevice->channelMap, sizeof(dspConfig.channelMapOut)); + mal_dsp_init(&dspConfig, mal_device__on_read_from_device, pDevice, &pDevice->dsp); + } + + + + + // Some backends don't require the worker thread. + if (pContext->backend != mal_backend_opensl) { + // The worker thread. + if (!mal_thread_create(pContext, &pDevice->thread, mal_worker_thread, pDevice)) { + mal_device_uninit(pDevice); + return mal_post_error(pDevice, "Failed to create worker thread.", MAL_FAILED_TO_CREATE_THREAD); + } + + // Wait for the worker thread to put the device into it's stopped state for real. + mal_event_wait(pContext, &pDevice->stopEvent); + } else { + mal_device__set_state(pDevice, MAL_STATE_STOPPED); + } + + mal_assert(mal_device__get_state(pDevice) == MAL_STATE_STOPPED); + return MAL_SUCCESS; +} + +void mal_device_uninit(mal_device* pDevice) +{ + if (!mal_device__is_initialized(pDevice)) return; + + // Make sure the device is stopped first. The backends will probably handle this naturally, + // but I like to do it explicitly for my own sanity. + if (mal_device_is_started(pDevice)) { + while (mal_device_stop(pDevice) == MAL_DEVICE_BUSY) { + mal_sleep(1); + } + } + + // Putting the device into an uninitialized state will make the worker thread return. + mal_device__set_state(pDevice, MAL_STATE_UNINITIALIZED); + + // Wake up the worker thread and wait for it to properly terminate. + if (pDevice->pContext->backend != mal_backend_opensl) { + mal_event_signal(pDevice->pContext, &pDevice->wakeupEvent); + mal_thread_wait(pDevice->pContext, &pDevice->thread); + } + + mal_event_delete(pDevice->pContext, &pDevice->stopEvent); + mal_event_delete(pDevice->pContext, &pDevice->startEvent); + mal_event_delete(pDevice->pContext, &pDevice->wakeupEvent); + mal_mutex_delete(pDevice->pContext, &pDevice->lock); + +#ifdef MAL_ENABLE_WASAPI + if (pDevice->pContext->backend == mal_backend_wasapi) { + mal_device_uninit__wasapi(pDevice); + } +#endif +#ifdef MAL_ENABLE_DSOUND + if (pDevice->pContext->backend == mal_backend_dsound) { + mal_device_uninit__dsound(pDevice); + } +#endif +#ifdef MAL_ENABLE_WINMM + if (pDevice->pContext->backend == mal_backend_winmm) { + mal_device_uninit__winmm(pDevice); + } +#endif +#ifdef MAL_ENABLE_ALSA + if (pDevice->pContext->backend == mal_backend_alsa) { + mal_device_uninit__alsa(pDevice); + } +#endif +#ifdef MAL_ENABLE_OSS + if (pDevice->pContext->backend == mal_backend_oss) { + mal_device_uninit__oss(pDevice); + } +#endif +#ifdef MAL_ENABLE_OPENSL + if (pDevice->pContext->backend == mal_backend_opensl) { + mal_device_uninit__opensl(pDevice); + } +#endif +#ifdef MAL_ENABLE_OPENAL + if (pDevice->pContext->backend == mal_backend_openal) { + mal_device_uninit__openal(pDevice); + } +#endif +#ifdef MAL_ENABLE_NULL + if (pDevice->pContext->backend == mal_backend_null) { + mal_device_uninit__null(pDevice); + } +#endif + + mal_zero_object(pDevice); +} + +void mal_device_set_recv_callback(mal_device* pDevice, mal_recv_proc proc) +{ + if (pDevice == NULL) return; + mal_atomic_exchange_ptr(&pDevice->onRecv, proc); +} + +void mal_device_set_send_callback(mal_device* pDevice, mal_send_proc proc) +{ + if (pDevice == NULL) return; + mal_atomic_exchange_ptr(&pDevice->onSend, proc); +} + +void mal_device_set_stop_callback(mal_device* pDevice, mal_stop_proc proc) +{ + if (pDevice == NULL) return; + mal_atomic_exchange_ptr(&pDevice->onStop, proc); +} + +mal_result mal_device_start(mal_device* pDevice) +{ + if (pDevice == NULL) return mal_post_error(pDevice, "mal_device_start() called with invalid arguments (pDevice == NULL).", MAL_INVALID_ARGS); + if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) return mal_post_error(pDevice, "mal_device_start() called for an uninitialized device.", MAL_DEVICE_NOT_INITIALIZED); + + mal_result result = MAL_ERROR; + mal_mutex_lock(pDevice->pContext, &pDevice->lock); + { + // Be a bit more descriptive if the device is already started or is already in the process of starting. This is likely + // a bug with the application. + if (mal_device__get_state(pDevice) == MAL_STATE_STARTING) { + mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + return mal_post_error(pDevice, "mal_device_start() called while another thread is already starting it.", MAL_DEVICE_ALREADY_STARTING); + } + if (mal_device__get_state(pDevice) == MAL_STATE_STARTED) { + mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + return mal_post_error(pDevice, "mal_device_start() called for a device that's already started.", MAL_DEVICE_ALREADY_STARTED); + } + + // The device needs to be in a stopped state. If it's not, we just let the caller know the device is busy. + if (mal_device__get_state(pDevice) != MAL_STATE_STOPPED) { + mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + return mal_post_error(pDevice, "mal_device_start() called while another thread is in the process of stopping it.", MAL_DEVICE_BUSY); + } + + mal_device__set_state(pDevice, MAL_STATE_STARTING); + + // Asynchronous backends need to be handled differently. +#ifdef MAL_ENABLE_OPENSL + if (pDevice->pContext->backend == mal_backend_opensl) { + mal_device__start_backend__opensl(pDevice); + mal_device__set_state(pDevice, MAL_STATE_STARTED); + } else +#endif + // Synchronous backends. + { + mal_event_signal(pDevice->pContext, &pDevice->wakeupEvent); + + // Wait for the worker thread to finish starting the device. Note that the worker thread will be the one + // who puts the device into the started state. Don't call mal_device__set_state() here. + mal_event_wait(pDevice->pContext, &pDevice->startEvent); + result = pDevice->workResult; + } + } + mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + + return result; +} + +mal_result mal_device_stop(mal_device* pDevice) +{ + if (pDevice == NULL) return mal_post_error(pDevice, "mal_device_stop() called with invalid arguments (pDevice == NULL).", MAL_INVALID_ARGS); + if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) return mal_post_error(pDevice, "mal_device_stop() called for an uninitialized device.", MAL_DEVICE_NOT_INITIALIZED); + + mal_result result = MAL_ERROR; + mal_mutex_lock(pDevice->pContext, &pDevice->lock); + { + // Be a bit more descriptive if the device is already stopped or is already in the process of stopping. This is likely + // a bug with the application. + if (mal_device__get_state(pDevice) == MAL_STATE_STOPPING) { + mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + return mal_post_error(pDevice, "mal_device_stop() called while another thread is already stopping it.", MAL_DEVICE_ALREADY_STOPPING); + } + if (mal_device__get_state(pDevice) == MAL_STATE_STOPPED) { + mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + return mal_post_error(pDevice, "mal_device_stop() called for a device that's already stopped.", MAL_DEVICE_ALREADY_STOPPED); + } + + // The device needs to be in a started state. If it's not, we just let the caller know the device is busy. + if (mal_device__get_state(pDevice) != MAL_STATE_STARTED) { + mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + return mal_post_error(pDevice, "mal_device_stop() called while another thread is in the process of starting it.", MAL_DEVICE_BUSY); + } + + mal_device__set_state(pDevice, MAL_STATE_STOPPING); + + // There's no need to wake up the thread like we do when starting. + + // Asynchronous backends need to be handled differently. +#ifdef MAL_ENABLE_OPENSL + if (pDevice->pContext->backend == mal_backend_opensl) { + mal_device__stop_backend__opensl(pDevice); + } else +#endif + // Synchronous backends. + { + // When we get here the worker thread is likely in a wait state while waiting for the backend device to deliver or request + // audio data. We need to force these to return as quickly as possible. + mal_device__break_main_loop(pDevice); + + // We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be + // the one who puts the device into the stopped state. Don't call mal_device__set_state() here. + mal_event_wait(pDevice->pContext, &pDevice->stopEvent); + result = MAL_SUCCESS; + } + } + mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + + return result; +} + +mal_bool32 mal_device_is_started(mal_device* pDevice) +{ + if (pDevice == NULL) return MAL_FALSE; + return mal_device__get_state(pDevice) == MAL_STATE_STARTED; +} + +mal_uint32 mal_device_get_buffer_size_in_bytes(mal_device* pDevice) +{ + if (pDevice == NULL) return 0; + return pDevice->bufferSizeInFrames * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); +} + +mal_uint32 mal_get_sample_size_in_bytes(mal_format format) +{ + mal_uint32 sizes[] = { + 0, // unknown + 1, // u8 + 2, // s16 + 3, // s24 + 4, // s32 + 4, // f32 + }; + return sizes[format]; +} + +mal_context_config mal_context_config_init(mal_log_proc onLog) +{ + mal_context_config config; + mal_zero_object(&config); + + config.onLog = onLog; + + return config; +} + +mal_device_config mal_device_config_init(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_recv_proc onRecvCallback, mal_send_proc onSendCallback) +{ + mal_device_config config; + mal_zero_object(&config); + + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.onRecvCallback = onRecvCallback; + config.onSendCallback = onSendCallback; + + switch (channels) + { + case 1: + { + config.channelMap[0] = MAL_CHANNEL_FRONT_CENTER; + } break; + + case 2: + { + config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + } break; + + case 3: + { + config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + config.channelMap[2] = MAL_CHANNEL_LFE; + } break; + + case 4: + { + config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + config.channelMap[2] = MAL_CHANNEL_BACK_LEFT; + config.channelMap[3] = MAL_CHANNEL_BACK_RIGHT; + } break; + + case 5: + { + config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + config.channelMap[2] = MAL_CHANNEL_BACK_LEFT; + config.channelMap[3] = MAL_CHANNEL_BACK_RIGHT; + config.channelMap[4] = MAL_CHANNEL_LFE; + } break; + + case 6: + { + config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + config.channelMap[2] = MAL_CHANNEL_FRONT_CENTER; + config.channelMap[3] = MAL_CHANNEL_LFE; + config.channelMap[4] = MAL_CHANNEL_BACK_LEFT; + config.channelMap[5] = MAL_CHANNEL_BACK_RIGHT; + } break; + + case 8: + { + config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + config.channelMap[2] = MAL_CHANNEL_FRONT_CENTER; + config.channelMap[3] = MAL_CHANNEL_LFE; + config.channelMap[4] = MAL_CHANNEL_BACK_LEFT; + config.channelMap[5] = MAL_CHANNEL_BACK_RIGHT; + config.channelMap[6] = MAL_CHANNEL_SIDE_LEFT; + config.channelMap[7] = MAL_CHANNEL_SIDE_RIGHT; + } break; + + default: + { + // Just leave it all blank in this case. This will use the same mapping as the device's native mapping. + } break; + } + + return config; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// SRC +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void mal_src_cache_init(mal_src* pSRC, mal_src_cache* pCache) +{ + mal_assert(pSRC != NULL); + mal_assert(pCache != NULL); + + pCache->pSRC = pSRC; + pCache->cachedFrameCount = 0; + pCache->iNextFrame = 0; +} + +mal_uint32 mal_src_cache_read_frames(mal_src_cache* pCache, mal_uint32 frameCount, float* pFramesOut) +{ + mal_assert(pCache != NULL); + mal_assert(pCache->pSRC != NULL); + mal_assert(pCache->pSRC->onRead != NULL); + mal_assert(frameCount > 0); + mal_assert(pFramesOut != NULL); + + mal_uint32 channels = pCache->pSRC->config.channels; + + mal_uint32 totalFramesRead = 0; + while (frameCount > 0) { + // If there's anything in memory go ahead and copy that over first. + mal_uint32 framesRemainingInMemory = pCache->cachedFrameCount - pCache->iNextFrame; + mal_uint32 framesToReadFromMemory = frameCount; + if (framesToReadFromMemory > framesRemainingInMemory) { + framesToReadFromMemory = framesRemainingInMemory; + } + + mal_copy_memory(pFramesOut, pCache->pCachedFrames + pCache->iNextFrame*channels, framesToReadFromMemory * channels * sizeof(float)); + pCache->iNextFrame += framesToReadFromMemory; + + totalFramesRead += framesToReadFromMemory; + frameCount -= framesToReadFromMemory; + if (frameCount == 0) { + break; + } + + + // At this point there are still more frames to read from the client, so we'll need to reload the cache with fresh data. + mal_assert(frameCount > 0); + pFramesOut += framesToReadFromMemory * channels; + + pCache->iNextFrame = 0; + pCache->cachedFrameCount = 0; + if (pCache->pSRC->config.formatIn == mal_format_f32) { + // No need for a conversion - read straight into the cache. + mal_uint32 framesToReadFromClient = mal_countof(pCache->pCachedFrames) / pCache->pSRC->config.channels; + if (framesToReadFromClient > pCache->pSRC->config.cacheSizeInFrames) { + framesToReadFromClient = pCache->pSRC->config.cacheSizeInFrames; + } + + pCache->cachedFrameCount = pCache->pSRC->onRead(framesToReadFromClient, pCache->pCachedFrames, pCache->pSRC->pUserData); + } else { + // A format conversion is required which means we need to use an intermediary buffer. + mal_uint8 pIntermediaryBuffer[sizeof(pCache->pCachedFrames)]; + mal_uint32 framesToReadFromClient = mal_min(mal_buffer_frame_capacity(pIntermediaryBuffer, channels, pCache->pSRC->config.formatIn), mal_buffer_frame_capacity(pCache->pCachedFrames, channels, mal_format_f32)); + if (framesToReadFromClient > pCache->pSRC->config.cacheSizeInFrames) { + framesToReadFromClient = pCache->pSRC->config.cacheSizeInFrames; + } + + pCache->cachedFrameCount = pCache->pSRC->onRead(framesToReadFromClient, pIntermediaryBuffer, pCache->pSRC->pUserData); + + // Convert to f32. + mal_pcm_convert(pCache->pCachedFrames, mal_format_f32, pIntermediaryBuffer, pCache->pSRC->config.formatIn, pCache->cachedFrameCount * channels); + } + + + // Get out of this loop if nothing was able to be retrieved. + if (pCache->cachedFrameCount == 0) { + break; + } + } + + return totalFramesRead; +} + + +mal_uint32 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut); +mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut); + +mal_result mal_src_init(mal_src_config* pConfig, mal_src_read_proc onRead, void* pUserData, mal_src* pSRC) +{ + if (pSRC == NULL) return MAL_INVALID_ARGS; + mal_zero_object(pSRC); + + if (pConfig == NULL || onRead == NULL) return MAL_INVALID_ARGS; + if (pConfig->channels == 0 || pConfig->channels > MAL_MAX_CHANNELS) return MAL_INVALID_ARGS; + + pSRC->config = *pConfig; + pSRC->onRead = onRead; + pSRC->pUserData = pUserData; + + // If the in and out sample rates are the same, fall back to the passthrough algorithm. + if (pSRC->config.sampleRateIn == pSRC->config.sampleRateOut) { + pSRC->config.algorithm = mal_src_algorithm_none; + } + + if (pSRC->config.cacheSizeInFrames > MAL_SRC_CACHE_SIZE_IN_FRAMES || pSRC->config.cacheSizeInFrames == 0) { + pSRC->config.cacheSizeInFrames = MAL_SRC_CACHE_SIZE_IN_FRAMES; + } + + pSRC->ratio = (float)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut; + + mal_src_cache_init(pSRC, &pSRC->cache); + return MAL_SUCCESS; +} + +mal_uint32 mal_src_read_frames(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut) +{ + if (pSRC == NULL || frameCount == 0 || pFramesOut == NULL) return 0; + + // Could just use a function pointer instead of a switch for this... + switch (pSRC->config.algorithm) + { + case mal_src_algorithm_none: return mal_src_read_frames_passthrough(pSRC, frameCount, pFramesOut); + case mal_src_algorithm_linear: return mal_src_read_frames_linear(pSRC, frameCount, pFramesOut); + default: return 0; + } +} + +mal_uint32 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut) +{ + mal_assert(pSRC != NULL); + mal_assert(frameCount > 0); + mal_assert(pFramesOut != NULL); + + // Fast path. No need for data conversion - just pass right through. + if (pSRC->config.formatIn == pSRC->config.formatOut) { + return pSRC->onRead(frameCount, pFramesOut, pSRC->pUserData); + } + + // Slower path. Need to do a format conversion. + mal_uint32 totalFramesRead = 0; + while (frameCount > 0) { + mal_uint8 pStagingBuffer[MAL_MAX_CHANNELS * 2048]; + mal_uint32 stagingBufferSizeInFrames = sizeof(pStagingBuffer) / mal_get_sample_size_in_bytes(pSRC->config.formatIn) / pSRC->config.channels; + mal_uint32 framesToRead = stagingBufferSizeInFrames; + if (framesToRead > frameCount) { + framesToRead = frameCount; + } + + mal_uint32 framesRead = pSRC->onRead(framesToRead, pStagingBuffer, pSRC->pUserData); + if (framesRead == 0) { + break; + } + + mal_pcm_convert(pFramesOut, pSRC->config.formatOut, pStagingBuffer, pSRC->config.formatIn, framesRead * pSRC->config.channels); + + pFramesOut = (mal_uint8*)pFramesOut + (framesRead * pSRC->config.channels * mal_get_sample_size_in_bytes(pSRC->config.formatOut)); + frameCount -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut) +{ + mal_assert(pSRC != NULL); + mal_assert(frameCount > 0); + mal_assert(pFramesOut != NULL); + + // For linear SRC, the bin is only 2 frames: 1 prior, 1 future. + + // Load the bin if necessary. + if (!pSRC->linear.isPrevFramesLoaded) { + mal_uint32 framesRead = mal_src_cache_read_frames(&pSRC->cache, 1, pSRC->bin); + if (framesRead == 0) { + return 0; + } + pSRC->linear.isPrevFramesLoaded = MAL_TRUE; + } + if (!pSRC->linear.isNextFramesLoaded) { + mal_uint32 framesRead = mal_src_cache_read_frames(&pSRC->cache, 1, pSRC->bin + pSRC->config.channels); + if (framesRead == 0) { + return 0; + } + pSRC->linear.isNextFramesLoaded = MAL_TRUE; + } + + float factor = pSRC->ratio; + + mal_uint32 totalFramesRead = 0; + while (frameCount > 0) { + // The bin is where the previous and next frames are located. + float* pPrevFrame = pSRC->bin; + float* pNextFrame = pSRC->bin + pSRC->config.channels; + + float pFrame[MAL_MAX_CHANNELS]; + mal_blend_f32(pFrame, pPrevFrame, pNextFrame, pSRC->linear.alpha, pSRC->config.channels); + + pSRC->linear.alpha += factor; + + // The new alpha value is how we determine whether or not we need to read fresh frames. + mal_uint32 framesToReadFromClient = (mal_uint32)pSRC->linear.alpha; + pSRC->linear.alpha = pSRC->linear.alpha - framesToReadFromClient; + + for (mal_uint32 i = 0; i < framesToReadFromClient; ++i) { + for (mal_uint32 j = 0; j < pSRC->config.channels; ++j) { + pPrevFrame[j] = pNextFrame[j]; + } + + mal_uint32 framesRead = mal_src_cache_read_frames(&pSRC->cache, 1, pNextFrame); + if (framesRead == 0) { + for (mal_uint32 j = 0; j < pSRC->config.channels; ++j) { + pNextFrame[j] = 0; + } + + pSRC->linear.isNextFramesLoaded = MAL_FALSE; + break; + } + } + + mal_pcm_convert(pFramesOut, pSRC->config.formatOut, pFrame, mal_format_f32, 1 * pSRC->config.channels); + + pFramesOut = (mal_uint8*)pFramesOut + (1 * pSRC->config.channels * mal_get_sample_size_in_bytes(pSRC->config.formatOut)); + frameCount -= 1; + totalFramesRead += 1; + + // If there's no frames available we need to get out of this loop. + if (!pSRC->linear.isNextFramesLoaded) { + break; + } + } + + return totalFramesRead; +} + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// FORMAT CONVERSION +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void mal_pcm_u8_to_s16(short* pOut, const unsigned char* pIn, unsigned int count); +void mal_pcm_u8_to_s24(void* pOut, const unsigned char* pIn, unsigned int count); +void mal_pcm_u8_to_s32(int* pOut, const unsigned char* pIn, unsigned int count); +void mal_pcm_u8_to_f32(float* pOut, const unsigned char* pIn, unsigned int count); +void mal_pcm_s16_to_u8(unsigned char* pOut, const short* pIn, unsigned int count); +void mal_pcm_s16_to_s24(void* pOut, const short* pIn, unsigned int count); +void mal_pcm_s16_to_s32(int* pOut, const short* pIn, unsigned int count); +void mal_pcm_s16_to_f32(float* pOut, const short* pIn, unsigned int count); +void mal_pcm_s24_to_u8(unsigned char* pOut, const void* pIn, unsigned int count); +void mal_pcm_s24_to_s16(short* pOut, const void* pIn, unsigned int count); +void mal_pcm_s24_to_s32(int* pOut, const void* pIn, unsigned int count); +void mal_pcm_s24_to_f32(float* pOut, const void* pIn, unsigned int count); +void mal_pcm_s32_to_u8(unsigned char* pOut, const int* pIn, unsigned int count); +void mal_pcm_s32_to_s16(short* pOut, const int* pIn, unsigned int count); +void mal_pcm_s32_to_s24(void* pOut, const int* pIn, unsigned int count); +void mal_pcm_s32_to_f32(float* pOut, const int* pIn, unsigned int count); +void mal_pcm_f32_to_u8(unsigned char* pOut, const float* pIn, unsigned int count); +void mal_pcm_f32_to_s16(short* pOut, const float* pIn, unsigned int count); +void mal_pcm_f32_to_s24(void* pOut, const float* pIn, unsigned int count); +void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count); + +void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_format formatIn, unsigned int sampleCount) +{ + if (formatOut == formatIn) { + mal_copy_memory(pOut, pIn, sampleCount * mal_get_sample_size_in_bytes(formatOut)); + return; + } + + switch (formatIn) + { + case mal_format_u8: + { + switch (formatOut) + { + case mal_format_s16: mal_pcm_u8_to_s16((short*)pOut, (const unsigned char*)pIn, sampleCount); return; + case mal_format_s24: mal_pcm_u8_to_s24( pOut, (const unsigned char*)pIn, sampleCount); return; + case mal_format_s32: mal_pcm_u8_to_s32( (int*)pOut, (const unsigned char*)pIn, sampleCount); return; + case mal_format_f32: mal_pcm_u8_to_f32((float*)pOut, (const unsigned char*)pIn, sampleCount); return; + default: break; + } + } break; + + case mal_format_s16: + { + switch (formatOut) + { + case mal_format_u8: mal_pcm_s16_to_u8( (unsigned char*)pOut, (const short*)pIn, sampleCount); return; + case mal_format_s24: mal_pcm_s16_to_s24( pOut, (const short*)pIn, sampleCount); return; + case mal_format_s32: mal_pcm_s16_to_s32( (int*)pOut, (const short*)pIn, sampleCount); return; + case mal_format_f32: mal_pcm_s16_to_f32( (float*)pOut, (const short*)pIn, sampleCount); return; + default: break; + } + } break; + + case mal_format_s24: + { + switch (formatOut) + { + case mal_format_u8: mal_pcm_s24_to_u8( (unsigned char*)pOut, pIn, sampleCount); return; + case mal_format_s16: mal_pcm_s24_to_s16( (short*)pOut, pIn, sampleCount); return; + case mal_format_s32: mal_pcm_s24_to_s32( (int*)pOut, pIn, sampleCount); return; + case mal_format_f32: mal_pcm_s24_to_f32( (float*)pOut, pIn, sampleCount); return; + default: break; + } + } break; + + case mal_format_s32: + { + switch (formatOut) + { + case mal_format_u8: mal_pcm_s32_to_u8( (unsigned char*)pOut, (const int*)pIn, sampleCount); return; + case mal_format_s16: mal_pcm_s32_to_s16( (short*)pOut, (const int*)pIn, sampleCount); return; + case mal_format_s24: mal_pcm_s32_to_s24( pOut, (const int*)pIn, sampleCount); return; + case mal_format_f32: mal_pcm_s32_to_f32( (float*)pOut, (const int*)pIn, sampleCount); return; + default: break; + } + } break; + + case mal_format_f32: + { + switch (formatOut) + { + case mal_format_u8: mal_pcm_f32_to_u8( (unsigned char*)pOut, (const float*)pIn, sampleCount); return; + case mal_format_s16: mal_pcm_f32_to_s16( (short*)pOut, (const float*)pIn, sampleCount); return; + case mal_format_s24: mal_pcm_f32_to_s24( pOut, (const float*)pIn, sampleCount); return; + case mal_format_s32: mal_pcm_f32_to_s32( (int*)pOut, (const float*)pIn, sampleCount); return; + default: break; + } + } break; + + default: break; + } +} + + +static void mal_rearrange_channels_u8(mal_uint8* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) +{ + mal_uint8 temp[MAL_MAX_CHANNELS]; + mal_copy_memory(temp, pFrame, sizeof(temp[0]) * channels); + + switch (channels) { + case 18: pFrame[17] = temp[channelMap[17]]; + case 17: pFrame[16] = temp[channelMap[16]]; + case 16: pFrame[15] = temp[channelMap[15]]; + case 15: pFrame[14] = temp[channelMap[14]]; + case 14: pFrame[13] = temp[channelMap[13]]; + case 13: pFrame[12] = temp[channelMap[12]]; + case 12: pFrame[11] = temp[channelMap[11]]; + case 11: pFrame[10] = temp[channelMap[10]]; + case 10: pFrame[ 9] = temp[channelMap[ 9]]; + case 9: pFrame[ 8] = temp[channelMap[ 8]]; + case 8: pFrame[ 7] = temp[channelMap[ 7]]; + case 7: pFrame[ 6] = temp[channelMap[ 6]]; + case 6: pFrame[ 5] = temp[channelMap[ 5]]; + case 5: pFrame[ 4] = temp[channelMap[ 4]]; + case 4: pFrame[ 3] = temp[channelMap[ 3]]; + case 3: pFrame[ 2] = temp[channelMap[ 2]]; + case 2: pFrame[ 1] = temp[channelMap[ 1]]; + case 1: pFrame[ 0] = temp[channelMap[ 0]]; + } +} + +static void mal_rearrange_channels_s16(mal_int16* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) +{ + mal_int16 temp[MAL_MAX_CHANNELS]; + mal_copy_memory(temp, pFrame, sizeof(temp[0]) * channels); + + switch (channels) { + case 18: pFrame[17] = temp[channelMap[17]]; + case 17: pFrame[16] = temp[channelMap[16]]; + case 16: pFrame[15] = temp[channelMap[15]]; + case 15: pFrame[14] = temp[channelMap[14]]; + case 14: pFrame[13] = temp[channelMap[13]]; + case 13: pFrame[12] = temp[channelMap[12]]; + case 12: pFrame[11] = temp[channelMap[11]]; + case 11: pFrame[10] = temp[channelMap[10]]; + case 10: pFrame[ 9] = temp[channelMap[ 9]]; + case 9: pFrame[ 8] = temp[channelMap[ 8]]; + case 8: pFrame[ 7] = temp[channelMap[ 7]]; + case 7: pFrame[ 6] = temp[channelMap[ 6]]; + case 6: pFrame[ 5] = temp[channelMap[ 5]]; + case 5: pFrame[ 4] = temp[channelMap[ 4]]; + case 4: pFrame[ 3] = temp[channelMap[ 3]]; + case 3: pFrame[ 2] = temp[channelMap[ 2]]; + case 2: pFrame[ 1] = temp[channelMap[ 1]]; + case 1: pFrame[ 0] = temp[channelMap[ 0]]; + } +} + +static void mal_rearrange_channels_s32(mal_int32* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) +{ + mal_int32 temp[MAL_MAX_CHANNELS]; + mal_copy_memory(temp, pFrame, sizeof(temp[0]) * channels); + + switch (channels) { + case 18: pFrame[17] = temp[channelMap[17]]; + case 17: pFrame[16] = temp[channelMap[16]]; + case 16: pFrame[15] = temp[channelMap[15]]; + case 15: pFrame[14] = temp[channelMap[14]]; + case 14: pFrame[13] = temp[channelMap[13]]; + case 13: pFrame[12] = temp[channelMap[12]]; + case 12: pFrame[11] = temp[channelMap[11]]; + case 11: pFrame[10] = temp[channelMap[10]]; + case 10: pFrame[ 9] = temp[channelMap[ 9]]; + case 9: pFrame[ 8] = temp[channelMap[ 8]]; + case 8: pFrame[ 7] = temp[channelMap[ 7]]; + case 7: pFrame[ 6] = temp[channelMap[ 6]]; + case 6: pFrame[ 5] = temp[channelMap[ 5]]; + case 5: pFrame[ 4] = temp[channelMap[ 4]]; + case 4: pFrame[ 3] = temp[channelMap[ 3]]; + case 3: pFrame[ 2] = temp[channelMap[ 2]]; + case 2: pFrame[ 1] = temp[channelMap[ 1]]; + case 1: pFrame[ 0] = temp[channelMap[ 0]]; + } +} + +static void mal_rearrange_channels_f32(float* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) +{ + float temp[MAL_MAX_CHANNELS]; + mal_copy_memory(temp, pFrame, sizeof(temp[0]) * channels); + + switch (channels) { + case 18: pFrame[17] = temp[channelMap[17]]; + case 17: pFrame[16] = temp[channelMap[16]]; + case 16: pFrame[15] = temp[channelMap[15]]; + case 15: pFrame[14] = temp[channelMap[14]]; + case 14: pFrame[13] = temp[channelMap[13]]; + case 13: pFrame[12] = temp[channelMap[12]]; + case 12: pFrame[11] = temp[channelMap[11]]; + case 11: pFrame[10] = temp[channelMap[10]]; + case 10: pFrame[ 9] = temp[channelMap[ 9]]; + case 9: pFrame[ 8] = temp[channelMap[ 8]]; + case 8: pFrame[ 7] = temp[channelMap[ 7]]; + case 7: pFrame[ 6] = temp[channelMap[ 6]]; + case 6: pFrame[ 5] = temp[channelMap[ 5]]; + case 5: pFrame[ 4] = temp[channelMap[ 4]]; + case 4: pFrame[ 3] = temp[channelMap[ 3]]; + case 3: pFrame[ 2] = temp[channelMap[ 2]]; + case 2: pFrame[ 1] = temp[channelMap[ 1]]; + case 1: pFrame[ 0] = temp[channelMap[ 0]]; + } +} + +static void mal_rearrange_channels_generic(void* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS], mal_format format) +{ + mal_uint32 sampleSizeInBytes = mal_get_sample_size_in_bytes(format); + + mal_uint8 temp[MAL_MAX_CHANNELS * 8]; // x8 to ensure it's large enough for all formats. + mal_copy_memory(temp, pFrame, sampleSizeInBytes * channels); + + switch (channels) { + case 18: mal_copy_memory((mal_uint8*)pFrame + (17 * sampleSizeInBytes), &temp[channelMap[17] * sampleSizeInBytes], sampleSizeInBytes); + case 17: mal_copy_memory((mal_uint8*)pFrame + (16 * sampleSizeInBytes), &temp[channelMap[16] * sampleSizeInBytes], sampleSizeInBytes); + case 16: mal_copy_memory((mal_uint8*)pFrame + (15 * sampleSizeInBytes), &temp[channelMap[15] * sampleSizeInBytes], sampleSizeInBytes); + case 15: mal_copy_memory((mal_uint8*)pFrame + (14 * sampleSizeInBytes), &temp[channelMap[14] * sampleSizeInBytes], sampleSizeInBytes); + case 14: mal_copy_memory((mal_uint8*)pFrame + (13 * sampleSizeInBytes), &temp[channelMap[13] * sampleSizeInBytes], sampleSizeInBytes); + case 13: mal_copy_memory((mal_uint8*)pFrame + (12 * sampleSizeInBytes), &temp[channelMap[12] * sampleSizeInBytes], sampleSizeInBytes); + case 12: mal_copy_memory((mal_uint8*)pFrame + (11 * sampleSizeInBytes), &temp[channelMap[11] * sampleSizeInBytes], sampleSizeInBytes); + case 11: mal_copy_memory((mal_uint8*)pFrame + (10 * sampleSizeInBytes), &temp[channelMap[10] * sampleSizeInBytes], sampleSizeInBytes); + case 10: mal_copy_memory((mal_uint8*)pFrame + ( 9 * sampleSizeInBytes), &temp[channelMap[ 9] * sampleSizeInBytes], sampleSizeInBytes); + case 9: mal_copy_memory((mal_uint8*)pFrame + ( 8 * sampleSizeInBytes), &temp[channelMap[ 8] * sampleSizeInBytes], sampleSizeInBytes); + case 8: mal_copy_memory((mal_uint8*)pFrame + ( 7 * sampleSizeInBytes), &temp[channelMap[ 7] * sampleSizeInBytes], sampleSizeInBytes); + case 7: mal_copy_memory((mal_uint8*)pFrame + ( 6 * sampleSizeInBytes), &temp[channelMap[ 6] * sampleSizeInBytes], sampleSizeInBytes); + case 6: mal_copy_memory((mal_uint8*)pFrame + ( 5 * sampleSizeInBytes), &temp[channelMap[ 5] * sampleSizeInBytes], sampleSizeInBytes); + case 5: mal_copy_memory((mal_uint8*)pFrame + ( 4 * sampleSizeInBytes), &temp[channelMap[ 4] * sampleSizeInBytes], sampleSizeInBytes); + case 4: mal_copy_memory((mal_uint8*)pFrame + ( 3 * sampleSizeInBytes), &temp[channelMap[ 3] * sampleSizeInBytes], sampleSizeInBytes); + case 3: mal_copy_memory((mal_uint8*)pFrame + ( 2 * sampleSizeInBytes), &temp[channelMap[ 2] * sampleSizeInBytes], sampleSizeInBytes); + case 2: mal_copy_memory((mal_uint8*)pFrame + ( 1 * sampleSizeInBytes), &temp[channelMap[ 1] * sampleSizeInBytes], sampleSizeInBytes); + case 1: mal_copy_memory((mal_uint8*)pFrame + ( 0 * sampleSizeInBytes), &temp[channelMap[ 0] * sampleSizeInBytes], sampleSizeInBytes); + } +} + +static void mal_rearrange_channels(void* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS], mal_format format) +{ + switch (format) + { + case mal_format_u8: mal_rearrange_channels_u8( (mal_uint8*)pFrame, channels, channelMap); break; + case mal_format_s16: mal_rearrange_channels_s16((mal_int16*)pFrame, channels, channelMap); break; + case mal_format_s32: mal_rearrange_channels_s32((mal_int32*)pFrame, channels, channelMap); break; + case mal_format_f32: mal_rearrange_channels_f32( (float*)pFrame, channels, channelMap); break; + default: mal_rearrange_channels_generic(pFrame, channels, channelMap, format); break; + } +} + +static void mal_dsp_mix_channels__dec(float* pFramesOut, mal_uint32 channelsOut, const mal_uint8 channelMapOut[MAL_MAX_CHANNELS], const float* pFramesIn, mal_uint32 channelsIn, const mal_uint8 channelMapIn[MAL_MAX_CHANNELS], mal_uint32 frameCount, mal_channel_mix_mode mode) +{ + mal_assert(pFramesOut != NULL); + mal_assert(channelsOut > 0); + mal_assert(pFramesIn != NULL); + mal_assert(channelsIn > 0); + mal_assert(channelsOut < channelsIn); + + (void)channelMapOut; + (void)channelMapIn; + + if (mode == mal_channel_mix_mode_basic) { + // Basic mode is where we just drop excess channels. + for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { + switch (channelsOut) { + case 17: pFramesOut[iFrame*channelsOut+16] = pFramesIn[iFrame*channelsIn+16]; + case 16: pFramesOut[iFrame*channelsOut+15] = pFramesIn[iFrame*channelsIn+15]; + case 15: pFramesOut[iFrame*channelsOut+14] = pFramesIn[iFrame*channelsIn+14]; + case 14: pFramesOut[iFrame*channelsOut+13] = pFramesIn[iFrame*channelsIn+13]; + case 13: pFramesOut[iFrame*channelsOut+12] = pFramesIn[iFrame*channelsIn+12]; + case 12: pFramesOut[iFrame*channelsOut+11] = pFramesIn[iFrame*channelsIn+11]; + case 11: pFramesOut[iFrame*channelsOut+10] = pFramesIn[iFrame*channelsIn+10]; + case 10: pFramesOut[iFrame*channelsOut+ 9] = pFramesIn[iFrame*channelsIn+ 9]; + case 9: pFramesOut[iFrame*channelsOut+ 8] = pFramesIn[iFrame*channelsIn+ 8]; + case 8: pFramesOut[iFrame*channelsOut+ 7] = pFramesIn[iFrame*channelsIn+ 7]; + case 7: pFramesOut[iFrame*channelsOut+ 6] = pFramesIn[iFrame*channelsIn+ 6]; + case 6: pFramesOut[iFrame*channelsOut+ 5] = pFramesIn[iFrame*channelsIn+ 5]; + case 5: pFramesOut[iFrame*channelsOut+ 4] = pFramesIn[iFrame*channelsIn+ 4]; + case 4: pFramesOut[iFrame*channelsOut+ 3] = pFramesIn[iFrame*channelsIn+ 3]; + case 3: pFramesOut[iFrame*channelsOut+ 2] = pFramesIn[iFrame*channelsIn+ 2]; + case 2: pFramesOut[iFrame*channelsOut+ 1] = pFramesIn[iFrame*channelsIn+ 1]; + case 1: pFramesOut[iFrame*channelsOut+ 0] = pFramesIn[iFrame*channelsIn+ 0]; + } + } + } else { + // Blend mode is where we just use simple averaging to blend based on spacial locality. + if (channelsOut == 1) { + for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { + float total = 0; + switch (channelsIn) { + case 18: total += pFramesIn[iFrame*channelsIn+17]; + case 17: total += pFramesIn[iFrame*channelsIn+16]; + case 16: total += pFramesIn[iFrame*channelsIn+15]; + case 15: total += pFramesIn[iFrame*channelsIn+14]; + case 14: total += pFramesIn[iFrame*channelsIn+13]; + case 13: total += pFramesIn[iFrame*channelsIn+12]; + case 12: total += pFramesIn[iFrame*channelsIn+11]; + case 11: total += pFramesIn[iFrame*channelsIn+10]; + case 10: total += pFramesIn[iFrame*channelsIn+ 9]; + case 9: total += pFramesIn[iFrame*channelsIn+ 8]; + case 8: total += pFramesIn[iFrame*channelsIn+ 7]; + case 7: total += pFramesIn[iFrame*channelsIn+ 6]; + case 6: total += pFramesIn[iFrame*channelsIn+ 5]; + case 5: total += pFramesIn[iFrame*channelsIn+ 4]; + case 4: total += pFramesIn[iFrame*channelsIn+ 3]; + case 3: total += pFramesIn[iFrame*channelsIn+ 2]; + case 2: total += pFramesIn[iFrame*channelsIn+ 1]; + case 1: total += pFramesIn[iFrame*channelsIn+ 0]; + } + + pFramesOut[iFrame+0] = total / channelsIn; + } + } else if (channelsOut == 2) { + // TODO: Implement proper stereo blending. + mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); + } else { + // Fall back to basic mode. + mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); + } + } +} + +static void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut, const mal_uint8 channelMapOut[MAL_MAX_CHANNELS], const float* pFramesIn, mal_uint32 channelsIn, const mal_uint8 channelMapIn[MAL_MAX_CHANNELS], mal_uint32 frameCount, mal_channel_mix_mode mode) +{ + mal_assert(pFramesOut != NULL); + mal_assert(channelsOut > 0); + mal_assert(pFramesIn != NULL); + mal_assert(channelsIn > 0); + mal_assert(channelsOut > channelsIn); + + (void)channelMapOut; + (void)channelMapIn; + + if (mode == mal_channel_mix_mode_basic) {\ + // Basic mode is where we just zero out extra channels. + for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { + switch (channelsIn) { + case 17: pFramesOut[iFrame*channelsOut+16] = pFramesIn[iFrame*channelsIn+16]; + case 16: pFramesOut[iFrame*channelsOut+15] = pFramesIn[iFrame*channelsIn+15]; + case 15: pFramesOut[iFrame*channelsOut+14] = pFramesIn[iFrame*channelsIn+14]; + case 14: pFramesOut[iFrame*channelsOut+13] = pFramesIn[iFrame*channelsIn+13]; + case 13: pFramesOut[iFrame*channelsOut+12] = pFramesIn[iFrame*channelsIn+12]; + case 12: pFramesOut[iFrame*channelsOut+11] = pFramesIn[iFrame*channelsIn+11]; + case 11: pFramesOut[iFrame*channelsOut+10] = pFramesIn[iFrame*channelsIn+10]; + case 10: pFramesOut[iFrame*channelsOut+ 9] = pFramesIn[iFrame*channelsIn+ 9]; + case 9: pFramesOut[iFrame*channelsOut+ 8] = pFramesIn[iFrame*channelsIn+ 8]; + case 8: pFramesOut[iFrame*channelsOut+ 7] = pFramesIn[iFrame*channelsIn+ 7]; + case 7: pFramesOut[iFrame*channelsOut+ 6] = pFramesIn[iFrame*channelsIn+ 6]; + case 6: pFramesOut[iFrame*channelsOut+ 5] = pFramesIn[iFrame*channelsIn+ 5]; + case 5: pFramesOut[iFrame*channelsOut+ 4] = pFramesIn[iFrame*channelsIn+ 4]; + case 4: pFramesOut[iFrame*channelsOut+ 3] = pFramesIn[iFrame*channelsIn+ 3]; + case 3: pFramesOut[iFrame*channelsOut+ 2] = pFramesIn[iFrame*channelsIn+ 2]; + case 2: pFramesOut[iFrame*channelsOut+ 1] = pFramesIn[iFrame*channelsIn+ 1]; + case 1: pFramesOut[iFrame*channelsOut+ 0] = pFramesIn[iFrame*channelsIn+ 0]; + } + + // Zero out extra channels. + switch (channelsOut - channelsIn) { + case 17: pFramesOut[iFrame*channelsOut+16] = 0; + case 16: pFramesOut[iFrame*channelsOut+15] = 0; + case 15: pFramesOut[iFrame*channelsOut+14] = 0; + case 14: pFramesOut[iFrame*channelsOut+13] = 0; + case 13: pFramesOut[iFrame*channelsOut+12] = 0; + case 12: pFramesOut[iFrame*channelsOut+11] = 0; + case 11: pFramesOut[iFrame*channelsOut+10] = 0; + case 10: pFramesOut[iFrame*channelsOut+ 9] = 0; + case 9: pFramesOut[iFrame*channelsOut+ 8] = 0; + case 8: pFramesOut[iFrame*channelsOut+ 7] = 0; + case 7: pFramesOut[iFrame*channelsOut+ 6] = 0; + case 6: pFramesOut[iFrame*channelsOut+ 5] = 0; + case 5: pFramesOut[iFrame*channelsOut+ 4] = 0; + case 4: pFramesOut[iFrame*channelsOut+ 3] = 0; + case 3: pFramesOut[iFrame*channelsOut+ 2] = 0; + case 2: pFramesOut[iFrame*channelsOut+ 1] = 0; + case 1: pFramesOut[iFrame*channelsOut+ 0] = 0; + } + } + } else { + // Using blended mixing mode. Basically this is just the mode where audio is distributed across all channels + // based on spacial locality. + if (channelsIn == 1) { + for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { + switch (channelsOut) { + case 18: pFramesOut[iFrame*channelsOut+17] = pFramesIn[iFrame*channelsIn+0]; + case 17: pFramesOut[iFrame*channelsOut+16] = pFramesIn[iFrame*channelsIn+0]; + case 16: pFramesOut[iFrame*channelsOut+15] = pFramesIn[iFrame*channelsIn+0]; + case 15: pFramesOut[iFrame*channelsOut+14] = pFramesIn[iFrame*channelsIn+0]; + case 14: pFramesOut[iFrame*channelsOut+13] = pFramesIn[iFrame*channelsIn+0]; + case 13: pFramesOut[iFrame*channelsOut+12] = pFramesIn[iFrame*channelsIn+0]; + case 12: pFramesOut[iFrame*channelsOut+11] = pFramesIn[iFrame*channelsIn+0]; + case 11: pFramesOut[iFrame*channelsOut+10] = pFramesIn[iFrame*channelsIn+0]; + case 10: pFramesOut[iFrame*channelsOut+ 9] = pFramesIn[iFrame*channelsIn+0]; + case 9: pFramesOut[iFrame*channelsOut+ 8] = pFramesIn[iFrame*channelsIn+0]; + case 8: pFramesOut[iFrame*channelsOut+ 7] = pFramesIn[iFrame*channelsIn+0]; + case 7: pFramesOut[iFrame*channelsOut+ 6] = pFramesIn[iFrame*channelsIn+0]; + case 6: pFramesOut[iFrame*channelsOut+ 5] = pFramesIn[iFrame*channelsIn+0]; + case 5: pFramesOut[iFrame*channelsOut+ 4] = pFramesIn[iFrame*channelsIn+0]; + case 4: pFramesOut[iFrame*channelsOut+ 3] = pFramesIn[iFrame*channelsIn+0]; + case 3: pFramesOut[iFrame*channelsOut+ 2] = pFramesIn[iFrame*channelsIn+0]; + case 2: pFramesOut[iFrame*channelsOut+ 1] = pFramesIn[iFrame*channelsIn+0]; + case 1: pFramesOut[iFrame*channelsOut+ 0] = pFramesIn[iFrame*channelsIn+0]; + } + } + } else if (channelsIn == 2) { + // TODO: Implement an optimized stereo conversion. + mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); + } else { + // Fall back to basic mixing mode. + mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); + } + } +} + +static void mal_dsp_mix_channels(float* pFramesOut, mal_uint32 channelsOut, const mal_uint8 channelMapOut[MAL_MAX_CHANNELS], const float* pFramesIn, mal_uint32 channelsIn, const mal_uint8 channelMapIn[MAL_MAX_CHANNELS], mal_uint32 frameCount, mal_channel_mix_mode mode) +{ + if (channelsIn < channelsOut) { + // Increasing the channel count. + mal_dsp_mix_channels__inc(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mode); + } else { + // Decreasing the channel count. + mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mode); + } +} + + +mal_uint32 mal_dsp__src_on_read(mal_uint32 frameCount, void* pFramesOut, void* pUserData) +{ + mal_dsp* pDSP = (mal_dsp*)pUserData; + mal_assert(pDSP != NULL); + + return pDSP->onRead(frameCount, pFramesOut, pDSP->pUserDataForOnRead); +} + +mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* pUserData, mal_dsp* pDSP) +{ + if (pDSP == NULL) return MAL_INVALID_ARGS; + mal_zero_object(pDSP); + pDSP->config = *pConfig; + pDSP->onRead = onRead; + pDSP->pUserDataForOnRead = pUserData; + + if (pDSP->config.cacheSizeInFrames > MAL_SRC_CACHE_SIZE_IN_FRAMES || pDSP->config.cacheSizeInFrames == 0) { + pDSP->config.cacheSizeInFrames = MAL_SRC_CACHE_SIZE_IN_FRAMES; + } + + if (pConfig->sampleRateIn != pConfig->sampleRateOut) { + pDSP->isSRCRequired = MAL_TRUE; + + mal_src_config srcConfig; + srcConfig.sampleRateIn = pConfig->sampleRateIn; + srcConfig.sampleRateOut = pConfig->sampleRateOut; + srcConfig.formatIn = pConfig->formatIn; + srcConfig.formatOut = mal_format_f32; + srcConfig.channels = pConfig->channelsIn; + srcConfig.algorithm = mal_src_algorithm_linear; + srcConfig.cacheSizeInFrames = pConfig->cacheSizeInFrames; + mal_result result = mal_src_init(&srcConfig, mal_dsp__src_on_read, pDSP, &pDSP->src); + if (result != MAL_SUCCESS) { + return result; + } + } + + + + pDSP->isChannelMappingRequired = MAL_FALSE; + if (pConfig->channelMapIn[0] != MAL_CHANNEL_NONE && pConfig->channelMapOut[0] != MAL_CHANNEL_NONE) { // <-- Channel mapping will be ignored if the first channel map is MAL_CHANNEL_NONE. + // When using channel mapping we need to figure out a shuffling table. The first thing to do is convert the input channel map + // so that it contains the same number of channels as the output channel count. + mal_uint32 iChannel; + mal_uint32 channelsMin = mal_min(pConfig->channelsIn, pConfig->channelsOut); + for (iChannel = 0; iChannel < channelsMin; ++iChannel) { + pDSP->channelMapInPostMix[iChannel] = pConfig->channelMapIn[iChannel]; + } + + // Any excess channels need to be filled with the relevant channels from the output channel map. Currently we're justing filling it with + // the first channels that are not present in the input channel map. + if (pConfig->channelsOut > pConfig->channelsIn) { + for (iChannel = pConfig->channelsIn; iChannel < pConfig->channelsOut; ++iChannel) { + mal_uint8 newChannel = MAL_CHANNEL_NONE; + for (mal_uint32 iChannelOut = 0; iChannelOut < pConfig->channelsOut; ++iChannelOut) { + mal_bool32 exists = MAL_FALSE; + for (mal_uint32 iChannelIn = 0; iChannelIn < pConfig->channelsIn; ++iChannelIn) { + if (pConfig->channelMapOut[iChannelOut] == pConfig->channelMapIn[iChannelIn]) { + exists = MAL_TRUE; + break; + } + } + + if (!exists) { + newChannel = pConfig->channelMapOut[iChannelOut]; + break; + } + } + + pDSP->channelMapInPostMix[iChannel] = newChannel; + } + } + + // We only need to do a channel mapping if the map after mixing is different to the final output map. + for (iChannel = 0; iChannel < pConfig->channelsOut; ++iChannel) { + if (pDSP->channelMapInPostMix[iChannel] != pConfig->channelMapOut[iChannel]) { + pDSP->isChannelMappingRequired = MAL_TRUE; + break; + } + } + + // Now we need to create the shuffling table. + if (pDSP->isChannelMappingRequired) { + for (mal_uint32 iChannelIn = 0; iChannelIn < pConfig->channelsOut; ++iChannelIn) { + for (mal_uint32 iChannelOut = 0; iChannelOut < pConfig->channelsOut; ++iChannelOut) { + if (pDSP->channelMapInPostMix[iChannelOut] == pConfig->channelMapOut[iChannelIn]) { + pDSP->channelShuffleTable[iChannelOut] = (mal_uint8)iChannelIn; + } + } + } + } + } + + if (pConfig->formatIn == pConfig->formatOut && pConfig->channelsIn == pConfig->channelsOut && pConfig->sampleRateIn == pConfig->sampleRateOut && !pDSP->isChannelMappingRequired) { + pDSP->isPassthrough = MAL_TRUE; + } else { + pDSP->isPassthrough = MAL_FALSE; + } + + return MAL_SUCCESS; +} + +mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut) +{ + if (pDSP == NULL || pFramesOut == NULL) return 0; + + // Fast path. + if (pDSP->isPassthrough) { + return pDSP->onRead(frameCount, pFramesOut, pDSP->pUserDataForOnRead); + } + + + // Slower path - where the real work is done. + mal_uint8 pFrames[2][MAL_MAX_CHANNELS * 512 * MAL_MAX_SAMPLE_SIZE_IN_BYTES]; + mal_format pFramesFormat[2]; + mal_uint32 iFrames = 0; // <-- Used as an index into pFrames and cycles between 0 and 1. + + mal_uint32 totalFramesRead = 0; + while (frameCount > 0) { + iFrames = 0; + + mal_uint32 framesToRead = mal_countof(pFrames[0]) / (mal_max(pDSP->config.channelsIn, pDSP->config.channelsOut) * MAL_MAX_SAMPLE_SIZE_IN_BYTES); + if (framesToRead > frameCount) { + framesToRead = frameCount; + } + + // The initial filling of sample data depends on whether or not we are using SRC. + mal_uint32 framesRead = 0; + if (pDSP->isSRCRequired) { + framesRead = mal_src_read_frames(&pDSP->src, framesToRead, pFrames[iFrames]); + pFramesFormat[iFrames] = pDSP->src.config.formatOut; // Should always be f32. + } else { + framesRead = pDSP->onRead(framesToRead, pFrames[iFrames], pDSP->pUserDataForOnRead); + pFramesFormat[iFrames] = pDSP->config.formatIn; + } + + if (framesRead == 0) { + break; + } + + + // Channel mixing. The input format must be in f32 which may require a conversion. + if (pDSP->config.channelsIn != pDSP->config.channelsOut) { + if (pFramesFormat[iFrames] != mal_format_f32) { + mal_pcm_convert(pFrames[(iFrames + 1) % 2], mal_format_f32, pFrames[iFrames], pDSP->config.formatIn, framesRead * pDSP->config.channelsIn); + iFrames = (iFrames + 1) % 2; + pFramesFormat[iFrames] = mal_format_f32; + } + + mal_dsp_mix_channels((float*)(pFrames[(iFrames + 1) % 2]), pDSP->config.channelsOut, pDSP->config.channelMapOut, (const float*)(pFrames[iFrames]), pDSP->config.channelsIn, pDSP->config.channelMapIn, framesRead, mal_channel_mix_mode_blend); + iFrames = (iFrames + 1) % 2; + pFramesFormat[iFrames] = mal_format_f32; + } + + + // Channel mapping. + if (pDSP->isChannelMappingRequired) { + for (mal_uint32 i = 0; i < framesRead; ++i) { + mal_rearrange_channels(pFrames[iFrames] + (i * pDSP->config.channelsOut * mal_get_sample_size_in_bytes(pFramesFormat[iFrames])), pDSP->config.channelsOut, pDSP->channelShuffleTable, pFramesFormat[iFrames]); + } + } + + + // Final conversion to output format. + mal_pcm_convert(pFramesOut, pDSP->config.formatOut, pFrames[iFrames], pFramesFormat[iFrames], framesRead * pDSP->config.channelsOut); + + pFramesOut = (mal_uint8*)pFramesOut + (framesRead * pDSP->config.channelsOut * mal_get_sample_size_in_bytes(pDSP->config.formatOut)); + frameCount -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + + +mal_uint32 mal_calculate_frame_count_after_src(mal_uint32 sampleRateOut, mal_uint32 sampleRateIn, mal_uint32 frameCountIn) +{ + double srcRatio = (double)sampleRateOut / sampleRateIn; + double frameCountOutF = frameCountIn * srcRatio; + + mal_uint32 frameCountOut = (mal_uint32)frameCountOutF; + + // If the output frame count is fractional, make sure we add an extra frame to ensure there's enough room for that last sample. + if ((frameCountOutF - frameCountOut) > 0.0) { + frameCountOut += 1; + } + + return frameCountOut; +} + +typedef struct +{ + const void* pDataIn; + mal_format formatIn; + mal_uint32 channelsIn; + mal_uint32 totalFrameCount; + mal_uint32 iNextFrame; +} mal_convert_frames__data; + +mal_uint32 mal_convert_frames__on_read(mal_uint32 frameCount, void* pFramesOut, void* pUserData) +{ + mal_convert_frames__data* pData = (mal_convert_frames__data*)pUserData; + mal_assert(pData != NULL); + mal_assert(pData->totalFrameCount >= pData->iNextFrame); + + mal_uint32 framesToRead = frameCount; + mal_uint32 framesRemaining = (pData->totalFrameCount - pData->iNextFrame); + if (framesToRead > framesRemaining) { + framesToRead = framesRemaining; + } + + mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(pData->formatIn) * pData->channelsIn; + mal_copy_memory(pFramesOut, (const mal_uint8*)pData->pDataIn + (frameSizeInBytes * pData->iNextFrame), frameSizeInBytes * framesToRead); + + pData->iNextFrame += framesToRead; + return framesToRead; +} + +mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut, const void* pIn, mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_uint32 frameCountIn) +{ + if (frameCountIn == 0) { + return 0; + } + + mal_uint32 frameCountOut = mal_calculate_frame_count_after_src(sampleRateOut, sampleRateIn, frameCountIn); + if (pOut == NULL) { + return frameCountOut; + } + + mal_convert_frames__data data; + data.pDataIn = pIn; + data.formatIn = formatIn; + data.channelsIn = channelsIn; + data.totalFrameCount = frameCountIn; + data.iNextFrame = 0; + + mal_dsp_config config; + mal_zero_object(&config); + config.formatIn = formatIn; + config.channelsIn = channelsIn; + config.sampleRateIn = sampleRateIn; + config.formatOut = formatOut; + config.channelsOut = channelsOut; + config.sampleRateOut = sampleRateOut; + + mal_dsp dsp; + if (mal_dsp_init(&config, mal_convert_frames__on_read, &data, &dsp) != MAL_SUCCESS) { + return 0; + } + + return mal_dsp_read_frames(&dsp, frameCountOut, pOut); +} + + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Miscellaneous Helpers +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void mal_blend_f32(float* pOut, float* pInA, float* pInB, float factor, mal_uint32 channels) +{ + for (mal_uint32 i = 0; i < channels; ++i) { + pOut[i] = mal_mix_f32(pInA[i], pInB[i], factor); + } +} + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// +// +// AUTO-GENERATED +// +// +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// FORMAT CONVERSION +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if 0 +#include "tools/malgen/bin/malgen_test0.c" +#else +void mal_pcm_u8_to_s16(short* pOut, const unsigned char* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + r = x - 128; + r = r << 8; + pOut[i] = (short)r; + } +} + +void mal_pcm_u8_to_s24(void* pOut, const unsigned char* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + r = x - 128; + r = r << 16; + ((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16); + } +} + +void mal_pcm_u8_to_s32(int* pOut, const unsigned char* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + r = x - 128; + r = r << 24; + pOut[i] = (int)r; + } +} + +void mal_pcm_u8_to_f32(float* pOut, const unsigned char* pIn, unsigned int count) +{ + float r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + r = x * 0.00784313725490196078f; + r = r - 1; + pOut[i] = (float)r; + } +} + +void mal_pcm_s16_to_u8(unsigned char* pOut, const short* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + r = x >> 8; + r = r + 128; + pOut[i] = (unsigned char)r; + } +} + +void mal_pcm_s16_to_s24(void* pOut, const short* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + r = x << 8; + ((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16); + } +} + +void mal_pcm_s16_to_s32(int* pOut, const short* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + r = x << 16; + pOut[i] = (int)r; + } +} + +void mal_pcm_s16_to_f32(float* pOut, const short* pIn, unsigned int count) +{ + float r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + r = (float)(x + 32768); + r = r * 0.00003051804379339284f; + r = r - 1; + pOut[i] = (float)r; + } +} + +void mal_pcm_s24_to_u8(unsigned char* pOut, const void* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8; + r = x >> 16; + r = r + 128; + pOut[i] = (unsigned char)r; + } +} + +void mal_pcm_s24_to_s16(short* pOut, const void* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8; + r = x >> 8; + pOut[i] = (short)r; + } +} + +void mal_pcm_s24_to_s32(int* pOut, const void* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8; + r = x << 8; + pOut[i] = (int)r; + } +} + +void mal_pcm_s24_to_f32(float* pOut, const void* pIn, unsigned int count) +{ + float r; + for (unsigned int i = 0; i < count; ++i) { + int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8; + r = (float)(x + 8388608); + r = r * 0.00000011920929665621f; + r = r - 1; + pOut[i] = (float)r; + } +} + +void mal_pcm_s32_to_u8(unsigned char* pOut, const int* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + r = x >> 24; + r = r + 128; + pOut[i] = (unsigned char)r; + } +} + +void mal_pcm_s32_to_s16(short* pOut, const int* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + r = x >> 16; + pOut[i] = (short)r; + } +} + +void mal_pcm_s32_to_s24(void* pOut, const int* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + r = x >> 8; + ((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16); + } +} + +void mal_pcm_s32_to_f32(float* pOut, const int* pIn, unsigned int count) +{ + float r; + for (unsigned int i = 0; i < count; ++i) { + int x = pIn[i]; + int s; + s = ((*((int*)&x)) & 0x80000000) >> 31; + s = s + 2147483647; + r = x / (float)(unsigned int)s; + pOut[i] = (float)r; + } +} + +void mal_pcm_f32_to_u8(unsigned char* pOut, const float* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + float x = pIn[i]; + float c; + int s; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + s = ((*((int*)&x)) & 0x80000000) >> 31; + s = s + 127; + r = (int)(c * s); + r = r + 128; + pOut[i] = (unsigned char)r; + } +} + +void mal_pcm_f32_to_s16(short* pOut, const float* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + float x = pIn[i]; + float c; + int s; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + s = ((*((int*)&x)) & 0x80000000) >> 31; + s = s + 32767; + r = (int)(c * s); + pOut[i] = (short)r; + } +} + +void mal_pcm_f32_to_s24(void* pOut, const float* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + float x = pIn[i]; + float c; + int s; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + s = ((*((int*)&x)) & 0x80000000) >> 31; + s = s + 8388607; + r = (int)(c * s); + ((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16); + } +} + +void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + float x = pIn[i]; + float c; + mal_int64 s; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + s = ((*((int*)&x)) & 0x80000000) >> 31; + s = s + 2147483647; + r = (int)(c * s); + pOut[i] = (int)r; + } +} +#endif + +#endif + + +// REVISION HISTORY +// ================ +// +// v0.x - 2017-xx-xx +// - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of +// audio data to a different format. +// - Expose the mutex APIs. +// +// v0.5 - 2017-11-11 +// - API CHANGE: The mal_context_init() function now takes a pointer to a mal_context_config object for +// configuring the context. The works in the same kind of way as the device config. The rationale for this +// change is to give applications better control over context-level properties, add support for backend- +// specific configurations, and support extensibility without breaking the API. +// - API CHANGE: The alsa.preferPlugHW device config variable has been removed since it's not really useful for +// anything anymore. +// - ALSA: By default, device enumeration will now only enumerate over unique card/device pairs. Applications +// can enable verbose device enumeration by setting the alsa.useVerboseDeviceEnumeration context config +// variable. +// - ALSA: When opening a device in shared mode (the default), the dmix/dsnoop plugin will be prioritized. If +// this fails it will fall back to the hw plugin. With this change the preferExclusiveMode config is now +// honored. Note that this does not happen when alsa.useVerboseDeviceEnumeration is set to true (see above) +// which is by design. +// - ALSA: Add support for excluding the "null" device using the alsa.excludeNullDevice context config variable. +// - ALSA: Fix a bug with channel mapping which causes an assertion to fail. +// - Fix errors with enumeration when pInfo is set to NULL. +// - OSS: Fix a bug when starting a device when the client sends 0 samples for the initial buffer fill. +// +// v0.4 - 2017-11-05 +// - API CHANGE: The log callback is now per-context rather than per-device and as is thus now passed to +// mal_context_init(). The rationale for this change is that it allows applications to capture diagnostic +// messages at the context level. Previously this was only available at the device level. +// - API CHANGE: The device config passed to mal_device_init() is now const. +// - Added support for OSS which enables support on BSD platforms. +// - Added support for WinMM (waveOut/waveIn). +// - Added support for UWP (Universal Windows Platform) applications. Currently C++ only. +// - Added support for exclusive mode for selected backends. Currently supported on WASAPI. +// - POSIX builds no longer require explicit linking to libpthread (-lpthread). +// - ALSA: Explicit linking to libasound (-lasound) is no longer required. +// - ALSA: Latency improvements. +// - ALSA: Use MMAP mode where available. This can be disabled with the alsa.noMMap config. +// - ALSA: Use "hw" devices instead of "plughw" devices by default. This can be disabled with the +// alsa.preferPlugHW config. +// - WASAPI is now the highest priority backend on Windows platforms. +// - Fixed an error with sample rate conversion which was causing crackling when capturing. +// - Improved error handling. +// - Improved compiler support. +// - Miscellaneous bug fixes. +// +// v0.3 - 2017-06-19 +// - API CHANGE: Introduced the notion of a context. The context is the highest level object and is required for +// enumerating and creating devices. Now, applications must first create a context, and then use that to +// enumerate and create devices. The reason for this change is to ensure device enumeration and creation is +// tied to the same backend. In addition, some backends are better suited to this design. +// - API CHANGE: Removed the rewinding APIs because they're too inconsistent across the different backends, hard +// to test and maintain, and just generally unreliable. +// - Added helper APIs for initializing mal_device_config objects. +// - Null Backend: Fixed a crash when recording. +// - Fixed build for UWP. +// - Added support for f32 formats to the OpenSL|ES backend. +// - Added initial implementation of the WASAPI backend. +// - Added initial implementation of the OpenAL backend. +// - Added support for low quality linear sample rate conversion. +// - Added early support for basic channel mapping. +// +// v0.2 - 2016-10-28 +// - API CHANGE: Add user data pointer as the last parameter to mal_device_init(). The rationale for this +// change is to ensure the logging callback has access to the user data during initialization. +// - API CHANGE: Have device configuration properties be passed to mal_device_init() via a structure. Rationale: +// 1) The number of parameters is just getting too much. +// 2) It makes it a bit easier to add new configuration properties in the future. In particular, there's a +// chance there will be support added for backend-specific properties. +// - Dropped support for f64, A-law and Mu-law formats since they just aren't common enough to justify the +// added maintenance cost. +// - DirectSound: Increased the default buffer size for capture devices. +// - Added initial implementation of the OpenSL|ES backend. +// +// v0.1 - 2016-10-21 +// - Initial versioned release. + + +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +*/ diff --git a/src/raylib.h b/src/raylib.h index 392e0a24..ae1e5813 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -486,6 +486,8 @@ typedef struct Wave { // Sound source type typedef struct Sound { + void* handle; // A pointer to internal data used by the sound system. + unsigned int source; // OpenAL audio source id unsigned int buffer; // OpenAL audio buffer id int format; // OpenAL audio format specifier From b0852002b83c615a67ae1b38feb8940213f6eed9 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 12 Nov 2017 14:54:37 +1000 Subject: [PATCH 002/139] Rename SoundInternal to SoundData for consistency with MusicData. --- src/audio.c | 42 +++++++++++++++++++++++------------------- src/raylib.h | 2 +- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/audio.c b/src/audio.c index a5f117b5..83c80d8e 100644 --- a/src/audio.c +++ b/src/audio.c @@ -211,8 +211,8 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo #define DEVICE_CHANNELS 2 #define DEVICE_SAMPLE_RATE 44100 -typedef struct SoundInternal SoundInternal; -struct SoundInternal +typedef struct SoundData SoundData; +struct SoundData { mal_format format; mal_uint32 channels; @@ -224,8 +224,8 @@ struct SoundInternal bool playing; bool paused; bool looping; - SoundInternal* next; - SoundInternal* prev; + SoundData* next; + SoundData* prev; mal_uint8 data[1]; // Raw audio data. }; @@ -234,10 +234,10 @@ static mal_device device; static mal_bool32 isAudioInitialized = MAL_FALSE; static float masterVolume = 1; static mal_mutex soundLock; -static SoundInternal* firstSound; // Sounds are tracked in a linked list. -static SoundInternal* lastSound; +static SoundData* firstSound; // Sounds are tracked in a linked list. +static SoundData* lastSound; -static void AppendSound(SoundInternal* internalSound) +static void AppendSound(SoundData* internalSound) { mal_mutex_lock(&context, &soundLock); { @@ -253,7 +253,7 @@ static void AppendSound(SoundInternal* internalSound) mal_mutex_unlock(&context, &soundLock); } -static void RemoveSound(SoundInternal* internalSound) +static void RemoveSound(SoundData* internalSound) { mal_mutex_lock(&context, &soundLock); { @@ -294,7 +294,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC float* pFramesOutF = (float*)pFramesOut; // <-- Just for convenience. // Sounds. - for (SoundInternal* internalSound = firstSound; internalSound != NULL; internalSound = internalSound->next) + for (SoundData* internalSound = firstSound; internalSound != NULL; internalSound = internalSound->next) { // Ignore stopped or paused sounds. if (!internalSound->playing || internalSound->paused) { @@ -583,7 +583,7 @@ Sound LoadSoundFromWave(Wave wave) TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to get frame count for format conversion."); } - SoundInternal* internalSound = (SoundInternal*)calloc(sizeof(*internalSound) + (frameCount*DEVICE_CHANNELS*4), 1); // <-- Make sure this is initialized to zero for safety. + SoundData* internalSound = (SoundData*)calloc(sizeof(*internalSound) + (frameCount*DEVICE_CHANNELS*4), 1); // <-- Make sure this is initialized to zero for safety. if (internalSound == NULL) { TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to allocate memory for internal buffer"); } @@ -678,7 +678,7 @@ void UnloadWave(Wave wave) void UnloadSound(Sound sound) { #if USE_MINI_AL - SoundInternal* internalSound = (SoundInternal*)sound.handle; + SoundData* internalSound = (SoundData*)sound.handle; RemoveSound(internalSound); free(internalSound); #else @@ -696,7 +696,7 @@ void UnloadSound(Sound sound) void UpdateSound(Sound sound, const void *data, int samplesCount) { #if USE_MINI_AL - SoundInternal* internalSound = (SoundInternal*)sound.handle; + SoundData* internalSound = (SoundData*)sound.handle; if (internalSound == NULL) { TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound"); @@ -739,7 +739,7 @@ void UpdateSound(Sound sound, const void *data, int samplesCount) void PlaySound(Sound sound) { #if USE_MINI_AL - SoundInternal* internalSound = (SoundInternal*)sound.handle; + SoundData* internalSound = (SoundData*)sound.handle; if (internalSound == NULL) { TraceLog(LOG_ERROR, "PlaySound() : Invalid sound"); @@ -773,7 +773,7 @@ void PlaySound(Sound sound) void PauseSound(Sound sound) { #if USE_MINI_AL - SoundInternal* internalSound = (SoundInternal*)sound.handle; + SoundData* internalSound = (SoundData*)sound.handle; if (internalSound == NULL) { TraceLog(LOG_ERROR, "PauseSound() : Invalid sound"); @@ -790,7 +790,7 @@ void PauseSound(Sound sound) void ResumeSound(Sound sound) { #if USE_MINI_AL - SoundInternal* internalSound = (SoundInternal*)sound.handle; + SoundData* internalSound = (SoundData*)sound.handle; if (internalSound == NULL) { TraceLog(LOG_ERROR, "ResumeSound() : Invalid sound"); @@ -811,7 +811,7 @@ void ResumeSound(Sound sound) void StopSound(Sound sound) { #if USE_MINI_AL - SoundInternal* internalSound = (SoundInternal*)sound.handle; + SoundData* internalSound = (SoundData*)sound.handle; if (internalSound == NULL) { TraceLog(LOG_ERROR, "StopSound() : Invalid sound"); @@ -829,7 +829,7 @@ void StopSound(Sound sound) bool IsSoundPlaying(Sound sound) { #if USE_MINI_AL - SoundInternal* internalSound = (SoundInternal*)sound.handle; + SoundData* internalSound = (SoundData*)sound.handle; if (internalSound == NULL) { TraceLog(LOG_ERROR, "IsSoundPlaying() : Invalid sound"); @@ -852,7 +852,7 @@ bool IsSoundPlaying(Sound sound) void SetSoundVolume(Sound sound, float volume) { #if USE_MINI_AL - SoundInternal* internalSound = (SoundInternal*)sound.handle; + SoundData* internalSound = (SoundData*)sound.handle; if (internalSound == NULL) { TraceLog(LOG_ERROR, "SetSoundVolume() : Invalid sound"); @@ -869,7 +869,7 @@ void SetSoundVolume(Sound sound, float volume) void SetSoundPitch(Sound sound, float pitch) { #if USE_MINI_AL - SoundInternal* internalSound = (SoundInternal*)sound.handle; + SoundData* internalSound = (SoundData*)sound.handle; if (internalSound == NULL) { TraceLog(LOG_ERROR, "SetSoundPitch() : Invalid sound"); @@ -1173,7 +1173,11 @@ void UnloadMusicStream(Music music) // Start music playing (open stream) void PlayMusicStream(Music music) { +#if USE_MINI_AL + //InternalMusic* internalMusic = +#else alSourcePlay(music->stream.source); +#endif } // Pause music playing diff --git a/src/raylib.h b/src/raylib.h index ae1e5813..b21b0878 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -486,7 +486,7 @@ typedef struct Wave { // Sound source type typedef struct Sound { - void* handle; // A pointer to internal data used by the sound system. + void* handle; // A pointer to internal data used by the audio system. unsigned int source; // OpenAL audio source id unsigned int buffer; // OpenAL audio buffer id From 09228752ce2695baf79cbc2edccc60fabb38f783 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 12 Nov 2017 10:33:44 +0100 Subject: [PATCH 003/139] Review default shaders usage on loading --- examples/shaders/shaders_postprocessing.c | 1 + src/rlgl.c | 82 ++++++++++++----------- src/shader_distortion.h | 4 +- 3 files changed, 45 insertions(+), 42 deletions(-) diff --git a/examples/shaders/shaders_postprocessing.c b/examples/shaders/shaders_postprocessing.c index f6ed8205..b8b5f6ae 100644 --- a/examples/shaders/shaders_postprocessing.c +++ b/examples/shaders/shaders_postprocessing.c @@ -83,6 +83,7 @@ int main() // NOTE 2: We load the correct shader depending on GLSL version Shader shaders[MAX_POSTPRO_SHADERS]; + // NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader shaders[FX_GRAYSCALE] = LoadShader(0, FormatText("resources/shaders/glsl%i/grayscale.fs", GLSL_VERSION)); shaders[FX_POSTERIZATION] = LoadShader(0, FormatText("resources/shaders/glsl%i/posterization.fs", GLSL_VERSION)); shaders[FX_DREAM_VISION] = LoadShader(0, FormatText("resources/shaders/glsl%i/dream_vision.fs", GLSL_VERSION)); diff --git a/src/rlgl.c b/src/rlgl.c index c5c9493d..518b0470 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -268,10 +268,8 @@ static int tempBufferCount = 0; static bool useTempBuffer = false; // Shaders -static unsigned int defaultVertexShader; -static unsigned int defaultFragmentShader; - -// Shader Programs +static unsigned int defaultVShaderId; // Default vertex shader id (used by default shader program) +static unsigned int defaultFShaderId; // Default fragment shader Id (used by default shader program) static Shader defaultShader; // Basic shader, support vertex color and diffuse texture static Shader currentShader; // Shader to be used on rendering (by default, defaultShader) @@ -328,8 +326,9 @@ static int screenHeight; // Default framebuffer height //---------------------------------------------------------------------------------- #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) static void LoadTextureCompressed(unsigned char *data, int width, int height, int compressedFormat, int mipmapCount); -static unsigned int LoadShaderPartial(const char *shaderStr, int type); // Load custom shader and return shader id -static unsigned int LoadShaderProgram(unsigned int vertexShader, unsigned int fragmentShader); // Load custom shader strings and return program id + +static unsigned int CompileShader(const char *shaderStr, int type); // Compile custom shader and return shader id +static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program static Shader LoadShaderDefault(void); // Load default shader (just vertex positioning and texture coloring) static void SetShaderDefaultLocations(Shader *shader); // Bind default shader locations (attributes and uniforms) @@ -2356,6 +2355,7 @@ char *LoadText(const char *fileName) } // Load shader from files and bind default locations +// NOTE: If shader string is NULL, using default vertex/fragment shaders Shader LoadShader(char *vsFileName, char *fsFileName) { Shader shader = { 0 }; @@ -2365,31 +2365,28 @@ Shader LoadShader(char *vsFileName, char *fsFileName) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - unsigned int vertexShader, fragmentShader; + unsigned int vertexShaderId, fragmentShaderId; - if (vsFileName == NULL) { - vertexShader = defaultVertexShader; - } else { + if (vsFileName == NULL) vertexShaderId = defaultVShaderId; + else + { char *vShaderStr = LoadText(vsFileName); - vertexShader = LoadShaderPartial(vShaderStr, GL_VERTEX_SHADER); + vertexShaderId = CompileShader(vShaderStr, GL_VERTEX_SHADER); free(vShaderStr); } - if (fsFileName == NULL) { - fragmentShader = defaultVertexShader; - } else { + if (fsFileName == NULL) fragmentShaderId = defaultVShaderId; + else + { char* fShaderStr = LoadText(fsFileName); - fragmentShader = LoadShaderPartial(fShaderStr, GL_FRAGMENT_SHADER); + fragmentShaderId = CompileShader(fShaderStr, GL_FRAGMENT_SHADER); free(fShaderStr); } - shader.id = LoadShaderProgram(vertexShader, fragmentShader); + shader.id = LoadShaderProgram(vertexShaderId, fragmentShaderId); - // After shader loading, we TRY to set default location names - if (shader.id > 0) SetShaderDefaultLocations(&shader); - - if (vertexShader != defaultVertexShader) glDeleteShader(vertexShader); - if (fragmentShader != defaultFragmentShader) glDeleteShader(fragmentShader); + if (vertexShaderId != defaultVShaderId) glDeleteShader(vertexShaderId); + if (fragmentShaderId != defaultFShaderId) glDeleteShader(fragmentShaderId); if (shader.id == 0) { @@ -2397,6 +2394,8 @@ Shader LoadShader(char *vsFileName, char *fsFileName) shader = defaultShader; } + // After shader loading, we TRY to set default location names + if (shader.id > 0) SetShaderDefaultLocations(&shader); // Get available shader uniforms // NOTE: This information is useful for debug... @@ -2421,7 +2420,6 @@ Shader LoadShader(char *vsFileName, char *fsFileName) TraceLog(LOG_DEBUG, "[SHDR ID %i] Active uniform [%s] set at location: %i", shader.id, name, location); } - #endif return shader; @@ -2929,7 +2927,10 @@ void InitVrSimulator(VrDeviceInfo info) #if defined(SUPPORT_DISTORTION_SHADER) // Load distortion shader (initialized by default with Oculus Rift CV1 parameters) - vrConfig.distortionShader.id = LoadShaderProgram(vDistortionShaderStr, fDistortionShaderStr); + unsigned int vertexShaderId = CompileShader(distortionVShaderStr, GL_VERTEX_SHADER); + unsigned int fragmentShaderId = CompileShader(distortionFShaderStr, GL_FRAGMENT_SHADER); + + vrConfig.distortionShader.id = LoadShaderProgram(vertexShaderId, fragmentShaderId); if (vrConfig.distortionShader.id > 0) SetShaderDefaultLocations(&vrConfig.distortionShader); #endif @@ -3143,7 +3144,8 @@ static void LoadTextureCompressed(unsigned char *data, int width, int height, in } } -static unsigned int LoadShaderPartial(const char *shaderStr, int type) +// Compile custom shader and return shader id +static unsigned int CompileShader(const char *shaderStr, int type) { unsigned int shader = glCreateShader(type); glShaderSource(shader, 1, &shaderStr, NULL); @@ -3154,7 +3156,7 @@ static unsigned int LoadShaderPartial(const char *shaderStr, int type) if (success != GL_TRUE) { - TraceLog(LOG_WARNING, "[VSHDR ID %i] Failed to compile shader...", shader); + TraceLog(LOG_WARNING, "[SHDR ID %i] Failed to compile shader...", shader); int maxLength = 0; int length; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); @@ -3172,13 +3174,13 @@ static unsigned int LoadShaderPartial(const char *shaderStr, int type) free(log); #endif } - else TraceLog(LOG_INFO, "[VSHDR ID %i] Shader compiled successfully", shader); + else TraceLog(LOG_INFO, "[SHDR ID %i] Shader compiled successfully", shader); return shader; } // Load custom shader strings and return program id -static unsigned int LoadShaderProgram(unsigned int vertexShader, unsigned int fragmentShader) +static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) { unsigned int program = 0; @@ -3187,8 +3189,8 @@ static unsigned int LoadShaderProgram(unsigned int vertexShader, unsigned int fr GLint success = 0; program = glCreateProgram(); - glAttachShader(program, vertexShader); - glAttachShader(program, fragmentShader); + glAttachShader(program, vShaderId); + glAttachShader(program, fShaderId); // NOTE: Default attribute shader locations must be binded before linking glBindAttribLocation(program, 0, DEFAULT_ATTRIB_POSITION_NAME); @@ -3247,7 +3249,7 @@ static Shader LoadShaderDefault(void) for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; // Vertex shader directly defined, no external file required - char vDefaultShaderStr[] = + char defaultVShaderStr[] = #if defined(GRAPHICS_API_OPENGL_21) "#version 120 \n" #elif defined(GRAPHICS_API_OPENGL_ES2) @@ -3276,7 +3278,7 @@ static Shader LoadShaderDefault(void) "} \n"; // Fragment shader directly defined, no external file required - char fDefaultShaderStr[] = + char defaultFShaderStr[] = #if defined(GRAPHICS_API_OPENGL_21) "#version 120 \n" #elif defined(GRAPHICS_API_OPENGL_ES2) @@ -3305,9 +3307,11 @@ static Shader LoadShaderDefault(void) #endif "} \n"; - defaultVertexShader = LoadShaderPartial(vDefaultShaderStr, GL_VERTEX_SHADER); - defaultFragmentShader = LoadShaderPartial(fDefaultShaderStr, GL_FRAGMENT_SHADER); - shader.id = LoadShaderProgram(defaultVertexShader, defaultFragmentShader); + // NOTE: Compiled vertex/fragment shaders are kept for re-use + defaultVShaderId = CompileShader(defaultVShaderStr, GL_VERTEX_SHADER); // Compile default vertex shader + defaultFShaderId = CompileShader(defaultFShaderStr, GL_FRAGMENT_SHADER); // Compile default fragment shader + + shader.id = LoadShaderProgram(defaultVShaderId, defaultFShaderId); if (shader.id > 0) { @@ -3369,12 +3373,10 @@ static void UnloadShaderDefault(void) { glUseProgram(0); - glDeleteShader(defaultVertexShader); - glDeleteShader(defaultFragmentShader); - //glDetachShader(defaultShader, vertexShader); - //glDetachShader(defaultShader, fragmentShader); - //glDeleteShader(vertexShader); // Already deleted on shader compilation - //glDeleteShader(fragmentShader); // Already deleted on shader compilation + glDetachShader(defaultShader.id, defaultVShaderId); + glDetachShader(defaultShader.id, defaultFShaderId); + glDeleteShader(defaultVShaderId); + glDeleteShader(defaultFShaderId); glDeleteProgram(defaultShader.id); } diff --git a/src/shader_distortion.h b/src/shader_distortion.h index 7a2c994b..3b37c630 100644 --- a/src/shader_distortion.h +++ b/src/shader_distortion.h @@ -1,6 +1,6 @@ // Vertex shader definition to embed, no external file required -static const char vDistortionShaderStr[] = +static const char distortionVShaderStr[] = #if defined(GRAPHICS_API_OPENGL_21) "#version 120 \n" #elif defined(GRAPHICS_API_OPENGL_ES2) @@ -29,7 +29,7 @@ static const char vDistortionShaderStr[] = "} \n"; // Fragment shader definition to embed, no external file required -static const char fDistortionShaderStr[] = +static const char distortionFShaderStr[] = #if defined(GRAPHICS_API_OPENGL_21) "#version 120 \n" #elif defined(GRAPHICS_API_OPENGL_ES2) From 02dd4d32b5ed7586e6691a6cdae03a658127c7be Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 12 Nov 2017 11:00:28 +0100 Subject: [PATCH 004/139] Allow custom distortion shader - IN PROGRESS - --- src/raylib.h | 17 ++++---- src/rlgl.c | 30 +++++++------- src/rlgl.h | 108 +++++++++++++++++++++++++++------------------------ 3 files changed, 81 insertions(+), 74 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index e5b74743..d5e907ab 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1095,14 +1095,15 @@ RLAPI void BeginBlendMode(int mode); // Beg RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) // VR control functions -VrDeviceInfo GetVrDeviceInfo(int vrDeviceType); // Get VR device information for some standard devices -void InitVrSimulator(VrDeviceInfo info); // Init VR simulator for selected device parameters -RLAPI void CloseVrSimulator(void); // Close VR simulator for current device -RLAPI bool IsVrSimulatorReady(void); // Detect if VR simulator is ready -RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera -RLAPI void ToggleVrMode(void); // Enable/Disable VR experience -RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering -RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering +RLAPI VrDeviceInfo GetVrDeviceInfo(int vrDeviceType); // Get VR device information for some standard devices +RLAPI void InitVrSimulator(VrDeviceInfo info); // Init VR simulator for selected device parameters +RLAPI void CloseVrSimulator(void); // Close VR simulator for current device +RLAPI bool IsVrSimulatorReady(void); // Detect if VR simulator is ready +RLAPI void SetVrDistortionShader(Shader shader); // Set VR distortion shader for stereoscopic rendering +RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera +RLAPI void ToggleVrMode(void); // Enable/Disable VR experience +RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering +RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) diff --git a/src/rlgl.c b/src/rlgl.c index 518b0470..f273e55d 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -232,7 +232,7 @@ typedef struct DrawCall { typedef struct VrStereoConfig { RenderTexture2D stereoFbo; // VR stereo rendering framebuffer Shader distortionShader; // VR stereo rendering distortion shader - //Rectangle eyesViewport[2]; // VR stereo rendering eyes viewports + Rectangle eyesViewport[2]; // VR stereo rendering eyes viewports Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices } VrStereoConfig; @@ -2926,7 +2926,7 @@ void InitVrSimulator(VrDeviceInfo info) vrConfig.stereoFbo = rlLoadRenderTexture(screenWidth, screenHeight); #if defined(SUPPORT_DISTORTION_SHADER) - // Load distortion shader (initialized by default with Oculus Rift CV1 parameters) + // Load distortion shader unsigned int vertexShaderId = CompileShader(distortionVShaderStr, GL_VERTEX_SHADER); unsigned int fragmentShaderId = CompileShader(distortionFShaderStr, GL_FRAGMENT_SHADER); @@ -2934,6 +2934,7 @@ void InitVrSimulator(VrDeviceInfo info) if (vrConfig.distortionShader.id > 0) SetShaderDefaultLocations(&vrConfig.distortionShader); #endif + // Set VR configutarion parameters, including distortion shader SetStereoConfig(info); vrSimulatorReady = true; @@ -2958,18 +2959,6 @@ void CloseVrSimulator(void) #endif } -// TODO: Review VR system to be more flexible, -// move distortion shader to user side, -// SetStereoConfig() must be reviewed... -/* -// Set VR view distortion shader -void SetVrDistortionShader(Shader shader) -{ - vrConfig.distortionShader = shader; - SetStereoConfig(info); -} -*/ - // Detect if VR simulator is running bool IsVrSimulatorReady(void) { @@ -2980,6 +2969,15 @@ bool IsVrSimulatorReady(void) #endif } +// Set VR distortion shader for stereoscopic rendering +// TODO: Review VR system to be more flexible, move distortion shader to user side +void SetVrDistortionShader(Shader shader) +{ + vrConfig.distortionShader = shader; + + //SetStereoConfig(info); // TODO: Must be reviewed to set new distortion shader uniform values... +} + // Enable/Disable VR experience (device or simulator) void ToggleVrMode(void) { @@ -4026,8 +4024,8 @@ static void SetStereoConfig(VrDeviceInfo hmd) vrConfig.eyesViewOffset[1] = MatrixTranslate(hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f); // Compute eyes Viewports - //vrConfig.eyesViewport[0] = (Rectangle){ 0, 0, hmd.hResolution/2, hmd.vResolution }; - //vrConfig.eyesViewport[1] = (Rectangle){ hmd.hResolution/2, 0, hmd.hResolution/2, hmd.vResolution }; + vrConfig.eyesViewport[0] = (Rectangle){ 0, 0, hmd.hResolution/2, hmd.vResolution }; + vrConfig.eyesViewport[1] = (Rectangle){ hmd.hResolution/2, 0, hmd.hResolution/2, hmd.vResolution }; } // Set internal projection and modelview matrix depending on eyes tracking data diff --git a/src/rlgl.h b/src/rlgl.h index 3f06a697..2e67c699 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -145,56 +145,6 @@ typedef unsigned char byte; // Boolean type typedef enum { false, true } bool; #endif - - // Shader location point type - typedef enum { - LOC_VERTEX_POSITION = 0, - LOC_VERTEX_TEXCOORD01, - LOC_VERTEX_TEXCOORD02, - LOC_VERTEX_NORMAL, - LOC_VERTEX_TANGENT, - LOC_VERTEX_COLOR, - LOC_MATRIX_MVP, - LOC_MATRIX_MODEL, - LOC_MATRIX_VIEW, - LOC_MATRIX_PROJECTION, - LOC_VECTOR_VIEW, - LOC_COLOR_DIFFUSE, - LOC_COLOR_SPECULAR, - LOC_COLOR_AMBIENT, - LOC_MAP_ALBEDO, // LOC_MAP_DIFFUSE - LOC_MAP_METALNESS, // LOC_MAP_SPECULAR - LOC_MAP_NORMAL, - LOC_MAP_ROUGHNESS, - LOC_MAP_OCCUSION, - LOC_MAP_EMISSION, - LOC_MAP_HEIGHT, - LOC_MAP_CUBEMAP, - LOC_MAP_IRRADIANCE, - LOC_MAP_PREFILTER, - LOC_MAP_BRDF - } ShaderLocationIndex; - - #define LOC_MAP_DIFFUSE LOC_MAP_ALBEDO - #define LOC_MAP_SPECULAR LOC_MAP_METALNESS - - // Material map type - typedef enum { - MAP_ALBEDO = 0, // MAP_DIFFUSE - MAP_METALNESS = 1, // MAP_SPECULAR - MAP_NORMAL = 2, - MAP_ROUGHNESS = 3, - MAP_OCCLUSION, - MAP_EMISSION, - MAP_HEIGHT, - MAP_CUBEMAP, // NOTE: Uses GL_TEXTURE_CUBE_MAP - MAP_IRRADIANCE, // NOTE: Uses GL_TEXTURE_CUBE_MAP - MAP_PREFILTER, // NOTE: Uses GL_TEXTURE_CUBE_MAP - MAP_BRDF - } TexmapIndex; - - #define MAP_DIFFUSE MAP_ALBEDO - #define MAP_SPECULAR MAP_METALNESS // Color type, RGBA (32bit) typedef struct Color { @@ -204,6 +154,14 @@ typedef unsigned char byte; unsigned char a; } Color; + // Rectangle type + typedef struct Rectangle { + int x; + int y; + int width; + int height; + } Rectangle; + // Texture2D type // NOTE: Data stored in GPU memory typedef struct Texture2D { @@ -341,6 +299,56 @@ typedef unsigned char byte; BLEND_MULTIPLIED } BlendMode; + // Shader location point type + typedef enum { + LOC_VERTEX_POSITION = 0, + LOC_VERTEX_TEXCOORD01, + LOC_VERTEX_TEXCOORD02, + LOC_VERTEX_NORMAL, + LOC_VERTEX_TANGENT, + LOC_VERTEX_COLOR, + LOC_MATRIX_MVP, + LOC_MATRIX_MODEL, + LOC_MATRIX_VIEW, + LOC_MATRIX_PROJECTION, + LOC_VECTOR_VIEW, + LOC_COLOR_DIFFUSE, + LOC_COLOR_SPECULAR, + LOC_COLOR_AMBIENT, + LOC_MAP_ALBEDO, // LOC_MAP_DIFFUSE + LOC_MAP_METALNESS, // LOC_MAP_SPECULAR + LOC_MAP_NORMAL, + LOC_MAP_ROUGHNESS, + LOC_MAP_OCCUSION, + LOC_MAP_EMISSION, + LOC_MAP_HEIGHT, + LOC_MAP_CUBEMAP, + LOC_MAP_IRRADIANCE, + LOC_MAP_PREFILTER, + LOC_MAP_BRDF + } ShaderLocationIndex; + + #define LOC_MAP_DIFFUSE LOC_MAP_ALBEDO + #define LOC_MAP_SPECULAR LOC_MAP_METALNESS + + // Material map type + typedef enum { + MAP_ALBEDO = 0, // MAP_DIFFUSE + MAP_METALNESS = 1, // MAP_SPECULAR + MAP_NORMAL = 2, + MAP_ROUGHNESS = 3, + MAP_OCCLUSION, + MAP_EMISSION, + MAP_HEIGHT, + MAP_CUBEMAP, // NOTE: Uses GL_TEXTURE_CUBE_MAP + MAP_IRRADIANCE, // NOTE: Uses GL_TEXTURE_CUBE_MAP + MAP_PREFILTER, // NOTE: Uses GL_TEXTURE_CUBE_MAP + MAP_BRDF + } TexmapIndex; + + #define MAP_DIFFUSE MAP_ALBEDO + #define MAP_SPECULAR MAP_METALNESS + // VR Head Mounted Display devices typedef enum { HMD_DEFAULT_DEVICE = 0, From 24b12e5e2380584b1668e864f2af5bed0db38487 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 12 Nov 2017 11:45:35 +0100 Subject: [PATCH 005/139] Remove PLATFORM_ checks from raylib header Now header is truly multiplatform... Actually still a small pending check on XBOX gamepad controls that hopefully will be removed with next GLFW 3.3 --- src/core.c | 25 +++++++++++++------------ src/raylib.h | 34 ++++++---------------------------- 2 files changed, 19 insertions(+), 40 deletions(-) diff --git a/src/core.c b/src/core.c index 0ca2f3e1..97d8a74c 100644 --- a/src/core.c +++ b/src/core.c @@ -279,10 +279,11 @@ static int renderOffsetY = 0; // Offset Y from render area (must b static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP) static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size) -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) -static const char *windowTitle; // Window text title... -static bool cursorOnScreen = false; // Tracks if cursor is inside client area static bool cursorHidden = false; // Track if cursor is hidden + +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) +static const char *windowTitle = NULL; // Window text title... +static bool cursorOnScreen = false; // Tracks if cursor is inside client area static int screenshotCounter = 0; // Screenshots counter // Register mouse states @@ -409,12 +410,13 @@ static void *GamepadThread(void *arg); // Mouse reading thread //---------------------------------------------------------------------------------- #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // Initialize window and OpenGL context -void InitWindow(int width, int height, const char *title) +// NOTE: data parameter could be used to pass any kind of required data to the initialization +void InitWindow(int width, int height, void *data) { TraceLog(LOG_INFO, "Initializing raylib (v1.8.0)"); - // Store window title (could be useful...) - windowTitle = title; + // Input data is window title char data + windowTitle = (char *)data; // Init graphics device (display device and OpenGL context) InitGraphicsDevice(width, height); @@ -471,15 +473,17 @@ void InitWindow(int width, int height, const char *title) #endif #if defined(PLATFORM_ANDROID) -// Initialize Android activity -void InitWindow(int width, int height, void *state) +// Initialize window and OpenGL context (and Android activity) +// NOTE: data parameter could be used to pass any kind of required data to the initialization +void InitWindow(int width, int height, void *data) { TraceLog(LOG_INFO, "Initializing raylib (v1.8.0)"); screenWidth = width; screenHeight = height; - app = (struct android_app *)state; + // Input data is android app pointer + app = (struct android_app *)data; internalDataPath = app->activity->internalDataPath; // Set desired windows flags before initializing anything @@ -508,7 +512,6 @@ void InitWindow(int width, int height, void *state) //AConfiguration_getScreenSize(app->config); //AConfiguration_getScreenLong(app->config); - //state->userData = &engine; app->onAppCmd = AndroidCommandCallback; app->onInputEvent = AndroidInputCallback; @@ -709,7 +712,6 @@ int GetScreenHeight(void) return screenHeight; } -#if !defined(PLATFORM_ANDROID) // Show mouse cursor void ShowCursor() { @@ -772,7 +774,6 @@ void DisableCursor() #endif cursorHidden = true; } -#endif // !defined(PLATFORM_ANDROID) // Set background color (framebuffer clear color) void ClearBackground(Color color) diff --git a/src/raylib.h b/src/raylib.h index d5e907ab..e5ad8a9d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -72,20 +72,6 @@ #ifndef RAYLIB_H #define RAYLIB_H -// Choose your platform here or just define it at compile time: -DPLATFORM_DESKTOP -//#define PLATFORM_DESKTOP // Windows, Linux or OSX -//#define PLATFORM_ANDROID // Android device -//#define PLATFORM_RPI // Raspberry Pi -//#define PLATFORM_WEB // HTML5 (emscripten, asm.js) - -// Security check in case no PLATFORM_* defined -#if !defined(PLATFORM_DESKTOP) && \ - !defined(PLATFORM_ANDROID) && \ - !defined(PLATFORM_RPI) && \ - !defined(PLATFORM_WEB) - #define PLATFORM_DESKTOP -#endif - #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) #define RLAPI __declspec(dllexport) // We are building raylib as a Win32 shared library (.dll) #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) @@ -179,13 +165,11 @@ #define KEY_Y 89 #define KEY_Z 90 -#if defined(PLATFORM_ANDROID) - // Android Physical Buttons - #define KEY_BACK 4 - #define KEY_MENU 82 - #define KEY_VOLUME_UP 24 - #define KEY_VOLUME_DOWN 25 -#endif +// Android Physical Buttons +#define KEY_BACK 4 +#define KEY_MENU 82 +#define KEY_VOLUME_UP 24 +#define KEY_VOLUME_DOWN 25 // Mouse Buttons #define MOUSE_LEFT_BUTTON 0 @@ -710,11 +694,7 @@ extern "C" { // Prevents name mangling of functions //------------------------------------------------------------------------------------ // Window-related functions -#if defined(PLATFORM_ANDROID) -RLAPI void InitWindow(int width, int height, void *state); // Initialize Android activity -#elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) -RLAPI void InitWindow(int width, int height, const char *title); // Initialize window and OpenGL context -#endif +RLAPI void InitWindow(int width, int height, void *data); // Initialize window and OpenGL context RLAPI void CloseWindow(void); // Close window and unload OpenGL context RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed RLAPI bool IsWindowMinimized(void); // Check if window has been minimized (or lost focus) @@ -727,14 +707,12 @@ RLAPI void SetWindowMinSize(int width, int height); // Set window RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height -#if !defined(PLATFORM_ANDROID) // Cursor-related functions RLAPI void ShowCursor(void); // Shows cursor RLAPI void HideCursor(void); // Hides cursor RLAPI bool IsCursorHidden(void); // Check if cursor is not visible RLAPI void EnableCursor(void); // Enables cursor (unlock cursor) RLAPI void DisableCursor(void); // Disables cursor (lock cursor) -#endif // Drawing-related functions RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color) From 68bf6c9701f9c1705849600838571f4f3b5c1446 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 12 Nov 2017 20:59:16 +1000 Subject: [PATCH 006/139] Initial work on porting AudioStream to use mini_al. --- src/audio.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/raylib.h | 2 + 2 files changed, 336 insertions(+), 3 deletions(-) diff --git a/src/audio.c b/src/audio.c index 83c80d8e..b04cc679 100644 --- a/src/audio.c +++ b/src/audio.c @@ -176,6 +176,22 @@ typedef struct MusicData { unsigned int samplesLeft; // Number of samples left to end } MusicData; +// AudioStreamData +typedef struct AudioStreamData AudioStreamData; +struct AudioStreamData { + mal_dsp dsp; // AudioStream data needs to flow through a persistent conversion pipeline. Not doing this will result in glitches between buffer updates. + float volume; + float pitch; + bool playing; + bool paused; + bool isSubBufferProcessed[2]; + unsigned int frameCursorPos; + unsigned int bufferSizeInFrames; + AudioStreamData* next; + AudioStreamData* prev; + unsigned char buffer[1]; +}; + #if defined(AUDIO_STANDALONE) typedef enum { LOG_INFO = 0, LOG_ERROR, LOG_WARNING, LOG_DEBUG, LOG_OTHER } TraceLogType; #endif @@ -236,6 +252,8 @@ static float masterVolume = 1; static mal_mutex soundLock; static SoundData* firstSound; // Sounds are tracked in a linked list. static SoundData* lastSound; +static AudioStreamData* firstAudioStream; +static AudioStreamData* lastAudioStream; static void AppendSound(SoundData* internalSound) { @@ -272,6 +290,42 @@ static void RemoveSound(SoundData* internalSound) mal_mutex_unlock(&context, &soundLock); } +static void AppendAudioStream(AudioStreamData* internalAudioStream) +{ + mal_mutex_lock(&context, &soundLock); + { + if (firstAudioStream == NULL) { + firstAudioStream = internalAudioStream; + } else { + lastAudioStream->next = internalAudioStream; + internalAudioStream->prev = lastAudioStream; + } + + lastAudioStream = internalAudioStream; + } + mal_mutex_unlock(&context, &soundLock); +} + +static void RemoveAudioStream(AudioStreamData* internalAudioStream) +{ + mal_mutex_lock(&context, &soundLock); + { + if (internalAudioStream->prev == NULL) { + firstAudioStream = internalAudioStream->next; + } else { + internalAudioStream->prev->next = internalAudioStream->next; + } + + if (internalAudioStream->next == NULL) { + lastAudioStream = internalAudioStream->prev; + } else { + internalAudioStream->next->prev = internalAudioStream->prev; + } + } + mal_mutex_unlock(&context, &soundLock); +} + + static void OnLog_MAL(mal_context* pContext, mal_device* pDevice, const char* message) { (void)pContext; @@ -342,8 +396,63 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC } } - // Music. - // TODO: Implement me. + // AudioStreams. These are handling slightly differently to sounds because we do data conversion at mixing time rather than + // load time. + for (AudioStreamData* internalData = firstAudioStream; internalData != NULL; internalData = internalData->next) + { + // Ignore stopped or paused streams. + if (!internalData->playing || internalData->paused) { + continue; + } + + mal_uint32 framesRead = 0; + for (;;) { + if (framesRead > frameCount) { + TraceLog(LOG_DEBUG, "Mixed too many frames from sound"); + break; + } + if (framesRead == frameCount) { + break; + } + + // Just read as much data we can from the stream. + mal_uint32 framesToRead = (frameCount - framesRead); + while (framesToRead > 0) { + float tempBuffer[1024]; // 512 frames for stereo. + + mal_uint32 framesToReadRightNow = framesToRead; + if (framesToReadRightNow > sizeof(tempBuffer)/DEVICE_CHANNELS) { + framesToReadRightNow = sizeof(tempBuffer)/DEVICE_CHANNELS; + } + + mal_uint32 framesJustRead = mal_dsp_read_frames(&internalData->dsp, framesToReadRightNow, tempBuffer); + if (framesJustRead > 0) { + // This is where the real mixing takes place. This can be optimized. This assumes the device and sound are of the same format. + // + // TODO: Implement pitching. + for (mal_uint32 iFrame = 0; iFrame < framesToRead; ++iFrame) { + float* pFrameOut = pFramesOutF + ((framesRead+iFrame) * device.channels); + float* pFrameIn = tempBuffer + (iFrame * device.channels); + + for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel) { + pFrameOut[iChannel] += pFrameIn[iChannel] * masterVolume * internalData->volume; + } + } + + framesToRead -= framesJustRead; + framesRead += framesJustRead; + } else { + break; // Avoid an infinite loop. + } + } + + // If for some reason we weren't able to read every frame we'll need to break from the loop. Not doing this could + // theoretically put us into an infinite loop. + if (framesToRead > 0) { + break; + } + } + } } mal_mutex_unlock(&context, &soundLock); @@ -1375,6 +1484,65 @@ float GetMusicTimePlayed(Music music) return secondsPlayed; } + +static mal_uint32 UpdateAudioStream_OnDSPRead(mal_uint32 frameCount, void* pFramesOut, void* pUserData) +{ + AudioStreamData* internalData = (AudioStreamData*)pUserData; + + mal_uint32 subBufferSizeInFrames = AUDIO_BUFFER_SIZE; + mal_uint32 currentSubBufferIndex = internalData->frameCursorPos / subBufferSizeInFrames; + if (currentSubBufferIndex > 1) { + TraceLog(LOG_DEBUG, "Frame cursor position moved too far forward in audio stream"); + return 0; + } + + // Another thread can update the processed state of buffers so we just take a copy here to try and avoid potential synchronization problems. + bool isSubBufferProcessed[2]; + isSubBufferProcessed[0] = internalData->isSubBufferProcessed[0]; + isSubBufferProcessed[1] = internalData->isSubBufferProcessed[1]; + + mal_uint32 channels = internalData->dsp.config.channelsIn; + mal_uint32 sampleSizeInBytes = mal_get_sample_size_in_bytes(internalData->dsp.config.formatIn); + mal_uint32 frameSizeInBytes = sampleSizeInBytes*channels; + + // Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0. + mal_uint32 framesRead = 0; + while (!isSubBufferProcessed[currentSubBufferIndex]) + { + mal_uint32 totalFramesRemaining = (frameCount - framesRead); + if (totalFramesRemaining == 0) { + break; + } + + mal_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames * currentSubBufferIndex; + mal_uint32 framesRemainingInThisSubBuffer = subBufferSizeInFrames - (internalData->frameCursorPos - firstFrameIndexOfThisSubBuffer); + + mal_uint32 framesToRead = totalFramesRemaining; + if (framesToRead > framesRemainingInThisSubBuffer) { + framesToRead = framesRemainingInThisSubBuffer; + } + + memcpy((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), internalData->buffer + (internalData->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes); + + framesRead += framesToRead; + internalData->frameCursorPos = (internalData->frameCursorPos + framesToRead) % internalData->bufferSizeInFrames; + + // If we've read to the end of the buffer, mark it as processed. + if (framesToRead == framesRemainingInThisSubBuffer) { + internalData->isSubBufferProcessed[currentSubBufferIndex] = true; + currentSubBufferIndex = (currentSubBufferIndex + 1) % 2; + } + } + + // Zero-fill excess. + mal_uint32 totalFramesRemaining = (frameCount - framesRead); + if (totalFramesRemaining > 0) { + memset((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes); + } + + return frameCount; +} + // Init audio stream (to stream audio pcm data) AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) { @@ -1391,6 +1559,41 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un stream.channels = 1; // Fallback to mono channel } + +#if USE_MINI_AL + AudioStreamData* internalData = (AudioStreamData*)calloc(1, sizeof(*internalData) + (AUDIO_BUFFER_SIZE*2 * stream.channels*(stream.sampleSize/8))); + if (internalData == NULL) + { + TraceLog(LOG_ERROR, "Failed to allocate buffer for audio stream"); + return stream; + } + + mal_dsp_config config; + memset(&config, 0, sizeof(config)); + config.formatIn = ((stream.sampleSize == 8) ? mal_format_u8 : ((stream.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); + config.channelsIn = stream.channels; + config.sampleRateIn = stream.sampleRate; + config.formatOut = DEVICE_FORMAT; + config.channelsOut = DEVICE_CHANNELS; + config.sampleRateOut = DEVICE_SAMPLE_RATE; + mal_result result = mal_dsp_init(&config, UpdateAudioStream_OnDSPRead, internalData, &internalData->dsp); + if (result != MAL_SUCCESS) + { + TraceLog(LOG_ERROR, "InitAudioStream() : Failed to initialize data conversion pipeline"); + free(internalData); + return stream; + } + + // Buffers should be marked as processed by default so that a call to UpdateAudioStream() immediately after initialization works correctly. + internalData->isSubBufferProcessed[0] = true; + internalData->isSubBufferProcessed[1] = true; + internalData->bufferSizeInFrames = AUDIO_BUFFER_SIZE*2; + internalData->volume = 1; + internalData->pitch = 1; + AppendAudioStream(internalData); + + stream.handle = internalData; +#else // Setup OpenAL format if (stream.channels == 1) { @@ -1435,6 +1638,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un free(pcm); alSourceQueueBuffers(stream.source, MAX_STREAM_BUFFERS, stream.buffers); +#endif TraceLog(LOG_INFO, "[AUD ID %i] Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.source, stream.sampleRate, stream.sampleSize, (stream.channels == 1) ? "Mono" : "Stereo"); @@ -1444,6 +1648,11 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un // Close audio stream and free memory void CloseAudioStream(AudioStream stream) { +#if USE_MINI_AL + AudioStreamData* internalData = (AudioStreamData*)stream.handle; + RemoveAudioStream(internalData); + free(internalData); +#else // Stop playing channel alSourceStop(stream.source); @@ -1462,7 +1671,8 @@ void CloseAudioStream(AudioStream stream) // Delete source and buffers alDeleteSources(1, &stream.source); alDeleteBuffers(MAX_STREAM_BUFFERS, stream.buffers); - +#endif + TraceLog(LOG_INFO, "[AUD ID %i] Unloaded audio stream data", stream.source); } @@ -1471,6 +1681,67 @@ void CloseAudioStream(AudioStream stream) // NOTE 2: To unqueue a buffer it needs to be processed: IsAudioBufferProcessed() void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) { +#if USE_MINI_AL + AudioStreamData* internalData = (AudioStreamData*)stream.handle; + if (internalData == NULL) + { + TraceLog(LOG_ERROR, "Invalid audio stream"); + return; + } + + // We need to determine which half of the buffer needs updating. If the stream is not started and the cursor position is + // at the front of the buffer, update the first subbuffer. + if (internalData->isSubBufferProcessed[0] || internalData->isSubBufferProcessed[1]) + { + mal_uint32 subBufferToUpdate; + if (internalData->isSubBufferProcessed[0] && internalData->isSubBufferProcessed[1]) + { + // Both buffers are available for updating. Update the first one and make sure the cursor is moved back to the front. + subBufferToUpdate = 0; + internalData->frameCursorPos = 0; + } + else + { + // Just update whichever sub-buffer is processed. + subBufferToUpdate = (internalData->isSubBufferProcessed[0]) ? 0 : 1; + } + + mal_uint32 subBufferSizeInFrames = AUDIO_BUFFER_SIZE; + unsigned char *subBuffer = internalData->buffer + ((subBufferSizeInFrames * stream.channels * (stream.sampleSize/8)) * subBufferToUpdate); + + // Does this API expect a whole buffer to be updated in one go? Assuming so, but if not will need to change this logic. + if (subBufferSizeInFrames >= (mal_uint32)samplesCount) + { + mal_uint32 framesToWrite = subBufferSizeInFrames; + if (framesToWrite > (mal_uint32)samplesCount) { + framesToWrite = (mal_uint32)samplesCount; + } + + mal_uint32 bytesToWrite = framesToWrite * stream.channels * (stream.sampleSize/8); + memcpy(subBuffer, data, bytesToWrite); + + // Any leftover frames should be filled with zeros. + mal_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite; + if (leftoverFrameCount > 0) { + memset(subBuffer + bytesToWrite, 0, leftoverFrameCount * stream.channels * (stream.sampleSize/8)); + } + + internalData->isSubBufferProcessed[subBufferToUpdate] = false; + } + else + { + TraceLog(LOG_ERROR, "[AUD ID %i] UpdateAudioStream() : Attempting to write too many frames to buffer"); + return; + } + } + else + { + TraceLog(LOG_ERROR, "[AUD ID %i] Audio buffer not available for updating"); + return; + } + + +#else ALuint buffer = 0; alSourceUnqueueBuffers(stream.source, 1, &buffer); @@ -1481,44 +1752,104 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) alSourceQueueBuffers(stream.source, 1, &buffer); } else TraceLog(LOG_WARNING, "[AUD ID %i] Audio buffer not available for unqueuing", stream.source); +#endif } // Check if any audio stream buffers requires refill bool IsAudioBufferProcessed(AudioStream stream) { +#if USE_MINI_AL + AudioStreamData* internalData = (AudioStreamData*)stream.handle; + if (internalData == NULL) + { + TraceLog(LOG_ERROR, "Invalid audio stream"); + return false; + } + + return internalData->isSubBufferProcessed[0] || internalData->isSubBufferProcessed[1]; +#else ALint processed = 0; // Determine if music stream is ready to be written alGetSourcei(stream.source, AL_BUFFERS_PROCESSED, &processed); return (processed > 0); +#endif } // Play audio stream void PlayAudioStream(AudioStream stream) { +#if USE_MINI_AL + AudioStreamData* internalData = (AudioStreamData*)stream.handle; + if (internalData == NULL) + { + TraceLog(LOG_ERROR, "Invalid audio stream"); + return; + } + + internalData->playing = true; +#else alSourcePlay(stream.source); +#endif } // Play audio stream void PauseAudioStream(AudioStream stream) { +#if USE_MINI_AL + AudioStreamData* internalData = (AudioStreamData*)stream.handle; + if (internalData == NULL) + { + TraceLog(LOG_ERROR, "Invalid audio stream"); + return; + } + + internalData->paused = true; +#else alSourcePause(stream.source); +#endif } // Resume audio stream playing void ResumeAudioStream(AudioStream stream) { +#if USE_MINI_AL + AudioStreamData* internalData = (AudioStreamData*)stream.handle; + if (internalData == NULL) + { + TraceLog(LOG_ERROR, "Invalid audio stream"); + return; + } + + internalData->paused = false; +#else ALenum state; alGetSourcei(stream.source, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) alSourcePlay(stream.source); +#endif } // Stop audio stream void StopAudioStream(AudioStream stream) { +#if USE_MINI_AL + AudioStreamData* internalData = (AudioStreamData*)stream.handle; + if (internalData == NULL) + { + TraceLog(LOG_ERROR, "Invalid audio stream"); + return; + } + + internalData->playing = 0; + internalData->paused = 0; + internalData->frameCursorPos = 0; + internalData->isSubBufferProcessed[0] = true; + internalData->isSubBufferProcessed[1] = true; +#else alSourceStop(stream.source); +#endif } //---------------------------------------------------------------------------------- diff --git a/src/raylib.h b/src/raylib.h index b21b0878..5e3724c9 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -504,6 +504,8 @@ typedef struct AudioStream { unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) unsigned int channels; // Number of channels (1-mono, 2-stereo) + void* handle; // A pointer to internal data used by the audio system. + int format; // OpenAL audio format specifier unsigned int source; // OpenAL audio source id unsigned int buffers[2]; // OpenAL audio buffers (double buffering) From ac4c911ad7e08cca3691896befbe8c09e3f3262f Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 12 Nov 2017 21:55:24 +1000 Subject: [PATCH 007/139] Work on porting Music to mini_al. --- src/audio.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/raylib.h | 3 +- 2 files changed, 116 insertions(+), 3 deletions(-) diff --git a/src/audio.c b/src/audio.c index b04cc679..d4f426e0 100644 --- a/src/audio.c +++ b/src/audio.c @@ -1283,7 +1283,7 @@ void UnloadMusicStream(Music music) void PlayMusicStream(Music music) { #if USE_MINI_AL - //InternalMusic* internalMusic = + PlayAudioStream(music->stream); #else alSourcePlay(music->stream.source); #endif @@ -1292,12 +1292,19 @@ void PlayMusicStream(Music music) // Pause music playing void PauseMusicStream(Music music) { +#if USE_MINI_AL + PauseAudioStream(music->stream); +#else alSourcePause(music->stream.source); +#endif } // Resume music playing void ResumeMusicStream(Music music) { +#if USE_MINI_AL + ResumeAudioStream(music->stream); +#else ALenum state; alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); @@ -1306,12 +1313,16 @@ void ResumeMusicStream(Music music) TraceLog(LOG_INFO, "[AUD ID %i] Resume music stream playing", music->stream.source); alSourcePlay(music->stream.source); } +#endif } // Stop music playing (close stream) // TODO: To clear a buffer, make sure they have been already processed! void StopMusicStream(Music music) { +#if USE_MINI_AL + StopAudioStream(music->stream); +#else alSourceStop(music->stream.source); /* @@ -1327,6 +1338,7 @@ void StopMusicStream(Music music) free(pcm); */ +#endif // Restart music context switch (music->ctxType) @@ -1351,6 +1363,77 @@ void StopMusicStream(Music music) // TODO: Make sure buffers are ready for update... check music state void UpdateMusicStream(Music music) { +#if USE_MINI_AL + bool streamEnding = false; + + // NOTE: Using dynamic allocation because it could require more than 16KB + void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, 1); + + int samplesCount = 0; // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts + + while (IsAudioBufferProcessed(music->stream)) + { + if (music->samplesLeft >= AUDIO_BUFFER_SIZE) samplesCount = AUDIO_BUFFER_SIZE; + else samplesCount = music->samplesLeft; + + // TODO: Really don't like ctxType thingy... + switch (music->ctxType) + { + case MUSIC_AUDIO_OGG: + { + // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) + int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount*music->stream.channels); + + } break; + #if defined(SUPPORT_FILEFORMAT_FLAC) + case MUSIC_AUDIO_FLAC: + { + // NOTE: Returns the number of samples to process + unsigned int numSamplesFlac = (unsigned int)drflac_read_s16(music->ctxFlac, samplesCount*music->stream.channels, (short *)pcm); + + } break; + #endif + #if defined(SUPPORT_FILEFORMAT_XM) + case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, samplesCount); break; + #endif + #if defined(SUPPORT_FILEFORMAT_MOD) + case MUSIC_MODULE_MOD: jar_mod_fillbuffer(&music->ctxMod, pcm, samplesCount, 0); break; + #endif + default: break; + } + + UpdateAudioStream(music->stream, pcm, samplesCount); + music->samplesLeft -= samplesCount; + + if (music->samplesLeft <= 0) + { + streamEnding = true; + break; + } + } + + // Free allocated pcm data + free(pcm); + + // Reset audio stream for looping + if (streamEnding) + { + StopMusicStream(music); // Stop music (and reset) + + // Decrease loopCount to stop when required + if (music->loopCount > 0) + { + music->loopCount--; // Decrease loop count + PlayMusicStream(music); // Play again + } + } + else + { + // NOTE: In case window is minimized, music stream is stopped, + // just make sure to play again on window restore + if (IsMusicPlaying(music)) PlayMusicStream(music); + } +#else ALenum state; ALint processed = 0; @@ -1431,11 +1514,15 @@ void UpdateMusicStream(Music music) if (state != AL_PLAYING) PlayMusicStream(music); } } +#endif } // Check if any music is playing bool IsMusicPlaying(Music music) { +#if USE_MINI_AL + return IsAudioStreamPlaying(music->stream); +#else bool playing = false; ALint state; @@ -1444,6 +1531,7 @@ bool IsMusicPlaying(Music music) if (state == AL_PLAYING) playing = true; return playing; +#endif } // Set volume for music @@ -1460,7 +1548,7 @@ void SetMusicPitch(Music music, float pitch) // Set music loop count (loop repeats) // NOTE: If set to -1, means infinite loop -void SetMusicLoopCount(Music music, float count) +void SetMusicLoopCount(Music music, int count) { music->loopCount = count; } @@ -1831,6 +1919,30 @@ void ResumeAudioStream(AudioStream stream) #endif } +// Check if audio stream is playing. +bool IsAudioStreamPlaying(AudioStream stream) +{ +#if USE_MINI_AL + AudioStreamData* internalData = (AudioStreamData*)stream.handle; + if (internalData == NULL) + { + TraceLog(LOG_ERROR, "Invalid audio stream"); + return false; + } + + return internalData->playing; +#else + bool playing = false; + ALint state; + + alGetSourcei(stream.source, AL_SOURCE_STATE, &state); + + if (state == AL_PLAYING) playing = true; + + return playing; +#endif +} + // Stop audio stream void StopAudioStream(AudioStream stream) { diff --git a/src/raylib.h b/src/raylib.h index 5e3724c9..725eb23b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1150,7 +1150,7 @@ RLAPI void ResumeMusicStream(Music music); // Resume RLAPI bool IsMusicPlaying(Music music); // Check if music is playing RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) -RLAPI void SetMusicLoopCount(Music music, float count); // Set music loop count (loop repeats) +RLAPI void SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats) RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) @@ -1163,6 +1163,7 @@ RLAPI bool IsAudioBufferProcessed(AudioStream stream); // Check i RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream RLAPI void PauseAudioStream(AudioStream stream); // Pause audio stream RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream +RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream #ifdef __cplusplus From e52f4282d6f8e7465367effb22ba6f90a9099667 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 12 Nov 2017 22:56:53 +1000 Subject: [PATCH 008/139] Update comments. --- src/audio.c | 2 +- src/external/mini_al.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/audio.c b/src/audio.c index d4f426e0..70426532 100644 --- a/src/audio.c +++ b/src/audio.c @@ -396,7 +396,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC } } - // AudioStreams. These are handling slightly differently to sounds because we do data conversion at mixing time rather than + // AudioStreams. These are handled slightly differently to sounds because we do data conversion at mixing time rather than // load time. for (AudioStreamData* internalData = firstAudioStream; internalData != NULL; internalData = internalData->next) { diff --git a/src/external/mini_al.c b/src/external/mini_al.c index 2ea2cc6b..7b437851 100644 --- a/src/external/mini_al.c +++ b/src/external/mini_al.c @@ -1,2 +1,4 @@ +// The implementation of mini_al needs to #include windows.h which means it needs to go into +// it's own translation unit. Not doing this will cause conflicts with CloseWindow(), etc. #define MAL_IMPLEMENTATION -#include "mini_al.h" // <-- The implementation of mini_al.h #includes windows.h, so need to #undef some stuff. \ No newline at end of file +#include "mini_al.h" \ No newline at end of file From 9c65caea8cef4d334ef71fc18e1ea4d77fd59187 Mon Sep 17 00:00:00 2001 From: Ray San Date: Mon, 13 Nov 2017 12:09:41 +0100 Subject: [PATCH 009/139] Added GLFW sources to raylib Compiling GLFW library with raylib avoids external dependencies, this way we solve version problems in some platforms --- src/external/glfw/LICENSE.md | 22 + src/external/glfw/README.md | 435 + src/external/glfw/deps/KHR/khrplatform.h | 282 + src/external/glfw/deps/getopt.c | 230 + src/external/glfw/deps/getopt.h | 57 + src/external/glfw/deps/glad.c | 1678 ++ src/external/glfw/deps/glad/glad.h | 3680 +++ src/external/glfw/deps/linmath.h | 574 + .../glfw/deps/mingw/_mingw_dxhelper.h | 117 + src/external/glfw/deps/mingw/dinput.h | 2467 ++ src/external/glfw/deps/mingw/xinput.h | 239 + src/external/glfw/deps/nuklear.h | 23590 ++++++++++++++++ src/external/glfw/deps/nuklear_glfw_gl2.h | 372 + src/external/glfw/deps/stb_image_write.h | 1048 + src/external/glfw/deps/tinycthread.c | 594 + src/external/glfw/deps/tinycthread.h | 443 + src/external/glfw/deps/vs2008/stdint.h | 247 + src/external/glfw/deps/vulkan/vk_platform.h | 120 + src/external/glfw/deps/vulkan/vulkan.h | 4763 ++++ src/external/glfw/include/GLFW/glfw3.h | 5270 ++++ src/external/glfw/include/GLFW/glfw3native.h | 572 + src/external/glfw/src/CMakeLists.txt | 152 + src/external/glfw/src/cocoa_init.m | 374 + src/external/glfw/src/cocoa_joystick.h | 50 + src/external/glfw/src/cocoa_joystick.m | 462 + src/external/glfw/src/cocoa_monitor.m | 531 + src/external/glfw/src/cocoa_platform.h | 164 + src/external/glfw/src/cocoa_time.c | 60 + src/external/glfw/src/cocoa_window.m | 1863 ++ src/external/glfw/src/context.c | 723 + src/external/glfw/src/egl_context.c | 786 + src/external/glfw/src/egl_context.h | 219 + src/external/glfw/src/glfw3.pc.in | 13 + src/external/glfw/src/glfw3Config.cmake.in | 1 + src/external/glfw/src/glfw_config.h.in | 57 + src/external/glfw/src/glx_context.c | 698 + src/external/glfw/src/glx_context.h | 181 + src/external/glfw/src/init.c | 317 + src/external/glfw/src/input.c | 1151 + src/external/glfw/src/internal.h | 1016 + src/external/glfw/src/linux_joystick.c | 429 + src/external/glfw/src/linux_joystick.h | 62 + src/external/glfw/src/mappings.h | 241 + src/external/glfw/src/mappings.h.in | 70 + src/external/glfw/src/mir_init.c | 240 + src/external/glfw/src/mir_monitor.c | 214 + src/external/glfw/src/mir_platform.h | 133 + src/external/glfw/src/mir_window.c | 955 + src/external/glfw/src/monitor.c | 467 + src/external/glfw/src/nsgl_context.h | 56 + src/external/glfw/src/nsgl_context.m | 335 + src/external/glfw/src/null_init.c | 50 + src/external/glfw/src/null_joystick.c | 42 + src/external/glfw/src/null_joystick.h | 31 + src/external/glfw/src/null_monitor.c | 64 + src/external/glfw/src/null_platform.h | 62 + src/external/glfw/src/null_window.c | 307 + src/external/glfw/src/osmesa_context.c | 370 + src/external/glfw/src/osmesa_context.h | 94 + src/external/glfw/src/posix_thread.c | 103 + src/external/glfw/src/posix_thread.h | 51 + src/external/glfw/src/posix_time.c | 85 + src/external/glfw/src/posix_time.h | 44 + src/external/glfw/src/vulkan.c | 322 + src/external/glfw/src/wgl_context.c | 731 + src/external/glfw/src/wgl_context.h | 158 + src/external/glfw/src/win32_init.c | 583 + src/external/glfw/src/win32_joystick.c | 751 + src/external/glfw/src/win32_joystick.h | 56 + src/external/glfw/src/win32_monitor.c | 512 + src/external/glfw/src/win32_platform.h | 409 + src/external/glfw/src/win32_thread.c | 97 + src/external/glfw/src/win32_time.c | 74 + src/external/glfw/src/win32_window.c | 1953 ++ src/external/glfw/src/window.c | 1021 + src/external/glfw/src/wl_init.c | 792 + src/external/glfw/src/wl_monitor.c | 201 + src/external/glfw/src/wl_platform.h | 223 + src/external/glfw/src/wl_window.c | 1106 + src/external/glfw/src/x11_init.c | 1045 + src/external/glfw/src/x11_monitor.c | 510 + src/external/glfw/src/x11_platform.h | 442 + src/external/glfw/src/x11_window.c | 2991 ++ src/external/glfw/src/xkb_unicode.c | 940 + src/external/glfw/src/xkb_unicode.h | 28 + src/rglfw.c | 74 + 86 files changed, 75142 insertions(+) create mode 100644 src/external/glfw/LICENSE.md create mode 100644 src/external/glfw/README.md create mode 100644 src/external/glfw/deps/KHR/khrplatform.h create mode 100644 src/external/glfw/deps/getopt.c create mode 100644 src/external/glfw/deps/getopt.h create mode 100644 src/external/glfw/deps/glad.c create mode 100644 src/external/glfw/deps/glad/glad.h create mode 100644 src/external/glfw/deps/linmath.h create mode 100644 src/external/glfw/deps/mingw/_mingw_dxhelper.h create mode 100644 src/external/glfw/deps/mingw/dinput.h create mode 100644 src/external/glfw/deps/mingw/xinput.h create mode 100644 src/external/glfw/deps/nuklear.h create mode 100644 src/external/glfw/deps/nuklear_glfw_gl2.h create mode 100644 src/external/glfw/deps/stb_image_write.h create mode 100644 src/external/glfw/deps/tinycthread.c create mode 100644 src/external/glfw/deps/tinycthread.h create mode 100644 src/external/glfw/deps/vs2008/stdint.h create mode 100644 src/external/glfw/deps/vulkan/vk_platform.h create mode 100644 src/external/glfw/deps/vulkan/vulkan.h create mode 100644 src/external/glfw/include/GLFW/glfw3.h create mode 100644 src/external/glfw/include/GLFW/glfw3native.h create mode 100644 src/external/glfw/src/CMakeLists.txt create mode 100644 src/external/glfw/src/cocoa_init.m create mode 100644 src/external/glfw/src/cocoa_joystick.h create mode 100644 src/external/glfw/src/cocoa_joystick.m create mode 100644 src/external/glfw/src/cocoa_monitor.m create mode 100644 src/external/glfw/src/cocoa_platform.h create mode 100644 src/external/glfw/src/cocoa_time.c create mode 100644 src/external/glfw/src/cocoa_window.m create mode 100644 src/external/glfw/src/context.c create mode 100644 src/external/glfw/src/egl_context.c create mode 100644 src/external/glfw/src/egl_context.h create mode 100644 src/external/glfw/src/glfw3.pc.in create mode 100644 src/external/glfw/src/glfw3Config.cmake.in create mode 100644 src/external/glfw/src/glfw_config.h.in create mode 100644 src/external/glfw/src/glx_context.c create mode 100644 src/external/glfw/src/glx_context.h create mode 100644 src/external/glfw/src/init.c create mode 100644 src/external/glfw/src/input.c create mode 100644 src/external/glfw/src/internal.h create mode 100644 src/external/glfw/src/linux_joystick.c create mode 100644 src/external/glfw/src/linux_joystick.h create mode 100644 src/external/glfw/src/mappings.h create mode 100644 src/external/glfw/src/mappings.h.in create mode 100644 src/external/glfw/src/mir_init.c create mode 100644 src/external/glfw/src/mir_monitor.c create mode 100644 src/external/glfw/src/mir_platform.h create mode 100644 src/external/glfw/src/mir_window.c create mode 100644 src/external/glfw/src/monitor.c create mode 100644 src/external/glfw/src/nsgl_context.h create mode 100644 src/external/glfw/src/nsgl_context.m create mode 100644 src/external/glfw/src/null_init.c create mode 100644 src/external/glfw/src/null_joystick.c create mode 100644 src/external/glfw/src/null_joystick.h create mode 100644 src/external/glfw/src/null_monitor.c create mode 100644 src/external/glfw/src/null_platform.h create mode 100644 src/external/glfw/src/null_window.c create mode 100644 src/external/glfw/src/osmesa_context.c create mode 100644 src/external/glfw/src/osmesa_context.h create mode 100644 src/external/glfw/src/posix_thread.c create mode 100644 src/external/glfw/src/posix_thread.h create mode 100644 src/external/glfw/src/posix_time.c create mode 100644 src/external/glfw/src/posix_time.h create mode 100644 src/external/glfw/src/vulkan.c create mode 100644 src/external/glfw/src/wgl_context.c create mode 100644 src/external/glfw/src/wgl_context.h create mode 100644 src/external/glfw/src/win32_init.c create mode 100644 src/external/glfw/src/win32_joystick.c create mode 100644 src/external/glfw/src/win32_joystick.h create mode 100644 src/external/glfw/src/win32_monitor.c create mode 100644 src/external/glfw/src/win32_platform.h create mode 100644 src/external/glfw/src/win32_thread.c create mode 100644 src/external/glfw/src/win32_time.c create mode 100644 src/external/glfw/src/win32_window.c create mode 100644 src/external/glfw/src/window.c create mode 100644 src/external/glfw/src/wl_init.c create mode 100644 src/external/glfw/src/wl_monitor.c create mode 100644 src/external/glfw/src/wl_platform.h create mode 100644 src/external/glfw/src/wl_window.c create mode 100644 src/external/glfw/src/x11_init.c create mode 100644 src/external/glfw/src/x11_monitor.c create mode 100644 src/external/glfw/src/x11_platform.h create mode 100644 src/external/glfw/src/x11_window.c create mode 100644 src/external/glfw/src/xkb_unicode.c create mode 100644 src/external/glfw/src/xkb_unicode.h create mode 100644 src/rglfw.c diff --git a/src/external/glfw/LICENSE.md b/src/external/glfw/LICENSE.md new file mode 100644 index 00000000..e4c6682e --- /dev/null +++ b/src/external/glfw/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2002-2006 Marcus Geelnard +Copyright (c) 2006-2016 Camilla Löwy + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would + be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. + diff --git a/src/external/glfw/README.md b/src/external/glfw/README.md new file mode 100644 index 00000000..4048baf1 --- /dev/null +++ b/src/external/glfw/README.md @@ -0,0 +1,435 @@ +# GLFW + +[![Build status](https://travis-ci.org/glfw/glfw.svg?branch=master)](https://travis-ci.org/glfw/glfw) +[![Build status](https://ci.appveyor.com/api/projects/status/0kf0ct9831i5l6sp/branch/master?svg=true)](https://ci.appveyor.com/project/elmindreda/glfw) +[![Coverity Scan](https://scan.coverity.com/projects/4884/badge.svg)](https://scan.coverity.com/projects/glfw-glfw) + +## Introduction + +GLFW is an Open Source, multi-platform library for OpenGL, OpenGL ES and Vulkan +application development. It provides a simple, platform-independent API for +creating windows, contexts and surfaces, reading input, handling events, etc. + +GLFW natively supports Windows, macOS and Linux and other Unix-like systems. +Experimental implementations for the Wayland protocol and the Mir display server +are available but not yet officially supported. + +GLFW is licensed under the [zlib/libpng +license](http://www.glfw.org/license.html). + +The latest stable release is version 3.2.1. + +See the [downloads](http://www.glfw.org/download.html) page for details and +files, or fetch the `latest` branch, which always points to the latest stable +release. Each release starting with 3.0 also has a corresponding [annotated +tag](https://github.com/glfw/glfw/releases) with source and binary archives. +The [version history](http://www.glfw.org/changelog.html) lists all user-visible +changes for every release. + +This is a development branch for version 3.3, which is _not yet described_. +Pre-release documentation is available [here](http://www.glfw.org/docs/3.3/). + +The `master` branch is the stable integration branch and _should_ always compile +and run on all supported platforms, although details of newly added features may +change until they have been included in a release. New features and many bug +fixes live in [other branches](https://github.com/glfw/glfw/branches/all) until +they are stable enough to merge. + +If you are new to GLFW, you may find the +[tutorial](http://www.glfw.org/docs/latest/quick.html) for GLFW 3 useful. If +you have used GLFW 2 in the past, there is a [transition +guide](http://www.glfw.org/docs/latest/moving.html) for moving to the GLFW +3 API. + + +## Compiling GLFW + +GLFW itself requires only the headers and libraries for your window system. It +does not need the headers for any context creation API (WGL, GLX, EGL, NSGL, +OSMesa) or rendering API (OpenGL, OpenGL ES, Vulkan) to enable support for them. + +GLFW supports compilation on Windows with Visual C++ 2010 and later, MinGW and +MinGW-w64, on macOS with Clang and on Linux and other Unix-like systems with GCC +and Clang. It will likely compile in other environments as well, but this is +not regularly tested. + +There are [pre-compiled Windows binaries](http://www.glfw.org/download.html) +available for all supported compilers. + +See the [compilation guide](http://www.glfw.org/docs/latest/compile.html) for +more information about how to compile GLFW yourself. + + +## Using GLFW + +See the [documentation](http://www.glfw.org/docs/latest/) for tutorials, guides +and the API reference. + + +## Contributing to GLFW + +See the [contribution +guide](https://github.com/glfw/glfw/blob/master/.github/CONTRIBUTING.md) for +more information. + + +## System requirements + +GLFW supports Windows XP and later and macOS 10.7 and later. Linux and other +Unix-like systems running the X Window System are supported even without +a desktop environment or modern extensions, although some features require +a running window or clipboard manager. The OSMesa backend requires Mesa 6.3. + +See the [compatibility guide](http://www.glfw.org/docs/latest/compat.html) +in the documentation for more information. + + +## Dependencies + +GLFW itself depends only on the headers and libraries for your window system. + +The (experimental) Wayland backend also depends on the `extra-cmake-modules` +package, which is used to generated Wayland protocol headers. + +The examples and test programs depend on a number of tiny libraries. These are +located in the `deps/` directory. + + - [getopt\_port](https://github.com/kimgr/getopt_port/) for examples + with command-line options + - [TinyCThread](https://github.com/tinycthread/tinycthread) for threaded + examples + - An OpenGL 3.2 core loader generated by + [glad](https://github.com/Dav1dde/glad) for examples using modern OpenGL + - [linmath.h](https://github.com/datenwolf/linmath.h) for linear algebra in + examples + - [Nuklear](https://github.com/vurtun/nuklear) for test and example UI + - [stb\_image\_write](https://github.com/nothings/stb) for writing images to disk + - [Vulkan headers](https://www.khronos.org/registry/vulkan/) for Vulkan tests + +The Vulkan example additionally requires the Vulkan SDK to be installed, or it +will not be included in the build. On macOS you need to provide the path to the +MoltenVK SDK manually as it has no standard installation location. + +The documentation is generated with [Doxygen](http://doxygen.org/) if CMake can +find that tool. + + +## Reporting bugs + +Bugs are reported to our [issue tracker](https://github.com/glfw/glfw/issues). +Please check the [contribution +guide](https://github.com/glfw/glfw/blob/master/.github/CONTRIBUTING.md) for +information on what to include when reporting a bug. + + +## Changelog + +- Added `glfwGetError` function for querying the last error code and its + description (#970) +- Added `glfwUpdateGamepadMappings` function for importing gamepad mappings in + SDL\_GameControllerDB format (#900) +- Added `glfwJoystickIsGamepad` function for querying whether a joystick has + a gamepad mapping (#900) +- Added `glfwGetJoystickGUID` function for querying the SDL compatible GUID of + a joystick (#900) +- Added `glfwGetGamepadName` function for querying the name provided by the + gamepad mapping (#900) +- Added `glfwGetGamepadState` function, `GLFW_GAMEPAD_*` and `GLFWgamepadstate` + for retrieving gamepad input state (#900) +- Added `glfwGetWindowContentScale` and `glfwGetMonitorContentScale` for + DPI-aware rendering (#235,#439,#677,#845,#898) +- Added `glfwRequestWindowAttention` function for requesting attention from the + user (#732,#988) +- Added `glfwGetKeyScancode` function that allows retrieving platform dependent + scancodes for keys (#830) +- Added `glfwSetWindowMaximizeCallback` and `GLFWwindowmaximizefun` for + receiving window maximization events (#778) +- Added `glfwSetWindowAttrib` function for changing window attributes (#537) +- Added `glfwGetJoystickHats` function for querying joystick hats + (#889,#906,#934) +- Added `glfwInitHint` and `glfwInitHintString` for setting initialization hints +- Added `glfwGetX11SelectionString` and `glfwSetX11SelectionString` + functions for accessing X11 primary selection (#894,#1056) +- Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850) +- Added definition of `GLAPIENTRY` to public header +- Added `GLFW_TRANSPARENT` window hint for enabling window framebuffer + transparency (#197,#663,#715,#723,#1078) +- Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering + (#749,#842) +- Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) +- Added macOS specific `GLFW_COCOA_RETINA_FRAMEBUFFER` window hint +- Added macOS specific `GLFW_COCOA_FRAME_AUTOSAVE` window hint (#195) +- Added macOS specific `GLFW_COCOA_GRAPHICS_SWITCHING` window hint (#377,#935) +- Added macOS specific `GLFW_COCOA_CHDIR_RESOURCES` init hint +- Added macOS specific `GLFW_COCOA_MENUBAR` init hint +- Added X11 specific `GLFW_X11_WM_CLASS_NAME` and `GLFW_X11_WM_CLASS_CLASS` init + hints (#893) +- Added `GLFW_INCLUDE_ES32` for including the OpenGL ES 3.2 header +- Added `GLFW_OSMESA_CONTEXT_API` for creating OpenGL contexts with + [OSMesa](https://www.mesa3d.org/osmesa.html) (#281) +- Added `GenerateMappings.cmake` script for updating gamepad mappings +- Removed `GLFW_USE_RETINA` compile-time option +- Removed `GLFW_USE_CHDIR` compile-time option +- Removed `GLFW_USE_MENUBAR` compile-time option +- Bugfix: Calling `glfwMaximizeWindow` on a full screen window was not ignored +- Bugfix: `GLFW_INCLUDE_VULKAN` could not be combined with the corresponding + OpenGL and OpenGL ES header macros +- Bugfix: `glfwGetInstanceProcAddress` returned `NULL` for + `vkGetInstanceProcAddr` when `_GLFW_VULKAN_STATIC` was enabled +- Bugfix: Invalid library paths were used in test and example CMake files (#930) +- Bugfix: The scancode for synthetic key release events was always zero +- Bugfix: The generated Doxyfile did not handle paths with spaces (#1081) +- [Win32] Added system error strings to relevant GLFW error descriptions (#733) +- [Win32] Moved to `WM_INPUT` for disabled cursor mode motion input (#125) +- [Win32] Removed XInput circular deadzone from joystick axis data (#1045) +- [Win32] Bugfix: Undecorated windows could not be iconified by the user (#861) +- [Win32] Bugfix: Deadzone logic could underflow with some controllers (#910) +- [Win32] Bugfix: Bitness test in `FindVulkan.cmake` was VS specific (#928) +- [Win32] Bugfix: `glfwVulkanSupported` emitted an error on systems with + a loader but no ICD (#916) +- [Win32] Bugfix: Non-iconified full sreeen windows did not prevent screen + blanking or password enabled screensavers (#851) +- [Win32] Bugfix: Mouse capture logic lost secondary release messages (#954) +- [Win32] Bugfix: The 32-bit Vulkan loader library static was not searched for +- [Win32] Bugfix: Vulkan libraries have a new path as of SDK 1.0.42.0 (#956) +- [Win32] Bugfix: Monitors with no display devices were not enumerated (#960) +- [Win32] Bugfix: Monitor events were not emitted (#784) +- [Win32] Bugfix: The Cygwin DLL was installed to the wrong directory (#1035) +- [Win32] Bugfix: Normalization of axis data via XInput was incorrect (#1045) +- [Win32] Bugfix: `glfw3native.h` would undefine a foreign `APIENTRY` (#1062) +- [Win32] Bugfix: Disabled cursor mode prevented use of caption buttons + (#650,#1071) +- [Win32] Bugfix: Returned key names did not match other platforms (#943) +- [Win32] Bugfix: Undecorated windows did not maximize to workarea (#899) +- [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) +- [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading +- [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X +- [X11] Bugfix: Dynamic X11 library loading did not use full sonames (#941) +- [X11] Bugfix: Window creation on 64-bit would read past top of stack (#951) +- [X11] Bugfix: XDND support had multiple non-conformance issues (#968) +- [X11] Bugfix: The RandR monitor path was disabled despite working RandR (#972) +- [X11] Bugfix: IM-duplicated key events would leak at low polling rates (#747) +- [X11] Bugfix: Gamma ramp setting via RandR did not validate ramp size +- [X11] Bugfix: Key name string encoding depended on current locale (#981,#983) +- [X11] Bugfix: Incremental reading of selections was not supported (#275) +- [X11] Bugfix: Selection I/O reported but did not support `COMPOUND_TEXT` +- [X11] Bugfix: Latin-1 text read from selections was not converted to UTF-8 +- [Linux] Moved to evdev for joystick input (#906,#1005) +- [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) +- [Linux] Bugfix: The joystick device path could be truncated (#1025) +- [Linux] Bugfix: `glfwInit` would fail if inotify creation failed (#833) +- [Linux] Bugfix: `strdup` was used without any required feature macro (#1055) +- [Cocoa] Added support for Vulkan window surface creation via + [MoltenVK](https://moltengl.com/moltenvk/) (#870) +- [Cocoa] Added support for loading a `MainMenu.nib` when available +- [Cocoa] Bugfix: Disabling window aspect ratio would assert (#852) +- [Cocoa] Bugfix: Window creation failed to set first responder (#876,#883) +- [Cocoa] Bugfix: Removed use of deprecated `CGDisplayIOServicePort` function + (#165,#192,#508,#511) +- [Cocoa] Bugfix: Disabled use of deprecated `CGDisplayModeCopyPixelEncoding` + function on macOS 10.12+ +- [Cocoa] Bugfix: Running in AppSandbox would emit warnings (#816,#882) +- [Cocoa] Bugfix: Windows created after the first were not cascaded (#195) +- [Cocoa] Bugfix: Leaving video mode with `glfwSetWindowMonitor` would set + incorrect position and size (#748) +- [Cocoa] Bugfix: Iconified full screen windows could not be restored (#848) +- [Cocoa] Bugfix: Value range was ignored for joystick hats and buttons (#888) +- [Cocoa] Bugfix: Full screen framebuffer was incorrectly sized for some video + modes (#682) +- [Cocoa] Bugfix: A string object for IME was updated non-idiomatically (#1050) +- [Cocoa] Bugfix: A hidden or disabled cursor would become visible when a user + notification was shown (#971,#1028) +- [Cocoa] Bugfix: Some characters did not repeat due to Press and Hold (#1010) +- [Cocoa] Bugfix: Window title was lost when full screen or undecorated (#1082) +- [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts +- [WGL] Added support for `WGL_ARB_create_context_no_error` +- [GLX] Added support for `GLX_ARB_create_context_no_error` +- [GLX] Bugfix: Context creation could segfault if no GLXFBConfigs were + available (#1040) +- [EGL] Added support for `EGL_KHR_get_all_proc_addresses` (#871) +- [EGL] Added support for `EGL_KHR_context_flush_control` +- [EGL] Bugfix: The test for `EGL_RGB_BUFFER` was invalid + + +## Contact + +On [glfw.org](http://www.glfw.org/) you can find the latest version of GLFW, as +well as news, documentation and other information about the project. + +If you have questions related to the use of GLFW, we have a +[forum](http://discourse.glfw.org/), and the `#glfw` IRC channel on +[Freenode](http://freenode.net/). + +If you have a bug to report, a patch to submit or a feature you'd like to +request, please file it in the +[issue tracker](https://github.com/glfw/glfw/issues) on GitHub. + +Finally, if you're interested in helping out with the development of GLFW or +porting it to your favorite platform, join us on the forum, GitHub or IRC. + + +## Acknowledgements + +GLFW exists because people around the world donated their time and lent their +skills. + + - Bobyshev Alexander + - Matt Arsenault + - David Avedissian + - Keith Bauer + - John Bartholomew + - Niklas Behrens + - Niklas Bergström + - Denis Bernard + - Doug Binks + - blanco + - Kyle Brenneman + - Rok Breulj + - Martin Capitanio + - David Carlier + - Arturo Castro + - Chi-kwan Chan + - Ian Clarkson + - Michał Cichoń + - Lambert Clara + - Yaron Cohen-Tal + - Omar Cornut + - Andrew Corrigan + - Bailey Cosier + - Noel Cower + - Jason Daly + - Jarrod Davis + - Olivier Delannoy + - Paul R. Deppe + - Michael Dickens + - Роман Донченко + - Mario Dorn + - Wolfgang Draxinger + - Jonathan Dummer + - Ralph Eastwood + - Fredrik Ehnbom + - Robin Eklind + - Siavash Eliasi + - Felipe Ferreira + - Michael Fogleman + - Gerald Franz + - Mário Freitas + - GeO4d + - Marcus Geelnard + - Eloi Marín Gratacós + - Stefan Gustavson + - Jonathan Hale + - Sylvain Hellegouarch + - Matthew Henry + - heromyth + - Lucas Hinderberger + - Paul Holden + - Warren Hu + - IntellectualKitty + - Aaron Jacobs + - Erik S. V. Jansson + - Toni Jovanoski + - Arseny Kapoulkine + - Cem Karan + - Osman Keskin + - Josh Kilmer + - Cameron King + - Peter Knut + - Christoph Kubisch + - Yuri Kunde Schlesner + - Konstantin Käfer + - Eric Larson + - Robin Leffmann + - Glenn Lewis + - Shane Liesegang + - Eyal Lotem + - Tristam MacDonald + - Hans Mackowiak + - Дмитри Малышев + - Zbigniew Mandziejewicz + - Célestin Marot + - Kyle McDonald + - David Medlock + - Bryce Mehring + - Jonathan Mercier + - Marcel Metz + - Liam Middlebrook + - Jonathan Miller + - Kenneth Miller + - Bruce Mitchener + - Jack Moffitt + - Jeff Molofee + - Pierre Morel + - Jon Morton + - Pierre Moulon + - Martins Mozeiko + - Julian Møller + - ndogxj + - Kristian Nielsen + - Kamil Nowakowski + - Denis Ovod + - Ozzy + - Andri Pálsson + - Peoro + - Braden Pellett + - Christopher Pelloux + - Arturo J. Pérez + - Anthony Pesch + - Orson Peters + - Emmanuel Gil Peyrot + - Cyril Pichard + - Keith Pitt + - Stanislav Podgorskiy + - Alexandre Pretyman + - Philip Rideout + - Eddie Ringle + - Jorge Rodriguez + - Ed Ropple + - Aleksey Rybalkin + - Riku Salminen + - Brandon Schaefer + - Sebastian Schuberth + - Christian Sdunek + - Matt Sealey + - Steve Sexton + - Arkady Shapkin + - Yoshiki Shibukawa + - Dmitri Shuralyov + - Daniel Skorupski + - Bradley Smith + - Patrick Snape + - Erlend Sogge Heggen + - Julian Squires + - Johannes Stein + - Pontus Stenetorp + - Michael Stocker + - Justin Stoecker + - Elviss Strazdins + - Paul Sultana + - Nathan Sweet + - TTK-Bandit + - Sergey Tikhomirov + - Arthur Tombs + - Ioannis Tsakpinis + - Samuli Tuomola + - Matthew Turner + - urraka + - Elias Vanderstuyft + - Stef Velzel + - Jari Vetoniemi + - Ricardo Vieira + - Nicholas Vitovitch + - Simon Voordouw + - Torsten Walluhn + - Patrick Walton + - Xo Wang + - Jay Weisskopf + - Frank Wille + - Ryogo Yoshimura + - Andrey Zholos + - Santi Zupancic + - Jonas Ådahl + - Lasse Öörni + - All the unmentioned and anonymous contributors in the GLFW community, for bug + reports, patches, feedback, testing and encouragement + diff --git a/src/external/glfw/deps/KHR/khrplatform.h b/src/external/glfw/deps/KHR/khrplatform.h new file mode 100644 index 00000000..c9e6f17d --- /dev/null +++ b/src/external/glfw/deps/KHR/khrplatform.h @@ -0,0 +1,282 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $ + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by sending them to the public Khronos Bugzilla + * (http://khronos.org/bugzilla) by filing a bug against product + * "Khronos (general)" component "Registry". + * + * A predefined template which fills in some of the bug fields can be + * reached using http://tinyurl.com/khrplatform-h-bugreport, but you + * must create a Bugzilla login first. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(_WIN32) && !defined(__SCITECH_SNAP__) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef _WIN64 +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/src/external/glfw/deps/getopt.c b/src/external/glfw/deps/getopt.c new file mode 100644 index 00000000..9743046f --- /dev/null +++ b/src/external/glfw/deps/getopt.c @@ -0,0 +1,230 @@ +/* Copyright (c) 2012, Kim Gräsman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Kim Gräsman nor the names of contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "getopt.h" + +#include +#include + +const int no_argument = 0; +const int required_argument = 1; +const int optional_argument = 2; + +char* optarg; +int optopt; +/* The variable optind [...] shall be initialized to 1 by the system. */ +int optind = 1; +int opterr; + +static char* optcursor = NULL; + +/* Implemented based on [1] and [2] for optional arguments. + optopt is handled FreeBSD-style, per [3]. + Other GNU and FreeBSD extensions are purely accidental. + +[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html +[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE +*/ +int getopt(int argc, char* const argv[], const char* optstring) { + int optchar = -1; + const char* optdecl = NULL; + + optarg = NULL; + opterr = 0; + optopt = 0; + + /* Unspecified, but we need it to avoid overrunning the argv bounds. */ + if (optind >= argc) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] is a null pointer, getopt() + shall return -1 without changing optind. */ + if (argv[optind] == NULL) + goto no_more_optchars; + + /* If, when getopt() is called *argv[optind] is not the character '-', + getopt() shall return -1 without changing optind. */ + if (*argv[optind] != '-') + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "-", + getopt() shall return -1 without changing optind. */ + if (strcmp(argv[optind], "-") == 0) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "--", + getopt() shall return -1 after incrementing optind. */ + if (strcmp(argv[optind], "--") == 0) { + ++optind; + goto no_more_optchars; + } + + if (optcursor == NULL || *optcursor == '\0') + optcursor = argv[optind] + 1; + + optchar = *optcursor; + + /* FreeBSD: The variable optopt saves the last known option character + returned by getopt(). */ + optopt = optchar; + + /* The getopt() function shall return the next option character (if one is + found) from argv that matches a character in optstring, if there is + one that matches. */ + optdecl = strchr(optstring, optchar); + if (optdecl) { + /* [I]f a character is followed by a colon, the option takes an + argument. */ + if (optdecl[1] == ':') { + optarg = ++optcursor; + if (*optarg == '\0') { + /* GNU extension: Two colons mean an option takes an + optional arg; if there is text in the current argv-element + (i.e., in the same word as the option name itself, for example, + "-oarg"), then it is returned in optarg, otherwise optarg is set + to zero. */ + if (optdecl[2] != ':') { + /* If the option was the last character in the string pointed to by + an element of argv, then optarg shall contain the next element + of argv, and optind shall be incremented by 2. If the resulting + value of optind is greater than argc, this indicates a missing + option-argument, and getopt() shall return an error indication. + + Otherwise, optarg shall point to the string following the + option character in that element of argv, and optind shall be + incremented by 1. + */ + if (++optind < argc) { + optarg = argv[optind]; + } else { + /* If it detects a missing option-argument, it shall return the + colon character ( ':' ) if the first character of optstring + was a colon, or a question-mark character ( '?' ) otherwise. + */ + optarg = NULL; + optchar = (optstring[0] == ':') ? ':' : '?'; + } + } else { + optarg = NULL; + } + } + + optcursor = NULL; + } + } else { + /* If getopt() encounters an option character that is not contained in + optstring, it shall return the question-mark ( '?' ) character. */ + optchar = '?'; + } + + if (optcursor == NULL || *++optcursor == '\0') + ++optind; + + return optchar; + +no_more_optchars: + optcursor = NULL; + return -1; +} + +/* Implementation based on [1]. + +[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +*/ +int getopt_long(int argc, char* const argv[], const char* optstring, + const struct option* longopts, int* longindex) { + const struct option* o = longopts; + const struct option* match = NULL; + int num_matches = 0; + size_t argument_name_length = 0; + const char* current_argument = NULL; + int retval = -1; + + optarg = NULL; + optopt = 0; + + if (optind >= argc) + return -1; + + if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) + return getopt(argc, argv, optstring); + + /* It's an option; starts with -- and is longer than two chars. */ + current_argument = argv[optind] + 2; + argument_name_length = strcspn(current_argument, "="); + for (; o->name; ++o) { + if (strncmp(o->name, current_argument, argument_name_length) == 0) { + match = o; + ++num_matches; + } + } + + if (num_matches == 1) { + /* If longindex is not NULL, it points to a variable which is set to the + index of the long option relative to longopts. */ + if (longindex) + *longindex = (int) (match - longopts); + + /* If flag is NULL, then getopt_long() shall return val. + Otherwise, getopt_long() returns 0, and flag shall point to a variable + which shall be set to val if the option is found, but left unchanged if + the option is not found. */ + if (match->flag) + *(match->flag) = match->val; + + retval = match->flag ? 0 : match->val; + + if (match->has_arg != no_argument) { + optarg = strchr(argv[optind], '='); + if (optarg != NULL) + ++optarg; + + if (match->has_arg == required_argument) { + /* Only scan the next argv for required arguments. Behavior is not + specified, but has been observed with Ubuntu and Mac OSX. */ + if (optarg == NULL && ++optind < argc) { + optarg = argv[optind]; + } + + if (optarg == NULL) + retval = ':'; + } + } else if (strchr(argv[optind], '=')) { + /* An argument was provided to a non-argument option. + I haven't seen this specified explicitly, but both GNU and BSD-based + implementations show this behavior. + */ + retval = '?'; + } + } else { + /* Unknown option or ambiguous match. */ + retval = '?'; + } + + ++optind; + return retval; +} diff --git a/src/external/glfw/deps/getopt.h b/src/external/glfw/deps/getopt.h new file mode 100644 index 00000000..e1eb540f --- /dev/null +++ b/src/external/glfw/deps/getopt.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2012, Kim Gräsman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Kim Gräsman nor the names of contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef INCLUDED_GETOPT_PORT_H +#define INCLUDED_GETOPT_PORT_H + +#if defined(__cplusplus) +extern "C" { +#endif + +extern const int no_argument; +extern const int required_argument; +extern const int optional_argument; + +extern char* optarg; +extern int optind, opterr, optopt; + +struct option { + const char* name; + int has_arg; + int* flag; + int val; +}; + +int getopt(int argc, char* const argv[], const char* optstring); + +int getopt_long(int argc, char* const argv[], + const char* optstring, const struct option* longopts, int* longindex); + +#if defined(__cplusplus) +} +#endif + +#endif // INCLUDED_GETOPT_PORT_H diff --git a/src/external/glfw/deps/glad.c b/src/external/glfw/deps/glad.c new file mode 100644 index 00000000..10b0a00e --- /dev/null +++ b/src/external/glfw/deps/glad.c @@ -0,0 +1,1678 @@ +/* + + OpenGL loader generated by glad 0.1.12a0 on Fri Sep 23 13:36:15 2016. + + Language/Generator: C/C++ + Specification: gl + APIs: gl=3.2 + Profile: compatibility + Extensions: + GL_ARB_multisample, + GL_ARB_robustness, + GL_KHR_debug + Loader: False + Local files: False + Omit khrplatform: False + + Commandline: + --profile="compatibility" --api="gl=3.2" --generator="c" --spec="gl" --no-loader --extensions="GL_ARB_multisample,GL_ARB_robustness,GL_KHR_debug" + Online: + http://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&api=gl%3D3.2&extensions=GL_ARB_multisample&extensions=GL_ARB_robustness&extensions=GL_KHR_debug +*/ + +#include +#include +#include +#include + +struct gladGLversionStruct GLVersion; + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define _GLAD_IS_SOME_NEW_VERSION 1 +#endif + +static int max_loaded_major; +static int max_loaded_minor; + +static const char *exts = NULL; +static int num_exts_i = 0; +static const char **exts_i = NULL; + +static int get_exts(void) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + exts = (const char *)glGetString(GL_EXTENSIONS); +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + int index; + + num_exts_i = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); + if (num_exts_i > 0) { + exts_i = (const char **)realloc((void *)exts_i, num_exts_i * sizeof *exts_i); + } + + if (exts_i == NULL) { + return 0; + } + + for(index = 0; index < num_exts_i; index++) { + exts_i[index] = (const char*)glGetStringi(GL_EXTENSIONS, index); + } + } +#endif + return 1; +} + +static void free_exts(void) { + if (exts_i != NULL) { + free((char **)exts_i); + exts_i = NULL; + } +} + +static int has_ext(const char *ext) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + int index; + + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + + if(strcmp(e, ext) == 0) { + return 1; + } + } + } +#endif + + return 0; +} +int GLAD_GL_VERSION_1_0; +int GLAD_GL_VERSION_1_1; +int GLAD_GL_VERSION_1_2; +int GLAD_GL_VERSION_1_3; +int GLAD_GL_VERSION_1_4; +int GLAD_GL_VERSION_1_5; +int GLAD_GL_VERSION_2_0; +int GLAD_GL_VERSION_2_1; +int GLAD_GL_VERSION_3_0; +int GLAD_GL_VERSION_3_1; +int GLAD_GL_VERSION_3_2; +PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +PFNGLWINDOWPOS2SPROC glad_glWindowPos2s; +PFNGLWINDOWPOS2IPROC glad_glWindowPos2i; +PFNGLWINDOWPOS2FPROC glad_glWindowPos2f; +PFNGLWINDOWPOS2DPROC glad_glWindowPos2d; +PFNGLVERTEX2FVPROC glad_glVertex2fv; +PFNGLINDEXIPROC glad_glIndexi; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +PFNGLRECTDVPROC glad_glRectdv; +PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +PFNGLEVALCOORD2DPROC glad_glEvalCoord2d; +PFNGLEVALCOORD2FPROC glad_glEvalCoord2f; +PFNGLINDEXDPROC glad_glIndexd; +PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +PFNGLINDEXFPROC glad_glIndexf; +PFNGLLINEWIDTHPROC glad_glLineWidth; +PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +PFNGLGETMAPFVPROC glad_glGetMapfv; +PFNGLINDEXSPROC glad_glIndexs; +PFNGLCOMPILESHADERPROC glad_glCompileShader; +PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv; +PFNGLINDEXFVPROC glad_glIndexfv; +PFNGLFOGIVPROC glad_glFogiv; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv; +PFNGLLIGHTMODELIVPROC glad_glLightModeliv; +PFNGLCOLOR4UIPROC glad_glColor4ui; +PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv; +PFNGLFOGFVPROC glad_glFogfv; +PFNGLENABLEIPROC glad_glEnablei; +PFNGLVERTEX4IVPROC glad_glVertex4iv; +PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv; +PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv; +PFNGLCREATESHADERPROC glad_glCreateShader; +PFNGLISBUFFERPROC glad_glIsBuffer; +PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +PFNGLVERTEX4FVPROC glad_glVertex4fv; +PFNGLBINDTEXTUREPROC glad_glBindTexture; +PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv; +PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; +PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv; +PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +PFNGLPOINTSIZEPROC glad_glPointSize; +PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +PFNGLCOLOR4BVPROC glad_glColor4bv; +PFNGLRASTERPOS2FPROC glad_glRasterPos2f; +PFNGLRASTERPOS2DPROC glad_glRasterPos2d; +PFNGLLOADIDENTITYPROC glad_glLoadIdentity; +PFNGLRASTERPOS2IPROC glad_glRasterPos2i; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +PFNGLCOLOR3BPROC glad_glColor3b; +PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +PFNGLEDGEFLAGPROC glad_glEdgeFlag; +PFNGLVERTEX3DPROC glad_glVertex3d; +PFNGLVERTEX3FPROC glad_glVertex3f; +PFNGLVERTEX3IPROC glad_glVertex3i; +PFNGLCOLOR3IPROC glad_glColor3i; +PFNGLUNIFORM3FPROC glad_glUniform3f; +PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +PFNGLCOLOR3SPROC glad_glColor3s; +PFNGLVERTEX3SPROC glad_glVertex3s; +PFNGLCOLORMASKIPROC glad_glColorMaski; +PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv; +PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +PFNGLVERTEX2IVPROC glad_glVertex2iv; +PFNGLCOLOR3SVPROC glad_glColor3sv; +PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +PFNGLNORMALPOINTERPROC glad_glNormalPointer; +PFNGLVERTEX4SVPROC glad_glVertex4sv; +PFNGLPASSTHROUGHPROC glad_glPassThrough; +PFNGLFOGIPROC glad_glFogi; +PFNGLBEGINPROC glad_glBegin; +PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv; +PFNGLCOLOR3UBVPROC glad_glColor3ubv; +PFNGLVERTEXPOINTERPROC glad_glVertexPointer; +PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +PFNGLDRAWARRAYSPROC glad_glDrawArrays; +PFNGLUNIFORM1UIPROC glad_glUniform1ui; +PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d; +PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f; +PFNGLLIGHTFVPROC glad_glLightfv; +PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +PFNGLCLEARPROC glad_glClear; +PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i; +PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; +PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s; +PFNGLISENABLEDPROC glad_glIsEnabled; +PFNGLSTENCILOPPROC glad_glStencilOp; +PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +PFNGLTRANSLATEFPROC glad_glTranslatef; +PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +PFNGLTRANSLATEDPROC glad_glTranslated; +PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv; +PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv; +PFNGLGETMATERIALFVPROC glad_glGetMaterialfv; +PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +PFNGLFOGCOORDFVPROC glad_glFogCoordfv; +PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +PFNGLINDEXSVPROC glad_glIndexsv; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +PFNGLVERTEX3IVPROC glad_glVertex3iv; +PFNGLBITMAPPROC glad_glBitmap; +PFNGLMATERIALIPROC glad_glMateriali; +PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +PFNGLGETQUERYIVPROC glad_glGetQueryiv; +PFNGLTEXCOORD4FPROC glad_glTexCoord4f; +PFNGLTEXCOORD4DPROC glad_glTexCoord4d; +PFNGLTEXCOORD4IPROC glad_glTexCoord4i; +PFNGLMATERIALFPROC glad_glMaterialf; +PFNGLTEXCOORD4SPROC glad_glTexCoord4s; +PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; +PFNGLISSHADERPROC glad_glIsShader; +PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s; +PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +PFNGLVERTEX3DVPROC glad_glVertex3dv; +PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +PFNGLENABLEPROC glad_glEnable; +PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; +PFNGLCOLOR4FVPROC glad_glColor4fv; +PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv; +PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv; +PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv; +PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i; +PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv; +PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv; +PFNGLTEXGENFPROC glad_glTexGenf; +PFNGLGETPOINTERVPROC glad_glGetPointerv; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +PFNGLNORMAL3FVPROC glad_glNormal3fv; +PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s; +PFNGLDEPTHRANGEPROC glad_glDepthRange; +PFNGLFRUSTUMPROC glad_glFrustum; +PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv; +PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +PFNGLPUSHMATRIXPROC glad_glPushMatrix; +PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv; +PFNGLORTHOPROC glad_glOrtho; +PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; +PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv; +PFNGLCLEARINDEXPROC glad_glClearIndex; +PFNGLMAP1DPROC glad_glMap1d; +PFNGLMAP1FPROC glad_glMap1f; +PFNGLFLUSHPROC glad_glFlush; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +PFNGLINDEXIVPROC glad_glIndexiv; +PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +PFNGLPIXELZOOMPROC glad_glPixelZoom; +PFNGLFENCESYNCPROC glad_glFenceSync; +PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; +PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +PFNGLLIGHTIPROC glad_glLighti; +PFNGLLIGHTFPROC glad_glLightf; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +PFNGLCLAMPCOLORPROC glad_glClampColor; +PFNGLUNIFORM4IVPROC glad_glUniform4iv; +PFNGLCLEARSTENCILPROC glad_glClearStencil; +PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv; +PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv; +PFNGLGENTEXTURESPROC glad_glGenTextures; +PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv; +PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +PFNGLINDEXPOINTERPROC glad_glIndexPointer; +PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +PFNGLISSYNCPROC glad_glIsSync; +PFNGLVERTEX2FPROC glad_glVertex2f; +PFNGLVERTEX2DPROC glad_glVertex2d; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +PFNGLUNIFORM2IPROC glad_glUniform2i; +PFNGLMAPGRID2DPROC glad_glMapGrid2d; +PFNGLMAPGRID2FPROC glad_glMapGrid2f; +PFNGLVERTEX2IPROC glad_glVertex2i; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +PFNGLVERTEX2SPROC glad_glVertex2s; +PFNGLNORMAL3BVPROC glad_glNormal3bv; +PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv; +PFNGLVERTEX3SVPROC glad_glVertex3sv; +PFNGLGENQUERIESPROC glad_glGenQueries; +PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv; +PFNGLTEXENVFPROC glad_glTexEnvf; +PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; +PFNGLFOGCOORDDPROC glad_glFogCoordd; +PFNGLFOGCOORDFPROC glad_glFogCoordf; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +PFNGLTEXENVIPROC glad_glTexEnvi; +PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv; +PFNGLISENABLEDIPROC glad_glIsEnabledi; +PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv; +PFNGLUNIFORM2IVPROC glad_glUniform2iv; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +PFNGLMATRIXMODEPROC glad_glMatrixMode; +PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer; +PFNGLGETMAPIVPROC glad_glGetMapiv; +PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +PFNGLGETSHADERIVPROC glad_glGetShaderiv; +PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d; +PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f; +PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; +PFNGLCALLLISTPROC glad_glCallList; +PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv; +PFNGLGETDOUBLEVPROC glad_glGetDoublev; +PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv; +PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +PFNGLLIGHTMODELFPROC glad_glLightModelf; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +PFNGLVERTEX2SVPROC glad_glVertex2sv; +PFNGLLIGHTMODELIPROC glad_glLightModeli; +PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv; +PFNGLUNIFORM3FVPROC glad_glUniform3fv; +PFNGLPIXELSTOREIPROC glad_glPixelStorei; +PFNGLCALLLISTSPROC glad_glCallLists; +PFNGLMAPBUFFERPROC glad_glMapBuffer; +PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d; +PFNGLTEXCOORD3IPROC glad_glTexCoord3i; +PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv; +PFNGLRASTERPOS3IPROC glad_glRasterPos3i; +PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b; +PFNGLRASTERPOS3DPROC glad_glRasterPos3d; +PFNGLRASTERPOS3FPROC glad_glRasterPos3f; +PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +PFNGLTEXCOORD3FPROC glad_glTexCoord3f; +PFNGLDELETESYNCPROC glad_glDeleteSync; +PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +PFNGLTEXCOORD3SPROC glad_glTexCoord3s; +PFNGLUNIFORM3IVPROC glad_glUniform3iv; +PFNGLRASTERPOS3SPROC glad_glRasterPos3s; +PFNGLPOLYGONMODEPROC glad_glPolygonMode; +PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; +PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident; +PFNGLISLISTPROC glad_glIsList; +PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv; +PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv; +PFNGLCOLOR4SPROC glad_glColor4s; +PFNGLUSEPROGRAMPROC glad_glUseProgram; +PFNGLLINESTIPPLEPROC glad_glLineStipple; +PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv; +PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +PFNGLCOLOR4BPROC glad_glColor4b; +PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f; +PFNGLCOLOR4FPROC glad_glColor4f; +PFNGLCOLOR4DPROC glad_glColor4d; +PFNGLCOLOR4IPROC glad_glColor4i; +PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; +PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv; +PFNGLVERTEX2DVPROC glad_glVertex2dv; +PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv; +PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +PFNGLFINISHPROC glad_glFinish; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +PFNGLDELETESHADERPROC glad_glDeleteShader; +PFNGLDRAWELEMENTSPROC glad_glDrawElements; +PFNGLRASTERPOS2SPROC glad_glRasterPos2s; +PFNGLGETMAPDVPROC glad_glGetMapdv; +PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +PFNGLMATERIALFVPROC glad_glMaterialfv; +PFNGLVIEWPORTPROC glad_glViewport; +PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +PFNGLINDEXDVPROC glad_glIndexdv; +PFNGLTEXCOORD3DPROC glad_glTexCoord3d; +PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv; +PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +PFNGLCLEARDEPTHPROC glad_glClearDepth; +PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +PFNGLTEXBUFFERPROC glad_glTexBuffer; +PFNGLPOPNAMEPROC glad_glPopName; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +PFNGLPIXELSTOREFPROC glad_glPixelStoref; +PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv; +PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv; +PFNGLRECTIPROC glad_glRecti; +PFNGLCOLOR4UBPROC glad_glColor4ub; +PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf; +PFNGLRECTFPROC glad_glRectf; +PFNGLRECTDPROC glad_glRectd; +PFNGLNORMAL3SVPROC glad_glNormal3sv; +PFNGLNEWLISTPROC glad_glNewList; +PFNGLCOLOR4USPROC glad_glColor4us; +PFNGLLINKPROGRAMPROC glad_glLinkProgram; +PFNGLHINTPROC glad_glHint; +PFNGLRECTSPROC glad_glRects; +PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv; +PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv; +PFNGLGETSTRINGPROC glad_glGetString; +PFNGLEDGEFLAGVPROC glad_glEdgeFlagv; +PFNGLDETACHSHADERPROC glad_glDetachShader; +PFNGLSCALEFPROC glad_glScalef; +PFNGLENDQUERYPROC glad_glEndQuery; +PFNGLSCALEDPROC glad_glScaled; +PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer; +PFNGLCOPYPIXELSPROC glad_glCopyPixels; +PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +PFNGLPOPATTRIBPROC glad_glPopAttrib; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +PFNGLINITNAMESPROC glad_glInitNames; +PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; +PFNGLCOLOR3DVPROC glad_glColor3dv; +PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +PFNGLWAITSYNCPROC glad_glWaitSync; +PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +PFNGLCOLORMATERIALPROC glad_glColorMaterial; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +PFNGLUNIFORM1FPROC glad_glUniform1f; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +PFNGLRENDERMODEPROC glad_glRenderMode; +PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv; +PFNGLUNIFORM1IPROC glad_glUniform1i; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +PFNGLUNIFORM3IPROC glad_glUniform3i; +PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +PFNGLDISABLEPROC glad_glDisable; +PFNGLLOGICOPPROC glad_glLogicOp; +PFNGLEVALPOINT2PROC glad_glEvalPoint2; +PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf; +PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i; +PFNGLUNIFORM4UIPROC glad_glUniform4ui; +PFNGLCOLOR3FPROC glad_glColor3f; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv; +PFNGLRECTFVPROC glad_glRectfv; +PFNGLCULLFACEPROC glad_glCullFace; +PFNGLGETLIGHTFVPROC glad_glGetLightfv; +PFNGLCOLOR3DPROC glad_glColor3d; +PFNGLTEXGENDPROC glad_glTexGend; +PFNGLTEXGENIPROC glad_glTexGeni; +PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s; +PFNGLGETSTRINGIPROC glad_glGetStringi; +PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i; +PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f; +PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d; +PFNGLATTACHSHADERPROC glad_glAttachShader; +PFNGLFOGCOORDDVPROC glad_glFogCoorddv; +PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +PFNGLGETTEXGENFVPROC glad_glGetTexGenfv; +PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer; +PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; +PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +PFNGLTEXGENIVPROC glad_glTexGeniv; +PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv; +PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv; +PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture; +PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us; +PFNGLTEXENVFVPROC glad_glTexEnvfv; +PFNGLREADBUFFERPROC glad_glReadBuffer; +PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv; +PFNGLLIGHTMODELFVPROC glad_glLightModelfv; +PFNGLDELETELISTSPROC glad_glDeleteLists; +PFNGLGETCLIPPLANEPROC glad_glGetClipPlane; +PFNGLVERTEX4DVPROC glad_glVertex4dv; +PFNGLTEXCOORD2DPROC glad_glTexCoord2d; +PFNGLPOPMATRIXPROC glad_glPopMatrix; +PFNGLTEXCOORD2FPROC glad_glTexCoord2f; +PFNGLCOLOR4IVPROC glad_glColor4iv; +PFNGLINDEXUBVPROC glad_glIndexubv; +PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +PFNGLTEXCOORD2IPROC glad_glTexCoord2i; +PFNGLRASTERPOS4DPROC glad_glRasterPos4d; +PFNGLRASTERPOS4FPROC glad_glRasterPos4f; +PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +PFNGLTEXCOORD2SPROC glad_glTexCoord2s; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +PFNGLVERTEX3FVPROC glad_glVertex3fv; +PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv; +PFNGLMATERIALIVPROC glad_glMaterialiv; +PFNGLISPROGRAMPROC glad_glIsProgram; +PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +PFNGLVERTEX4SPROC glad_glVertex4s; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +PFNGLNORMAL3DVPROC glad_glNormal3dv; +PFNGLUNIFORM4IPROC glad_glUniform4i; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +PFNGLROTATEDPROC glad_glRotated; +PFNGLROTATEFPROC glad_glRotatef; +PFNGLVERTEX4IPROC glad_glVertex4i; +PFNGLREADPIXELSPROC glad_glReadPixels; +PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +PFNGLLOADNAMEPROC glad_glLoadName; +PFNGLUNIFORM4FPROC glad_glUniform4f; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +PFNGLSHADEMODELPROC glad_glShadeModel; +PFNGLMAPGRID1DPROC glad_glMapGrid1d; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +PFNGLMAPGRID1FPROC glad_glMapGrid1f; +PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState; +PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; +PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer; +PFNGLALPHAFUNCPROC glad_glAlphaFunc; +PFNGLUNIFORM1IVPROC glad_glUniform1iv; +PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv; +PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +PFNGLSTENCILFUNCPROC glad_glStencilFunc; +PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv; +PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; +PFNGLCOLOR4UIVPROC glad_glColor4uiv; +PFNGLRECTIVPROC glad_glRectiv; +PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv; +PFNGLEVALMESH2PROC glad_glEvalMesh2; +PFNGLEVALMESH1PROC glad_glEvalMesh1; +PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer; +PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv; +PFNGLCOLOR4UBVPROC glad_glColor4ubv; +PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd; +PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf; +PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv; +PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +PFNGLTEXENVIVPROC glad_glTexEnviv; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +PFNGLGENBUFFERSPROC glad_glGenBuffers; +PFNGLSELECTBUFFERPROC glad_glSelectBuffer; +PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +PFNGLPUSHATTRIBPROC glad_glPushAttrib; +PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +PFNGLBLENDFUNCPROC glad_glBlendFunc; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +PFNGLLIGHTIVPROC glad_glLightiv; +PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; +PFNGLTEXGENFVPROC glad_glTexGenfv; +PFNGLENDPROC glad_glEnd; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +PFNGLSCISSORPROC glad_glScissor; +PFNGLCLIPPLANEPROC glad_glClipPlane; +PFNGLPUSHNAMEPROC glad_glPushName; +PFNGLTEXGENDVPROC glad_glTexGendv; +PFNGLINDEXUBPROC glad_glIndexub; +PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv; +PFNGLRASTERPOS4IPROC glad_glRasterPos4i; +PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd; +PFNGLCLEARCOLORPROC glad_glClearColor; +PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +PFNGLNORMAL3SPROC glad_glNormal3s; +PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +PFNGLBLENDCOLORPROC glad_glBlendColor; +PFNGLWINDOWPOS3DPROC glad_glWindowPos3d; +PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +PFNGLUNIFORM3UIPROC glad_glUniform3ui; +PFNGLCOLOR4DVPROC glad_glColor4dv; +PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +PFNGLUNIFORM2FVPROC glad_glUniform2fv; +PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub; +PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui; +PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv; +PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +PFNGLNORMAL3IVPROC glad_glNormal3iv; +PFNGLWINDOWPOS3SPROC glad_glWindowPos3s; +PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +PFNGLWINDOWPOS3IPROC glad_glWindowPos3i; +PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s; +PFNGLWINDOWPOS3FPROC glad_glWindowPos3f; +PFNGLCOLOR3USPROC glad_glColor3us; +PFNGLCOLOR3UIVPROC glad_glColor3uiv; +PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +PFNGLGETLIGHTIVPROC glad_glGetLightiv; +PFNGLDEPTHFUNCPROC glad_glDepthFunc; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +PFNGLLISTBASEPROC glad_glListBase; +PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f; +PFNGLCOLOR3UBPROC glad_glColor3ub; +PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d; +PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +PFNGLCOLOR3UIPROC glad_glColor3ui; +PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i; +PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; +PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv; +PFNGLCOLORMASKPROC glad_glColorMask; +PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +PFNGLRASTERPOS4SPROC glad_glRasterPos4s; +PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv; +PFNGLCOLOR4SVPROC glad_glColor4sv; +PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib; +PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +PFNGLFOGFPROC glad_glFogf; +PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +PFNGLCOLOR3IVPROC glad_glColor3iv; +PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +PFNGLTEXCOORD1IPROC glad_glTexCoord1i; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +PFNGLTEXCOORD1DPROC glad_glTexCoord1d; +PFNGLTEXCOORD1FPROC glad_glTexCoord1f; +PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv; +PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +PFNGLTEXCOORD1SPROC glad_glTexCoord1s; +PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +PFNGLGENLISTSPROC glad_glGenLists; +PFNGLCOLOR3BVPROC glad_glColor3bv; +PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; +PFNGLGETTEXGENDVPROC glad_glGetTexGendv; +PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +PFNGLENDLISTPROC glad_glEndList; +PFNGLUNIFORM2UIPROC glad_glUniform2ui; +PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +PFNGLCOLOR3USVPROC glad_glColor3usv; +PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv; +PFNGLDISABLEIPROC glad_glDisablei; +PFNGLINDEXMASKPROC glad_glIndexMask; +PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib; +PFNGLSHADERSOURCEPROC glad_glShaderSource; +PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; +PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +PFNGLCLEARACCUMPROC glad_glClearAccum; +PFNGLGETSYNCIVPROC glad_glGetSynciv; +PFNGLUNIFORM2FPROC glad_glUniform2f; +PFNGLBEGINQUERYPROC glad_glBeginQuery; +PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; +PFNGLBINDBUFFERPROC glad_glBindBuffer; +PFNGLMAP2DPROC glad_glMap2d; +PFNGLMAP2FPROC glad_glMap2f; +PFNGLVERTEX4DPROC glad_glVertex4d; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv; +PFNGLBUFFERDATAPROC glad_glBufferData; +PFNGLEVALPOINT1PROC glad_glEvalPoint1; +PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv; +PFNGLGETERRORPROC glad_glGetError; +PFNGLGETTEXENVIVPROC glad_glGetTexEnviv; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +PFNGLGETFLOATVPROC glad_glGetFloatv; +PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +PFNGLEVALCOORD1DPROC glad_glEvalCoord1d; +PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +PFNGLEVALCOORD1FPROC glad_glEvalCoord1f; +PFNGLPIXELMAPFVPROC glad_glPixelMapfv; +PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv; +PFNGLGETINTEGERVPROC glad_glGetIntegerv; +PFNGLACCUMPROC glad_glAccum; +PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv; +PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv; +PFNGLISQUERYPROC glad_glIsQuery; +PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +PFNGLSTENCILMASKPROC glad_glStencilMask; +PFNGLDRAWPIXELSPROC glad_glDrawPixels; +PFNGLMULTMATRIXDPROC glad_glMultMatrixd; +PFNGLMULTMATRIXFPROC glad_glMultMatrixf; +PFNGLISTEXTUREPROC glad_glIsTexture; +PFNGLGETMATERIALIVPROC glad_glGetMaterialiv; +PFNGLUNIFORM1FVPROC glad_glUniform1fv; +PFNGLLOADMATRIXFPROC glad_glLoadMatrixf; +PFNGLLOADMATRIXDPROC glad_glLoadMatrixd; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +PFNGLVERTEX4FPROC glad_glVertex4f; +PFNGLRECTSVPROC glad_glRectsv; +PFNGLCOLOR4USVPROC glad_glColor4usv; +PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple; +PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays; +PFNGLNORMAL3IPROC glad_glNormal3i; +PFNGLNORMAL3FPROC glad_glNormal3f; +PFNGLNORMAL3DPROC glad_glNormal3d; +PFNGLNORMAL3BPROC glad_glNormal3b; +PFNGLPIXELMAPUSVPROC glad_glPixelMapusv; +PFNGLGETTEXGENIVPROC glad_glGetTexGeniv; +PFNGLARRAYELEMENTPROC glad_glArrayElement; +PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; +PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +PFNGLDEPTHMASKPROC glad_glDepthMask; +PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +PFNGLCOLOR3FVPROC glad_glColor3fv; +PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +PFNGLUNIFORM4FVPROC glad_glUniform4fv; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +PFNGLCOLORPOINTERPROC glad_glColorPointer; +PFNGLFRONTFACEPROC glad_glFrontFace; +PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +int GLAD_GL_KHR_debug; +int GLAD_GL_ARB_robustness; +int GLAD_GL_ARB_multisample; +PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB; +PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB; +PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB; +PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB; +PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB; +PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB; +PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB; +PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB; +PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB; +PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB; +PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB; +PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB; +PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB; +PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB; +PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB; +PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB; +PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB; +PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB; +PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB; +PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB; +PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB; +PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl; +PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert; +PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback; +PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog; +PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup; +PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup; +PFNGLOBJECTLABELPROC glad_glObjectLabel; +PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel; +PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel; +PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel; +PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR; +PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR; +PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR; +PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR; +PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR; +PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR; +PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR; +PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR; +PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR; +PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR; +PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR; +static void load_GL_VERSION_1_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_0) return; + glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); + glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); + glad_glHint = (PFNGLHINTPROC)load("glHint"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); + glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize"); + glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode"); + glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); + glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); + glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer"); + glad_glClear = (PFNGLCLEARPROC)load("glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); + glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); + glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); + glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); + glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); + glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); + glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); + glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); + glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); + glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); + glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); + glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); + glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev"); + glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); + glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); + glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); + glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); + glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); + glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange"); + glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); + glad_glNewList = (PFNGLNEWLISTPROC)load("glNewList"); + glad_glEndList = (PFNGLENDLISTPROC)load("glEndList"); + glad_glCallList = (PFNGLCALLLISTPROC)load("glCallList"); + glad_glCallLists = (PFNGLCALLLISTSPROC)load("glCallLists"); + glad_glDeleteLists = (PFNGLDELETELISTSPROC)load("glDeleteLists"); + glad_glGenLists = (PFNGLGENLISTSPROC)load("glGenLists"); + glad_glListBase = (PFNGLLISTBASEPROC)load("glListBase"); + glad_glBegin = (PFNGLBEGINPROC)load("glBegin"); + glad_glBitmap = (PFNGLBITMAPPROC)load("glBitmap"); + glad_glColor3b = (PFNGLCOLOR3BPROC)load("glColor3b"); + glad_glColor3bv = (PFNGLCOLOR3BVPROC)load("glColor3bv"); + glad_glColor3d = (PFNGLCOLOR3DPROC)load("glColor3d"); + glad_glColor3dv = (PFNGLCOLOR3DVPROC)load("glColor3dv"); + glad_glColor3f = (PFNGLCOLOR3FPROC)load("glColor3f"); + glad_glColor3fv = (PFNGLCOLOR3FVPROC)load("glColor3fv"); + glad_glColor3i = (PFNGLCOLOR3IPROC)load("glColor3i"); + glad_glColor3iv = (PFNGLCOLOR3IVPROC)load("glColor3iv"); + glad_glColor3s = (PFNGLCOLOR3SPROC)load("glColor3s"); + glad_glColor3sv = (PFNGLCOLOR3SVPROC)load("glColor3sv"); + glad_glColor3ub = (PFNGLCOLOR3UBPROC)load("glColor3ub"); + glad_glColor3ubv = (PFNGLCOLOR3UBVPROC)load("glColor3ubv"); + glad_glColor3ui = (PFNGLCOLOR3UIPROC)load("glColor3ui"); + glad_glColor3uiv = (PFNGLCOLOR3UIVPROC)load("glColor3uiv"); + glad_glColor3us = (PFNGLCOLOR3USPROC)load("glColor3us"); + glad_glColor3usv = (PFNGLCOLOR3USVPROC)load("glColor3usv"); + glad_glColor4b = (PFNGLCOLOR4BPROC)load("glColor4b"); + glad_glColor4bv = (PFNGLCOLOR4BVPROC)load("glColor4bv"); + glad_glColor4d = (PFNGLCOLOR4DPROC)load("glColor4d"); + glad_glColor4dv = (PFNGLCOLOR4DVPROC)load("glColor4dv"); + glad_glColor4f = (PFNGLCOLOR4FPROC)load("glColor4f"); + glad_glColor4fv = (PFNGLCOLOR4FVPROC)load("glColor4fv"); + glad_glColor4i = (PFNGLCOLOR4IPROC)load("glColor4i"); + glad_glColor4iv = (PFNGLCOLOR4IVPROC)load("glColor4iv"); + glad_glColor4s = (PFNGLCOLOR4SPROC)load("glColor4s"); + glad_glColor4sv = (PFNGLCOLOR4SVPROC)load("glColor4sv"); + glad_glColor4ub = (PFNGLCOLOR4UBPROC)load("glColor4ub"); + glad_glColor4ubv = (PFNGLCOLOR4UBVPROC)load("glColor4ubv"); + glad_glColor4ui = (PFNGLCOLOR4UIPROC)load("glColor4ui"); + glad_glColor4uiv = (PFNGLCOLOR4UIVPROC)load("glColor4uiv"); + glad_glColor4us = (PFNGLCOLOR4USPROC)load("glColor4us"); + glad_glColor4usv = (PFNGLCOLOR4USVPROC)load("glColor4usv"); + glad_glEdgeFlag = (PFNGLEDGEFLAGPROC)load("glEdgeFlag"); + glad_glEdgeFlagv = (PFNGLEDGEFLAGVPROC)load("glEdgeFlagv"); + glad_glEnd = (PFNGLENDPROC)load("glEnd"); + glad_glIndexd = (PFNGLINDEXDPROC)load("glIndexd"); + glad_glIndexdv = (PFNGLINDEXDVPROC)load("glIndexdv"); + glad_glIndexf = (PFNGLINDEXFPROC)load("glIndexf"); + glad_glIndexfv = (PFNGLINDEXFVPROC)load("glIndexfv"); + glad_glIndexi = (PFNGLINDEXIPROC)load("glIndexi"); + glad_glIndexiv = (PFNGLINDEXIVPROC)load("glIndexiv"); + glad_glIndexs = (PFNGLINDEXSPROC)load("glIndexs"); + glad_glIndexsv = (PFNGLINDEXSVPROC)load("glIndexsv"); + glad_glNormal3b = (PFNGLNORMAL3BPROC)load("glNormal3b"); + glad_glNormal3bv = (PFNGLNORMAL3BVPROC)load("glNormal3bv"); + glad_glNormal3d = (PFNGLNORMAL3DPROC)load("glNormal3d"); + glad_glNormal3dv = (PFNGLNORMAL3DVPROC)load("glNormal3dv"); + glad_glNormal3f = (PFNGLNORMAL3FPROC)load("glNormal3f"); + glad_glNormal3fv = (PFNGLNORMAL3FVPROC)load("glNormal3fv"); + glad_glNormal3i = (PFNGLNORMAL3IPROC)load("glNormal3i"); + glad_glNormal3iv = (PFNGLNORMAL3IVPROC)load("glNormal3iv"); + glad_glNormal3s = (PFNGLNORMAL3SPROC)load("glNormal3s"); + glad_glNormal3sv = (PFNGLNORMAL3SVPROC)load("glNormal3sv"); + glad_glRasterPos2d = (PFNGLRASTERPOS2DPROC)load("glRasterPos2d"); + glad_glRasterPos2dv = (PFNGLRASTERPOS2DVPROC)load("glRasterPos2dv"); + glad_glRasterPos2f = (PFNGLRASTERPOS2FPROC)load("glRasterPos2f"); + glad_glRasterPos2fv = (PFNGLRASTERPOS2FVPROC)load("glRasterPos2fv"); + glad_glRasterPos2i = (PFNGLRASTERPOS2IPROC)load("glRasterPos2i"); + glad_glRasterPos2iv = (PFNGLRASTERPOS2IVPROC)load("glRasterPos2iv"); + glad_glRasterPos2s = (PFNGLRASTERPOS2SPROC)load("glRasterPos2s"); + glad_glRasterPos2sv = (PFNGLRASTERPOS2SVPROC)load("glRasterPos2sv"); + glad_glRasterPos3d = (PFNGLRASTERPOS3DPROC)load("glRasterPos3d"); + glad_glRasterPos3dv = (PFNGLRASTERPOS3DVPROC)load("glRasterPos3dv"); + glad_glRasterPos3f = (PFNGLRASTERPOS3FPROC)load("glRasterPos3f"); + glad_glRasterPos3fv = (PFNGLRASTERPOS3FVPROC)load("glRasterPos3fv"); + glad_glRasterPos3i = (PFNGLRASTERPOS3IPROC)load("glRasterPos3i"); + glad_glRasterPos3iv = (PFNGLRASTERPOS3IVPROC)load("glRasterPos3iv"); + glad_glRasterPos3s = (PFNGLRASTERPOS3SPROC)load("glRasterPos3s"); + glad_glRasterPos3sv = (PFNGLRASTERPOS3SVPROC)load("glRasterPos3sv"); + glad_glRasterPos4d = (PFNGLRASTERPOS4DPROC)load("glRasterPos4d"); + glad_glRasterPos4dv = (PFNGLRASTERPOS4DVPROC)load("glRasterPos4dv"); + glad_glRasterPos4f = (PFNGLRASTERPOS4FPROC)load("glRasterPos4f"); + glad_glRasterPos4fv = (PFNGLRASTERPOS4FVPROC)load("glRasterPos4fv"); + glad_glRasterPos4i = (PFNGLRASTERPOS4IPROC)load("glRasterPos4i"); + glad_glRasterPos4iv = (PFNGLRASTERPOS4IVPROC)load("glRasterPos4iv"); + glad_glRasterPos4s = (PFNGLRASTERPOS4SPROC)load("glRasterPos4s"); + glad_glRasterPos4sv = (PFNGLRASTERPOS4SVPROC)load("glRasterPos4sv"); + glad_glRectd = (PFNGLRECTDPROC)load("glRectd"); + glad_glRectdv = (PFNGLRECTDVPROC)load("glRectdv"); + glad_glRectf = (PFNGLRECTFPROC)load("glRectf"); + glad_glRectfv = (PFNGLRECTFVPROC)load("glRectfv"); + glad_glRecti = (PFNGLRECTIPROC)load("glRecti"); + glad_glRectiv = (PFNGLRECTIVPROC)load("glRectiv"); + glad_glRects = (PFNGLRECTSPROC)load("glRects"); + glad_glRectsv = (PFNGLRECTSVPROC)load("glRectsv"); + glad_glTexCoord1d = (PFNGLTEXCOORD1DPROC)load("glTexCoord1d"); + glad_glTexCoord1dv = (PFNGLTEXCOORD1DVPROC)load("glTexCoord1dv"); + glad_glTexCoord1f = (PFNGLTEXCOORD1FPROC)load("glTexCoord1f"); + glad_glTexCoord1fv = (PFNGLTEXCOORD1FVPROC)load("glTexCoord1fv"); + glad_glTexCoord1i = (PFNGLTEXCOORD1IPROC)load("glTexCoord1i"); + glad_glTexCoord1iv = (PFNGLTEXCOORD1IVPROC)load("glTexCoord1iv"); + glad_glTexCoord1s = (PFNGLTEXCOORD1SPROC)load("glTexCoord1s"); + glad_glTexCoord1sv = (PFNGLTEXCOORD1SVPROC)load("glTexCoord1sv"); + glad_glTexCoord2d = (PFNGLTEXCOORD2DPROC)load("glTexCoord2d"); + glad_glTexCoord2dv = (PFNGLTEXCOORD2DVPROC)load("glTexCoord2dv"); + glad_glTexCoord2f = (PFNGLTEXCOORD2FPROC)load("glTexCoord2f"); + glad_glTexCoord2fv = (PFNGLTEXCOORD2FVPROC)load("glTexCoord2fv"); + glad_glTexCoord2i = (PFNGLTEXCOORD2IPROC)load("glTexCoord2i"); + glad_glTexCoord2iv = (PFNGLTEXCOORD2IVPROC)load("glTexCoord2iv"); + glad_glTexCoord2s = (PFNGLTEXCOORD2SPROC)load("glTexCoord2s"); + glad_glTexCoord2sv = (PFNGLTEXCOORD2SVPROC)load("glTexCoord2sv"); + glad_glTexCoord3d = (PFNGLTEXCOORD3DPROC)load("glTexCoord3d"); + glad_glTexCoord3dv = (PFNGLTEXCOORD3DVPROC)load("glTexCoord3dv"); + glad_glTexCoord3f = (PFNGLTEXCOORD3FPROC)load("glTexCoord3f"); + glad_glTexCoord3fv = (PFNGLTEXCOORD3FVPROC)load("glTexCoord3fv"); + glad_glTexCoord3i = (PFNGLTEXCOORD3IPROC)load("glTexCoord3i"); + glad_glTexCoord3iv = (PFNGLTEXCOORD3IVPROC)load("glTexCoord3iv"); + glad_glTexCoord3s = (PFNGLTEXCOORD3SPROC)load("glTexCoord3s"); + glad_glTexCoord3sv = (PFNGLTEXCOORD3SVPROC)load("glTexCoord3sv"); + glad_glTexCoord4d = (PFNGLTEXCOORD4DPROC)load("glTexCoord4d"); + glad_glTexCoord4dv = (PFNGLTEXCOORD4DVPROC)load("glTexCoord4dv"); + glad_glTexCoord4f = (PFNGLTEXCOORD4FPROC)load("glTexCoord4f"); + glad_glTexCoord4fv = (PFNGLTEXCOORD4FVPROC)load("glTexCoord4fv"); + glad_glTexCoord4i = (PFNGLTEXCOORD4IPROC)load("glTexCoord4i"); + glad_glTexCoord4iv = (PFNGLTEXCOORD4IVPROC)load("glTexCoord4iv"); + glad_glTexCoord4s = (PFNGLTEXCOORD4SPROC)load("glTexCoord4s"); + glad_glTexCoord4sv = (PFNGLTEXCOORD4SVPROC)load("glTexCoord4sv"); + glad_glVertex2d = (PFNGLVERTEX2DPROC)load("glVertex2d"); + glad_glVertex2dv = (PFNGLVERTEX2DVPROC)load("glVertex2dv"); + glad_glVertex2f = (PFNGLVERTEX2FPROC)load("glVertex2f"); + glad_glVertex2fv = (PFNGLVERTEX2FVPROC)load("glVertex2fv"); + glad_glVertex2i = (PFNGLVERTEX2IPROC)load("glVertex2i"); + glad_glVertex2iv = (PFNGLVERTEX2IVPROC)load("glVertex2iv"); + glad_glVertex2s = (PFNGLVERTEX2SPROC)load("glVertex2s"); + glad_glVertex2sv = (PFNGLVERTEX2SVPROC)load("glVertex2sv"); + glad_glVertex3d = (PFNGLVERTEX3DPROC)load("glVertex3d"); + glad_glVertex3dv = (PFNGLVERTEX3DVPROC)load("glVertex3dv"); + glad_glVertex3f = (PFNGLVERTEX3FPROC)load("glVertex3f"); + glad_glVertex3fv = (PFNGLVERTEX3FVPROC)load("glVertex3fv"); + glad_glVertex3i = (PFNGLVERTEX3IPROC)load("glVertex3i"); + glad_glVertex3iv = (PFNGLVERTEX3IVPROC)load("glVertex3iv"); + glad_glVertex3s = (PFNGLVERTEX3SPROC)load("glVertex3s"); + glad_glVertex3sv = (PFNGLVERTEX3SVPROC)load("glVertex3sv"); + glad_glVertex4d = (PFNGLVERTEX4DPROC)load("glVertex4d"); + glad_glVertex4dv = (PFNGLVERTEX4DVPROC)load("glVertex4dv"); + glad_glVertex4f = (PFNGLVERTEX4FPROC)load("glVertex4f"); + glad_glVertex4fv = (PFNGLVERTEX4FVPROC)load("glVertex4fv"); + glad_glVertex4i = (PFNGLVERTEX4IPROC)load("glVertex4i"); + glad_glVertex4iv = (PFNGLVERTEX4IVPROC)load("glVertex4iv"); + glad_glVertex4s = (PFNGLVERTEX4SPROC)load("glVertex4s"); + glad_glVertex4sv = (PFNGLVERTEX4SVPROC)load("glVertex4sv"); + glad_glClipPlane = (PFNGLCLIPPLANEPROC)load("glClipPlane"); + glad_glColorMaterial = (PFNGLCOLORMATERIALPROC)load("glColorMaterial"); + glad_glFogf = (PFNGLFOGFPROC)load("glFogf"); + glad_glFogfv = (PFNGLFOGFVPROC)load("glFogfv"); + glad_glFogi = (PFNGLFOGIPROC)load("glFogi"); + glad_glFogiv = (PFNGLFOGIVPROC)load("glFogiv"); + glad_glLightf = (PFNGLLIGHTFPROC)load("glLightf"); + glad_glLightfv = (PFNGLLIGHTFVPROC)load("glLightfv"); + glad_glLighti = (PFNGLLIGHTIPROC)load("glLighti"); + glad_glLightiv = (PFNGLLIGHTIVPROC)load("glLightiv"); + glad_glLightModelf = (PFNGLLIGHTMODELFPROC)load("glLightModelf"); + glad_glLightModelfv = (PFNGLLIGHTMODELFVPROC)load("glLightModelfv"); + glad_glLightModeli = (PFNGLLIGHTMODELIPROC)load("glLightModeli"); + glad_glLightModeliv = (PFNGLLIGHTMODELIVPROC)load("glLightModeliv"); + glad_glLineStipple = (PFNGLLINESTIPPLEPROC)load("glLineStipple"); + glad_glMaterialf = (PFNGLMATERIALFPROC)load("glMaterialf"); + glad_glMaterialfv = (PFNGLMATERIALFVPROC)load("glMaterialfv"); + glad_glMateriali = (PFNGLMATERIALIPROC)load("glMateriali"); + glad_glMaterialiv = (PFNGLMATERIALIVPROC)load("glMaterialiv"); + glad_glPolygonStipple = (PFNGLPOLYGONSTIPPLEPROC)load("glPolygonStipple"); + glad_glShadeModel = (PFNGLSHADEMODELPROC)load("glShadeModel"); + glad_glTexEnvf = (PFNGLTEXENVFPROC)load("glTexEnvf"); + glad_glTexEnvfv = (PFNGLTEXENVFVPROC)load("glTexEnvfv"); + glad_glTexEnvi = (PFNGLTEXENVIPROC)load("glTexEnvi"); + glad_glTexEnviv = (PFNGLTEXENVIVPROC)load("glTexEnviv"); + glad_glTexGend = (PFNGLTEXGENDPROC)load("glTexGend"); + glad_glTexGendv = (PFNGLTEXGENDVPROC)load("glTexGendv"); + glad_glTexGenf = (PFNGLTEXGENFPROC)load("glTexGenf"); + glad_glTexGenfv = (PFNGLTEXGENFVPROC)load("glTexGenfv"); + glad_glTexGeni = (PFNGLTEXGENIPROC)load("glTexGeni"); + glad_glTexGeniv = (PFNGLTEXGENIVPROC)load("glTexGeniv"); + glad_glFeedbackBuffer = (PFNGLFEEDBACKBUFFERPROC)load("glFeedbackBuffer"); + glad_glSelectBuffer = (PFNGLSELECTBUFFERPROC)load("glSelectBuffer"); + glad_glRenderMode = (PFNGLRENDERMODEPROC)load("glRenderMode"); + glad_glInitNames = (PFNGLINITNAMESPROC)load("glInitNames"); + glad_glLoadName = (PFNGLLOADNAMEPROC)load("glLoadName"); + glad_glPassThrough = (PFNGLPASSTHROUGHPROC)load("glPassThrough"); + glad_glPopName = (PFNGLPOPNAMEPROC)load("glPopName"); + glad_glPushName = (PFNGLPUSHNAMEPROC)load("glPushName"); + glad_glClearAccum = (PFNGLCLEARACCUMPROC)load("glClearAccum"); + glad_glClearIndex = (PFNGLCLEARINDEXPROC)load("glClearIndex"); + glad_glIndexMask = (PFNGLINDEXMASKPROC)load("glIndexMask"); + glad_glAccum = (PFNGLACCUMPROC)load("glAccum"); + glad_glPopAttrib = (PFNGLPOPATTRIBPROC)load("glPopAttrib"); + glad_glPushAttrib = (PFNGLPUSHATTRIBPROC)load("glPushAttrib"); + glad_glMap1d = (PFNGLMAP1DPROC)load("glMap1d"); + glad_glMap1f = (PFNGLMAP1FPROC)load("glMap1f"); + glad_glMap2d = (PFNGLMAP2DPROC)load("glMap2d"); + glad_glMap2f = (PFNGLMAP2FPROC)load("glMap2f"); + glad_glMapGrid1d = (PFNGLMAPGRID1DPROC)load("glMapGrid1d"); + glad_glMapGrid1f = (PFNGLMAPGRID1FPROC)load("glMapGrid1f"); + glad_glMapGrid2d = (PFNGLMAPGRID2DPROC)load("glMapGrid2d"); + glad_glMapGrid2f = (PFNGLMAPGRID2FPROC)load("glMapGrid2f"); + glad_glEvalCoord1d = (PFNGLEVALCOORD1DPROC)load("glEvalCoord1d"); + glad_glEvalCoord1dv = (PFNGLEVALCOORD1DVPROC)load("glEvalCoord1dv"); + glad_glEvalCoord1f = (PFNGLEVALCOORD1FPROC)load("glEvalCoord1f"); + glad_glEvalCoord1fv = (PFNGLEVALCOORD1FVPROC)load("glEvalCoord1fv"); + glad_glEvalCoord2d = (PFNGLEVALCOORD2DPROC)load("glEvalCoord2d"); + glad_glEvalCoord2dv = (PFNGLEVALCOORD2DVPROC)load("glEvalCoord2dv"); + glad_glEvalCoord2f = (PFNGLEVALCOORD2FPROC)load("glEvalCoord2f"); + glad_glEvalCoord2fv = (PFNGLEVALCOORD2FVPROC)load("glEvalCoord2fv"); + glad_glEvalMesh1 = (PFNGLEVALMESH1PROC)load("glEvalMesh1"); + glad_glEvalPoint1 = (PFNGLEVALPOINT1PROC)load("glEvalPoint1"); + glad_glEvalMesh2 = (PFNGLEVALMESH2PROC)load("glEvalMesh2"); + glad_glEvalPoint2 = (PFNGLEVALPOINT2PROC)load("glEvalPoint2"); + glad_glAlphaFunc = (PFNGLALPHAFUNCPROC)load("glAlphaFunc"); + glad_glPixelZoom = (PFNGLPIXELZOOMPROC)load("glPixelZoom"); + glad_glPixelTransferf = (PFNGLPIXELTRANSFERFPROC)load("glPixelTransferf"); + glad_glPixelTransferi = (PFNGLPIXELTRANSFERIPROC)load("glPixelTransferi"); + glad_glPixelMapfv = (PFNGLPIXELMAPFVPROC)load("glPixelMapfv"); + glad_glPixelMapuiv = (PFNGLPIXELMAPUIVPROC)load("glPixelMapuiv"); + glad_glPixelMapusv = (PFNGLPIXELMAPUSVPROC)load("glPixelMapusv"); + glad_glCopyPixels = (PFNGLCOPYPIXELSPROC)load("glCopyPixels"); + glad_glDrawPixels = (PFNGLDRAWPIXELSPROC)load("glDrawPixels"); + glad_glGetClipPlane = (PFNGLGETCLIPPLANEPROC)load("glGetClipPlane"); + glad_glGetLightfv = (PFNGLGETLIGHTFVPROC)load("glGetLightfv"); + glad_glGetLightiv = (PFNGLGETLIGHTIVPROC)load("glGetLightiv"); + glad_glGetMapdv = (PFNGLGETMAPDVPROC)load("glGetMapdv"); + glad_glGetMapfv = (PFNGLGETMAPFVPROC)load("glGetMapfv"); + glad_glGetMapiv = (PFNGLGETMAPIVPROC)load("glGetMapiv"); + glad_glGetMaterialfv = (PFNGLGETMATERIALFVPROC)load("glGetMaterialfv"); + glad_glGetMaterialiv = (PFNGLGETMATERIALIVPROC)load("glGetMaterialiv"); + glad_glGetPixelMapfv = (PFNGLGETPIXELMAPFVPROC)load("glGetPixelMapfv"); + glad_glGetPixelMapuiv = (PFNGLGETPIXELMAPUIVPROC)load("glGetPixelMapuiv"); + glad_glGetPixelMapusv = (PFNGLGETPIXELMAPUSVPROC)load("glGetPixelMapusv"); + glad_glGetPolygonStipple = (PFNGLGETPOLYGONSTIPPLEPROC)load("glGetPolygonStipple"); + glad_glGetTexEnvfv = (PFNGLGETTEXENVFVPROC)load("glGetTexEnvfv"); + glad_glGetTexEnviv = (PFNGLGETTEXENVIVPROC)load("glGetTexEnviv"); + glad_glGetTexGendv = (PFNGLGETTEXGENDVPROC)load("glGetTexGendv"); + glad_glGetTexGenfv = (PFNGLGETTEXGENFVPROC)load("glGetTexGenfv"); + glad_glGetTexGeniv = (PFNGLGETTEXGENIVPROC)load("glGetTexGeniv"); + glad_glIsList = (PFNGLISLISTPROC)load("glIsList"); + glad_glFrustum = (PFNGLFRUSTUMPROC)load("glFrustum"); + glad_glLoadIdentity = (PFNGLLOADIDENTITYPROC)load("glLoadIdentity"); + glad_glLoadMatrixf = (PFNGLLOADMATRIXFPROC)load("glLoadMatrixf"); + glad_glLoadMatrixd = (PFNGLLOADMATRIXDPROC)load("glLoadMatrixd"); + glad_glMatrixMode = (PFNGLMATRIXMODEPROC)load("glMatrixMode"); + glad_glMultMatrixf = (PFNGLMULTMATRIXFPROC)load("glMultMatrixf"); + glad_glMultMatrixd = (PFNGLMULTMATRIXDPROC)load("glMultMatrixd"); + glad_glOrtho = (PFNGLORTHOPROC)load("glOrtho"); + glad_glPopMatrix = (PFNGLPOPMATRIXPROC)load("glPopMatrix"); + glad_glPushMatrix = (PFNGLPUSHMATRIXPROC)load("glPushMatrix"); + glad_glRotated = (PFNGLROTATEDPROC)load("glRotated"); + glad_glRotatef = (PFNGLROTATEFPROC)load("glRotatef"); + glad_glScaled = (PFNGLSCALEDPROC)load("glScaled"); + glad_glScalef = (PFNGLSCALEFPROC)load("glScalef"); + glad_glTranslated = (PFNGLTRANSLATEDPROC)load("glTranslated"); + glad_glTranslatef = (PFNGLTRANSLATEFPROC)load("glTranslatef"); +} +static void load_GL_VERSION_1_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_1) return; + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); + glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); + glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); + glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); + glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); + glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); + glad_glArrayElement = (PFNGLARRAYELEMENTPROC)load("glArrayElement"); + glad_glColorPointer = (PFNGLCOLORPOINTERPROC)load("glColorPointer"); + glad_glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC)load("glDisableClientState"); + glad_glEdgeFlagPointer = (PFNGLEDGEFLAGPOINTERPROC)load("glEdgeFlagPointer"); + glad_glEnableClientState = (PFNGLENABLECLIENTSTATEPROC)load("glEnableClientState"); + glad_glIndexPointer = (PFNGLINDEXPOINTERPROC)load("glIndexPointer"); + glad_glInterleavedArrays = (PFNGLINTERLEAVEDARRAYSPROC)load("glInterleavedArrays"); + glad_glNormalPointer = (PFNGLNORMALPOINTERPROC)load("glNormalPointer"); + glad_glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC)load("glTexCoordPointer"); + glad_glVertexPointer = (PFNGLVERTEXPOINTERPROC)load("glVertexPointer"); + glad_glAreTexturesResident = (PFNGLARETEXTURESRESIDENTPROC)load("glAreTexturesResident"); + glad_glPrioritizeTextures = (PFNGLPRIORITIZETEXTURESPROC)load("glPrioritizeTextures"); + glad_glIndexub = (PFNGLINDEXUBPROC)load("glIndexub"); + glad_glIndexubv = (PFNGLINDEXUBVPROC)load("glIndexubv"); + glad_glPopClientAttrib = (PFNGLPOPCLIENTATTRIBPROC)load("glPopClientAttrib"); + glad_glPushClientAttrib = (PFNGLPUSHCLIENTATTRIBPROC)load("glPushClientAttrib"); +} +static void load_GL_VERSION_1_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_2) return; + glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); + glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); + glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); + glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); +} +static void load_GL_VERSION_1_3(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_3) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); + glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); + glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D"); + glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); + glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D"); + glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage"); + glad_glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)load("glClientActiveTexture"); + glad_glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC)load("glMultiTexCoord1d"); + glad_glMultiTexCoord1dv = (PFNGLMULTITEXCOORD1DVPROC)load("glMultiTexCoord1dv"); + glad_glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC)load("glMultiTexCoord1f"); + glad_glMultiTexCoord1fv = (PFNGLMULTITEXCOORD1FVPROC)load("glMultiTexCoord1fv"); + glad_glMultiTexCoord1i = (PFNGLMULTITEXCOORD1IPROC)load("glMultiTexCoord1i"); + glad_glMultiTexCoord1iv = (PFNGLMULTITEXCOORD1IVPROC)load("glMultiTexCoord1iv"); + glad_glMultiTexCoord1s = (PFNGLMULTITEXCOORD1SPROC)load("glMultiTexCoord1s"); + glad_glMultiTexCoord1sv = (PFNGLMULTITEXCOORD1SVPROC)load("glMultiTexCoord1sv"); + glad_glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC)load("glMultiTexCoord2d"); + glad_glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC)load("glMultiTexCoord2dv"); + glad_glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC)load("glMultiTexCoord2f"); + glad_glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC)load("glMultiTexCoord2fv"); + glad_glMultiTexCoord2i = (PFNGLMULTITEXCOORD2IPROC)load("glMultiTexCoord2i"); + glad_glMultiTexCoord2iv = (PFNGLMULTITEXCOORD2IVPROC)load("glMultiTexCoord2iv"); + glad_glMultiTexCoord2s = (PFNGLMULTITEXCOORD2SPROC)load("glMultiTexCoord2s"); + glad_glMultiTexCoord2sv = (PFNGLMULTITEXCOORD2SVPROC)load("glMultiTexCoord2sv"); + glad_glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC)load("glMultiTexCoord3d"); + glad_glMultiTexCoord3dv = (PFNGLMULTITEXCOORD3DVPROC)load("glMultiTexCoord3dv"); + glad_glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC)load("glMultiTexCoord3f"); + glad_glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC)load("glMultiTexCoord3fv"); + glad_glMultiTexCoord3i = (PFNGLMULTITEXCOORD3IPROC)load("glMultiTexCoord3i"); + glad_glMultiTexCoord3iv = (PFNGLMULTITEXCOORD3IVPROC)load("glMultiTexCoord3iv"); + glad_glMultiTexCoord3s = (PFNGLMULTITEXCOORD3SPROC)load("glMultiTexCoord3s"); + glad_glMultiTexCoord3sv = (PFNGLMULTITEXCOORD3SVPROC)load("glMultiTexCoord3sv"); + glad_glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC)load("glMultiTexCoord4d"); + glad_glMultiTexCoord4dv = (PFNGLMULTITEXCOORD4DVPROC)load("glMultiTexCoord4dv"); + glad_glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)load("glMultiTexCoord4f"); + glad_glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC)load("glMultiTexCoord4fv"); + glad_glMultiTexCoord4i = (PFNGLMULTITEXCOORD4IPROC)load("glMultiTexCoord4i"); + glad_glMultiTexCoord4iv = (PFNGLMULTITEXCOORD4IVPROC)load("glMultiTexCoord4iv"); + glad_glMultiTexCoord4s = (PFNGLMULTITEXCOORD4SPROC)load("glMultiTexCoord4s"); + glad_glMultiTexCoord4sv = (PFNGLMULTITEXCOORD4SVPROC)load("glMultiTexCoord4sv"); + glad_glLoadTransposeMatrixf = (PFNGLLOADTRANSPOSEMATRIXFPROC)load("glLoadTransposeMatrixf"); + glad_glLoadTransposeMatrixd = (PFNGLLOADTRANSPOSEMATRIXDPROC)load("glLoadTransposeMatrixd"); + glad_glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC)load("glMultTransposeMatrixf"); + glad_glMultTransposeMatrixd = (PFNGLMULTTRANSPOSEMATRIXDPROC)load("glMultTransposeMatrixd"); +} +static void load_GL_VERSION_1_4(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_4) return; + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); + glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays"); + glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements"); + glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf"); + glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv"); + glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri"); + glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv"); + glad_glFogCoordf = (PFNGLFOGCOORDFPROC)load("glFogCoordf"); + glad_glFogCoordfv = (PFNGLFOGCOORDFVPROC)load("glFogCoordfv"); + glad_glFogCoordd = (PFNGLFOGCOORDDPROC)load("glFogCoordd"); + glad_glFogCoorddv = (PFNGLFOGCOORDDVPROC)load("glFogCoorddv"); + glad_glFogCoordPointer = (PFNGLFOGCOORDPOINTERPROC)load("glFogCoordPointer"); + glad_glSecondaryColor3b = (PFNGLSECONDARYCOLOR3BPROC)load("glSecondaryColor3b"); + glad_glSecondaryColor3bv = (PFNGLSECONDARYCOLOR3BVPROC)load("glSecondaryColor3bv"); + glad_glSecondaryColor3d = (PFNGLSECONDARYCOLOR3DPROC)load("glSecondaryColor3d"); + glad_glSecondaryColor3dv = (PFNGLSECONDARYCOLOR3DVPROC)load("glSecondaryColor3dv"); + glad_glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FPROC)load("glSecondaryColor3f"); + glad_glSecondaryColor3fv = (PFNGLSECONDARYCOLOR3FVPROC)load("glSecondaryColor3fv"); + glad_glSecondaryColor3i = (PFNGLSECONDARYCOLOR3IPROC)load("glSecondaryColor3i"); + glad_glSecondaryColor3iv = (PFNGLSECONDARYCOLOR3IVPROC)load("glSecondaryColor3iv"); + glad_glSecondaryColor3s = (PFNGLSECONDARYCOLOR3SPROC)load("glSecondaryColor3s"); + glad_glSecondaryColor3sv = (PFNGLSECONDARYCOLOR3SVPROC)load("glSecondaryColor3sv"); + glad_glSecondaryColor3ub = (PFNGLSECONDARYCOLOR3UBPROC)load("glSecondaryColor3ub"); + glad_glSecondaryColor3ubv = (PFNGLSECONDARYCOLOR3UBVPROC)load("glSecondaryColor3ubv"); + glad_glSecondaryColor3ui = (PFNGLSECONDARYCOLOR3UIPROC)load("glSecondaryColor3ui"); + glad_glSecondaryColor3uiv = (PFNGLSECONDARYCOLOR3UIVPROC)load("glSecondaryColor3uiv"); + glad_glSecondaryColor3us = (PFNGLSECONDARYCOLOR3USPROC)load("glSecondaryColor3us"); + glad_glSecondaryColor3usv = (PFNGLSECONDARYCOLOR3USVPROC)load("glSecondaryColor3usv"); + glad_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)load("glSecondaryColorPointer"); + glad_glWindowPos2d = (PFNGLWINDOWPOS2DPROC)load("glWindowPos2d"); + glad_glWindowPos2dv = (PFNGLWINDOWPOS2DVPROC)load("glWindowPos2dv"); + glad_glWindowPos2f = (PFNGLWINDOWPOS2FPROC)load("glWindowPos2f"); + glad_glWindowPos2fv = (PFNGLWINDOWPOS2FVPROC)load("glWindowPos2fv"); + glad_glWindowPos2i = (PFNGLWINDOWPOS2IPROC)load("glWindowPos2i"); + glad_glWindowPos2iv = (PFNGLWINDOWPOS2IVPROC)load("glWindowPos2iv"); + glad_glWindowPos2s = (PFNGLWINDOWPOS2SPROC)load("glWindowPos2s"); + glad_glWindowPos2sv = (PFNGLWINDOWPOS2SVPROC)load("glWindowPos2sv"); + glad_glWindowPos3d = (PFNGLWINDOWPOS3DPROC)load("glWindowPos3d"); + glad_glWindowPos3dv = (PFNGLWINDOWPOS3DVPROC)load("glWindowPos3dv"); + glad_glWindowPos3f = (PFNGLWINDOWPOS3FPROC)load("glWindowPos3f"); + glad_glWindowPos3fv = (PFNGLWINDOWPOS3FVPROC)load("glWindowPos3fv"); + glad_glWindowPos3i = (PFNGLWINDOWPOS3IPROC)load("glWindowPos3i"); + glad_glWindowPos3iv = (PFNGLWINDOWPOS3IVPROC)load("glWindowPos3iv"); + glad_glWindowPos3s = (PFNGLWINDOWPOS3SPROC)load("glWindowPos3s"); + glad_glWindowPos3sv = (PFNGLWINDOWPOS3SVPROC)load("glWindowPos3sv"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); +} +static void load_GL_VERSION_1_5(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_5) return; + glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); + glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); + glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); + glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); + glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); + glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); + glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv"); + glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); + glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); + glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); + glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData"); + glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer"); + glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); + glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); +} +static void load_GL_VERSION_2_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_0) return; + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); + glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); + glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); + glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); + glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); + glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d"); + glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); + glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s"); + glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv"); + glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d"); + glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); + glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s"); + glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv"); + glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d"); + glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); + glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s"); + glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv"); + glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv"); + glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv"); + glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv"); + glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub"); + glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv"); + glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv"); + glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv"); + glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv"); + glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d"); + glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); + glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv"); + glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s"); + glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv"); + glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv"); + glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv"); + glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); +} +static void load_GL_VERSION_2_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_1) return; + glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); + glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); + glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); + glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); + glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); + glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); +} +static void load_GL_VERSION_3_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_0) return; + glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); + glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); + glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); + glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); + glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); + glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); + glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); + glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); + glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor"); + glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender"); + glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender"); + glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); + glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); + glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); + glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i"); + glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i"); + glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i"); + glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); + glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui"); + glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui"); + glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui"); + glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); + glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv"); + glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv"); + glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv"); + glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); + glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv"); + glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv"); + glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv"); + glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); + glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv"); + glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv"); + glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv"); + glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv"); + glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); + glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation"); + glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); + glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); + glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); + glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); + glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); + glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); + glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); + glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); + glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); + glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); + glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); + glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); + glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); + glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); + glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); + glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); + glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); + glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); + glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); + glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); + glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); + glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); + glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); + glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); + glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); + glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); +} +static void load_GL_VERSION_3_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_1) return; + glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); + glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); + glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer"); + glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex"); + glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); + glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); + glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); + glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName"); + glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); + glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); + glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); + glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); +} +static void load_GL_VERSION_3_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_2) return; + glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex"); + glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex"); + glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex"); + glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex"); + glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex"); + glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); + glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); + glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); + glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); + glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); + glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); + glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); + glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); + glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); + glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture"); + glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample"); + glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample"); + glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); + glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); +} +static void load_GL_ARB_multisample(GLADloadproc load) { + if(!GLAD_GL_ARB_multisample) return; + glad_glSampleCoverageARB = (PFNGLSAMPLECOVERAGEARBPROC)load("glSampleCoverageARB"); +} +static void load_GL_ARB_robustness(GLADloadproc load) { + if(!GLAD_GL_ARB_robustness) return; + glad_glGetGraphicsResetStatusARB = (PFNGLGETGRAPHICSRESETSTATUSARBPROC)load("glGetGraphicsResetStatusARB"); + glad_glGetnTexImageARB = (PFNGLGETNTEXIMAGEARBPROC)load("glGetnTexImageARB"); + glad_glReadnPixelsARB = (PFNGLREADNPIXELSARBPROC)load("glReadnPixelsARB"); + glad_glGetnCompressedTexImageARB = (PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC)load("glGetnCompressedTexImageARB"); + glad_glGetnUniformfvARB = (PFNGLGETNUNIFORMFVARBPROC)load("glGetnUniformfvARB"); + glad_glGetnUniformivARB = (PFNGLGETNUNIFORMIVARBPROC)load("glGetnUniformivARB"); + glad_glGetnUniformuivARB = (PFNGLGETNUNIFORMUIVARBPROC)load("glGetnUniformuivARB"); + glad_glGetnUniformdvARB = (PFNGLGETNUNIFORMDVARBPROC)load("glGetnUniformdvARB"); + glad_glGetnMapdvARB = (PFNGLGETNMAPDVARBPROC)load("glGetnMapdvARB"); + glad_glGetnMapfvARB = (PFNGLGETNMAPFVARBPROC)load("glGetnMapfvARB"); + glad_glGetnMapivARB = (PFNGLGETNMAPIVARBPROC)load("glGetnMapivARB"); + glad_glGetnPixelMapfvARB = (PFNGLGETNPIXELMAPFVARBPROC)load("glGetnPixelMapfvARB"); + glad_glGetnPixelMapuivARB = (PFNGLGETNPIXELMAPUIVARBPROC)load("glGetnPixelMapuivARB"); + glad_glGetnPixelMapusvARB = (PFNGLGETNPIXELMAPUSVARBPROC)load("glGetnPixelMapusvARB"); + glad_glGetnPolygonStippleARB = (PFNGLGETNPOLYGONSTIPPLEARBPROC)load("glGetnPolygonStippleARB"); + glad_glGetnColorTableARB = (PFNGLGETNCOLORTABLEARBPROC)load("glGetnColorTableARB"); + glad_glGetnConvolutionFilterARB = (PFNGLGETNCONVOLUTIONFILTERARBPROC)load("glGetnConvolutionFilterARB"); + glad_glGetnSeparableFilterARB = (PFNGLGETNSEPARABLEFILTERARBPROC)load("glGetnSeparableFilterARB"); + glad_glGetnHistogramARB = (PFNGLGETNHISTOGRAMARBPROC)load("glGetnHistogramARB"); + glad_glGetnMinmaxARB = (PFNGLGETNMINMAXARBPROC)load("glGetnMinmaxARB"); +} +static void load_GL_KHR_debug(GLADloadproc load) { + if(!GLAD_GL_KHR_debug) return; + glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)load("glDebugMessageControl"); + glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC)load("glDebugMessageInsert"); + glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)load("glDebugMessageCallback"); + glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)load("glGetDebugMessageLog"); + glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)load("glPushDebugGroup"); + glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)load("glPopDebugGroup"); + glad_glObjectLabel = (PFNGLOBJECTLABELPROC)load("glObjectLabel"); + glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)load("glGetObjectLabel"); + glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)load("glObjectPtrLabel"); + glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)load("glGetObjectPtrLabel"); + glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv"); + glad_glDebugMessageControlKHR = (PFNGLDEBUGMESSAGECONTROLKHRPROC)load("glDebugMessageControlKHR"); + glad_glDebugMessageInsertKHR = (PFNGLDEBUGMESSAGEINSERTKHRPROC)load("glDebugMessageInsertKHR"); + glad_glDebugMessageCallbackKHR = (PFNGLDEBUGMESSAGECALLBACKKHRPROC)load("glDebugMessageCallbackKHR"); + glad_glGetDebugMessageLogKHR = (PFNGLGETDEBUGMESSAGELOGKHRPROC)load("glGetDebugMessageLogKHR"); + glad_glPushDebugGroupKHR = (PFNGLPUSHDEBUGGROUPKHRPROC)load("glPushDebugGroupKHR"); + glad_glPopDebugGroupKHR = (PFNGLPOPDEBUGGROUPKHRPROC)load("glPopDebugGroupKHR"); + glad_glObjectLabelKHR = (PFNGLOBJECTLABELKHRPROC)load("glObjectLabelKHR"); + glad_glGetObjectLabelKHR = (PFNGLGETOBJECTLABELKHRPROC)load("glGetObjectLabelKHR"); + glad_glObjectPtrLabelKHR = (PFNGLOBJECTPTRLABELKHRPROC)load("glObjectPtrLabelKHR"); + glad_glGetObjectPtrLabelKHR = (PFNGLGETOBJECTPTRLABELKHRPROC)load("glGetObjectPtrLabelKHR"); + glad_glGetPointervKHR = (PFNGLGETPOINTERVKHRPROC)load("glGetPointervKHR"); +} +static int find_extensionsGL(void) { + if (!get_exts()) return 0; + GLAD_GL_ARB_multisample = has_ext("GL_ARB_multisample"); + GLAD_GL_ARB_robustness = has_ext("GL_ARB_robustness"); + GLAD_GL_KHR_debug = has_ext("GL_KHR_debug"); + free_exts(); + return 1; +} + +static void find_coreGL(void) { + + /* Thank you @elmindreda + * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + * https://github.com/glfw/glfw/blob/master/src/context.c#L36 + */ + int i, major, minor; + + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + version = (const char*) glGetString(GL_VERSION); + if (!version) return; + + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + +/* PR #18 */ +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &major, &minor); +#else + sscanf(version, "%d.%d", &major, &minor); +#endif + + GLVersion.major = major; GLVersion.minor = minor; + max_loaded_major = major; max_loaded_minor = minor; + GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; + GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; + GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; + GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; + GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; + if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 2)) { + max_loaded_major = 3; + max_loaded_minor = 2; + } +} + +int gladLoadGLLoader(GLADloadproc load) { + GLVersion.major = 0; GLVersion.minor = 0; + glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + if(glGetString == NULL) return 0; + if(glGetString(GL_VERSION) == NULL) return 0; + find_coreGL(); + load_GL_VERSION_1_0(load); + load_GL_VERSION_1_1(load); + load_GL_VERSION_1_2(load); + load_GL_VERSION_1_3(load); + load_GL_VERSION_1_4(load); + load_GL_VERSION_1_5(load); + load_GL_VERSION_2_0(load); + load_GL_VERSION_2_1(load); + load_GL_VERSION_3_0(load); + load_GL_VERSION_3_1(load); + load_GL_VERSION_3_2(load); + + if (!find_extensionsGL()) return 0; + load_GL_ARB_multisample(load); + load_GL_ARB_robustness(load); + load_GL_KHR_debug(load); + return GLVersion.major != 0 || GLVersion.minor != 0; +} + diff --git a/src/external/glfw/deps/glad/glad.h b/src/external/glfw/deps/glad/glad.h new file mode 100644 index 00000000..7d81e98e --- /dev/null +++ b/src/external/glfw/deps/glad/glad.h @@ -0,0 +1,3680 @@ +/* + + OpenGL loader generated by glad 0.1.12a0 on Fri Sep 23 13:36:15 2016. + + Language/Generator: C/C++ + Specification: gl + APIs: gl=3.2 + Profile: compatibility + Extensions: + GL_ARB_multisample, + GL_ARB_robustness, + GL_KHR_debug + Loader: False + Local files: False + Omit khrplatform: False + + Commandline: + --profile="compatibility" --api="gl=3.2" --generator="c" --spec="gl" --no-loader --extensions="GL_ARB_multisample,GL_ARB_robustness,GL_KHR_debug" + Online: + http://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&api=gl%3D3.2&extensions=GL_ARB_multisample&extensions=GL_ARB_robustness&extensions=GL_KHR_debug +*/ + + +#ifndef __glad_h_ +#define __glad_h_ + +#ifdef __gl_h_ +#error OpenGL header already included, remove this include, glad already provides it +#endif +#define __gl_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct gladGLversionStruct { + int major; + int minor; +}; + +typedef void* (* GLADloadproc)(const char *name); + +#ifndef GLAPI +# if defined(GLAD_GLAPI_EXPORT) +# if defined(WIN32) || defined(__CYGWIN__) +# if defined(GLAD_GLAPI_EXPORT_BUILD) +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllexport)) extern +# else +# define GLAPI __declspec(dllexport) extern +# endif +# else +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllimport)) extern +# else +# define GLAPI __declspec(dllimport) extern +# endif +# endif +# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) +# define GLAPI __attribute__ ((visibility ("default"))) extern +# else +# define GLAPI extern +# endif +# else +# define GLAPI extern +# endif +#endif + +GLAPI struct gladGLversionStruct GLVersion; +GLAPI int gladLoadGLLoader(GLADloadproc); + +#include +#include +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glxext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GL_EXT_timer_query extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif +#endif +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef signed char GLbyte; +typedef short GLshort; +typedef int GLint; +typedef int GLclampx; +typedef unsigned char GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef int GLsizei; +typedef float GLfloat; +typedef float GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef unsigned short GLhalfARB; +typedef unsigned short GLhalf; +typedef GLint GLfixed; +typedef ptrdiff_t GLintptr; +typedef ptrdiff_t GLsizeiptr; +typedef int64_t GLint64; +typedef uint64_t GLuint64; +typedef ptrdiff_t GLintptrARB; +typedef ptrdiff_t GLsizeiptrARB; +typedef int64_t GLint64EXT; +typedef uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_NONE 0 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_VIEWPORT 0x0BA2 +#define GL_DITHER 0x0BD0 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND 0x0BE2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_DOUBLE 0x140A +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F +#define GL_TEXTURE 0x1702 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_STENCIL_INDEX 0x1901 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_REPEAT 0x2901 +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_CURRENT_BIT 0x00000001 +#define GL_POINT_BIT 0x00000002 +#define GL_LINE_BIT 0x00000004 +#define GL_POLYGON_BIT 0x00000008 +#define GL_POLYGON_STIPPLE_BIT 0x00000010 +#define GL_PIXEL_MODE_BIT 0x00000020 +#define GL_LIGHTING_BIT 0x00000040 +#define GL_FOG_BIT 0x00000080 +#define GL_ACCUM_BUFFER_BIT 0x00000200 +#define GL_VIEWPORT_BIT 0x00000800 +#define GL_TRANSFORM_BIT 0x00001000 +#define GL_ENABLE_BIT 0x00002000 +#define GL_HINT_BIT 0x00008000 +#define GL_EVAL_BIT 0x00010000 +#define GL_LIST_BIT 0x00020000 +#define GL_TEXTURE_BIT 0x00040000 +#define GL_SCISSOR_BIT 0x00080000 +#define GL_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 +#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 +#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_QUAD_STRIP 0x0008 +#define GL_POLYGON 0x0009 +#define GL_ACCUM 0x0100 +#define GL_LOAD 0x0101 +#define GL_RETURN 0x0102 +#define GL_MULT 0x0103 +#define GL_ADD 0x0104 +#define GL_AUX0 0x0409 +#define GL_AUX1 0x040A +#define GL_AUX2 0x040B +#define GL_AUX3 0x040C +#define GL_2D 0x0600 +#define GL_3D 0x0601 +#define GL_3D_COLOR 0x0602 +#define GL_3D_COLOR_TEXTURE 0x0603 +#define GL_4D_COLOR_TEXTURE 0x0604 +#define GL_PASS_THROUGH_TOKEN 0x0700 +#define GL_POINT_TOKEN 0x0701 +#define GL_LINE_TOKEN 0x0702 +#define GL_POLYGON_TOKEN 0x0703 +#define GL_BITMAP_TOKEN 0x0704 +#define GL_DRAW_PIXEL_TOKEN 0x0705 +#define GL_COPY_PIXEL_TOKEN 0x0706 +#define GL_LINE_RESET_TOKEN 0x0707 +#define GL_EXP 0x0800 +#define GL_EXP2 0x0801 +#define GL_COEFF 0x0A00 +#define GL_ORDER 0x0A01 +#define GL_DOMAIN 0x0A02 +#define GL_PIXEL_MAP_I_TO_I 0x0C70 +#define GL_PIXEL_MAP_S_TO_S 0x0C71 +#define GL_PIXEL_MAP_I_TO_R 0x0C72 +#define GL_PIXEL_MAP_I_TO_G 0x0C73 +#define GL_PIXEL_MAP_I_TO_B 0x0C74 +#define GL_PIXEL_MAP_I_TO_A 0x0C75 +#define GL_PIXEL_MAP_R_TO_R 0x0C76 +#define GL_PIXEL_MAP_G_TO_G 0x0C77 +#define GL_PIXEL_MAP_B_TO_B 0x0C78 +#define GL_PIXEL_MAP_A_TO_A 0x0C79 +#define GL_VERTEX_ARRAY_POINTER 0x808E +#define GL_NORMAL_ARRAY_POINTER 0x808F +#define GL_COLOR_ARRAY_POINTER 0x8090 +#define GL_INDEX_ARRAY_POINTER 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 +#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 +#define GL_SELECTION_BUFFER_POINTER 0x0DF3 +#define GL_CURRENT_COLOR 0x0B00 +#define GL_CURRENT_INDEX 0x0B01 +#define GL_CURRENT_NORMAL 0x0B02 +#define GL_CURRENT_TEXTURE_COORDS 0x0B03 +#define GL_CURRENT_RASTER_COLOR 0x0B04 +#define GL_CURRENT_RASTER_INDEX 0x0B05 +#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 +#define GL_CURRENT_RASTER_POSITION 0x0B07 +#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 +#define GL_CURRENT_RASTER_DISTANCE 0x0B09 +#define GL_POINT_SMOOTH 0x0B10 +#define GL_LINE_STIPPLE 0x0B24 +#define GL_LINE_STIPPLE_PATTERN 0x0B25 +#define GL_LINE_STIPPLE_REPEAT 0x0B26 +#define GL_LIST_MODE 0x0B30 +#define GL_MAX_LIST_NESTING 0x0B31 +#define GL_LIST_BASE 0x0B32 +#define GL_LIST_INDEX 0x0B33 +#define GL_POLYGON_STIPPLE 0x0B42 +#define GL_EDGE_FLAG 0x0B43 +#define GL_LIGHTING 0x0B50 +#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 +#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 +#define GL_LIGHT_MODEL_AMBIENT 0x0B53 +#define GL_SHADE_MODEL 0x0B54 +#define GL_COLOR_MATERIAL_FACE 0x0B55 +#define GL_COLOR_MATERIAL_PARAMETER 0x0B56 +#define GL_COLOR_MATERIAL 0x0B57 +#define GL_FOG 0x0B60 +#define GL_FOG_INDEX 0x0B61 +#define GL_FOG_DENSITY 0x0B62 +#define GL_FOG_START 0x0B63 +#define GL_FOG_END 0x0B64 +#define GL_FOG_MODE 0x0B65 +#define GL_FOG_COLOR 0x0B66 +#define GL_ACCUM_CLEAR_VALUE 0x0B80 +#define GL_MATRIX_MODE 0x0BA0 +#define GL_NORMALIZE 0x0BA1 +#define GL_MODELVIEW_STACK_DEPTH 0x0BA3 +#define GL_PROJECTION_STACK_DEPTH 0x0BA4 +#define GL_TEXTURE_STACK_DEPTH 0x0BA5 +#define GL_MODELVIEW_MATRIX 0x0BA6 +#define GL_PROJECTION_MATRIX 0x0BA7 +#define GL_TEXTURE_MATRIX 0x0BA8 +#define GL_ATTRIB_STACK_DEPTH 0x0BB0 +#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 +#define GL_ALPHA_TEST 0x0BC0 +#define GL_ALPHA_TEST_FUNC 0x0BC1 +#define GL_ALPHA_TEST_REF 0x0BC2 +#define GL_INDEX_LOGIC_OP 0x0BF1 +#define GL_LOGIC_OP 0x0BF1 +#define GL_AUX_BUFFERS 0x0C00 +#define GL_INDEX_CLEAR_VALUE 0x0C20 +#define GL_INDEX_WRITEMASK 0x0C21 +#define GL_INDEX_MODE 0x0C30 +#define GL_RGBA_MODE 0x0C31 +#define GL_RENDER_MODE 0x0C40 +#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define GL_POINT_SMOOTH_HINT 0x0C51 +#define GL_FOG_HINT 0x0C54 +#define GL_TEXTURE_GEN_S 0x0C60 +#define GL_TEXTURE_GEN_T 0x0C61 +#define GL_TEXTURE_GEN_R 0x0C62 +#define GL_TEXTURE_GEN_Q 0x0C63 +#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 +#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 +#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 +#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 +#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 +#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 +#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 +#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 +#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 +#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 +#define GL_MAP_COLOR 0x0D10 +#define GL_MAP_STENCIL 0x0D11 +#define GL_INDEX_SHIFT 0x0D12 +#define GL_INDEX_OFFSET 0x0D13 +#define GL_RED_SCALE 0x0D14 +#define GL_RED_BIAS 0x0D15 +#define GL_ZOOM_X 0x0D16 +#define GL_ZOOM_Y 0x0D17 +#define GL_GREEN_SCALE 0x0D18 +#define GL_GREEN_BIAS 0x0D19 +#define GL_BLUE_SCALE 0x0D1A +#define GL_BLUE_BIAS 0x0D1B +#define GL_ALPHA_SCALE 0x0D1C +#define GL_ALPHA_BIAS 0x0D1D +#define GL_DEPTH_SCALE 0x0D1E +#define GL_DEPTH_BIAS 0x0D1F +#define GL_MAX_EVAL_ORDER 0x0D30 +#define GL_MAX_LIGHTS 0x0D31 +#define GL_MAX_CLIP_PLANES 0x0D32 +#define GL_MAX_PIXEL_MAP_TABLE 0x0D34 +#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 +#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 +#define GL_MAX_NAME_STACK_DEPTH 0x0D37 +#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 +#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 +#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B +#define GL_INDEX_BITS 0x0D51 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 +#define GL_ACCUM_RED_BITS 0x0D58 +#define GL_ACCUM_GREEN_BITS 0x0D59 +#define GL_ACCUM_BLUE_BITS 0x0D5A +#define GL_ACCUM_ALPHA_BITS 0x0D5B +#define GL_NAME_STACK_DEPTH 0x0D70 +#define GL_AUTO_NORMAL 0x0D80 +#define GL_MAP1_COLOR_4 0x0D90 +#define GL_MAP1_INDEX 0x0D91 +#define GL_MAP1_NORMAL 0x0D92 +#define GL_MAP1_TEXTURE_COORD_1 0x0D93 +#define GL_MAP1_TEXTURE_COORD_2 0x0D94 +#define GL_MAP1_TEXTURE_COORD_3 0x0D95 +#define GL_MAP1_TEXTURE_COORD_4 0x0D96 +#define GL_MAP1_VERTEX_3 0x0D97 +#define GL_MAP1_VERTEX_4 0x0D98 +#define GL_MAP2_COLOR_4 0x0DB0 +#define GL_MAP2_INDEX 0x0DB1 +#define GL_MAP2_NORMAL 0x0DB2 +#define GL_MAP2_TEXTURE_COORD_1 0x0DB3 +#define GL_MAP2_TEXTURE_COORD_2 0x0DB4 +#define GL_MAP2_TEXTURE_COORD_3 0x0DB5 +#define GL_MAP2_TEXTURE_COORD_4 0x0DB6 +#define GL_MAP2_VERTEX_3 0x0DB7 +#define GL_MAP2_VERTEX_4 0x0DB8 +#define GL_MAP1_GRID_DOMAIN 0x0DD0 +#define GL_MAP1_GRID_SEGMENTS 0x0DD1 +#define GL_MAP2_GRID_DOMAIN 0x0DD2 +#define GL_MAP2_GRID_SEGMENTS 0x0DD3 +#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 +#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 +#define GL_SELECTION_BUFFER_SIZE 0x0DF4 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_COLOR_ARRAY 0x8076 +#define GL_INDEX_ARRAY 0x8077 +#define GL_TEXTURE_COORD_ARRAY 0x8078 +#define GL_EDGE_FLAG_ARRAY 0x8079 +#define GL_VERTEX_ARRAY_SIZE 0x807A +#define GL_VERTEX_ARRAY_TYPE 0x807B +#define GL_VERTEX_ARRAY_STRIDE 0x807C +#define GL_NORMAL_ARRAY_TYPE 0x807E +#define GL_NORMAL_ARRAY_STRIDE 0x807F +#define GL_COLOR_ARRAY_SIZE 0x8081 +#define GL_COLOR_ARRAY_TYPE 0x8082 +#define GL_COLOR_ARRAY_STRIDE 0x8083 +#define GL_INDEX_ARRAY_TYPE 0x8085 +#define GL_INDEX_ARRAY_STRIDE 0x8086 +#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A +#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C +#define GL_TEXTURE_COMPONENTS 0x1003 +#define GL_TEXTURE_BORDER 0x1005 +#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 +#define GL_TEXTURE_INTENSITY_SIZE 0x8061 +#define GL_TEXTURE_PRIORITY 0x8066 +#define GL_TEXTURE_RESIDENT 0x8067 +#define GL_AMBIENT 0x1200 +#define GL_DIFFUSE 0x1201 +#define GL_SPECULAR 0x1202 +#define GL_POSITION 0x1203 +#define GL_SPOT_DIRECTION 0x1204 +#define GL_SPOT_EXPONENT 0x1205 +#define GL_SPOT_CUTOFF 0x1206 +#define GL_CONSTANT_ATTENUATION 0x1207 +#define GL_LINEAR_ATTENUATION 0x1208 +#define GL_QUADRATIC_ATTENUATION 0x1209 +#define GL_COMPILE 0x1300 +#define GL_COMPILE_AND_EXECUTE 0x1301 +#define GL_2_BYTES 0x1407 +#define GL_3_BYTES 0x1408 +#define GL_4_BYTES 0x1409 +#define GL_EMISSION 0x1600 +#define GL_SHININESS 0x1601 +#define GL_AMBIENT_AND_DIFFUSE 0x1602 +#define GL_COLOR_INDEXES 0x1603 +#define GL_MODELVIEW 0x1700 +#define GL_PROJECTION 0x1701 +#define GL_COLOR_INDEX 0x1900 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_BITMAP 0x1A00 +#define GL_RENDER 0x1C00 +#define GL_FEEDBACK 0x1C01 +#define GL_SELECT 0x1C02 +#define GL_FLAT 0x1D00 +#define GL_SMOOTH 0x1D01 +#define GL_S 0x2000 +#define GL_T 0x2001 +#define GL_R 0x2002 +#define GL_Q 0x2003 +#define GL_MODULATE 0x2100 +#define GL_DECAL 0x2101 +#define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_ENV_COLOR 0x2201 +#define GL_TEXTURE_ENV 0x2300 +#define GL_EYE_LINEAR 0x2400 +#define GL_OBJECT_LINEAR 0x2401 +#define GL_SPHERE_MAP 0x2402 +#define GL_TEXTURE_GEN_MODE 0x2500 +#define GL_OBJECT_PLANE 0x2501 +#define GL_EYE_PLANE 0x2502 +#define GL_CLAMP 0x2900 +#define GL_ALPHA4 0x803B +#define GL_ALPHA8 0x803C +#define GL_ALPHA12 0x803D +#define GL_ALPHA16 0x803E +#define GL_LUMINANCE4 0x803F +#define GL_LUMINANCE8 0x8040 +#define GL_LUMINANCE12 0x8041 +#define GL_LUMINANCE16 0x8042 +#define GL_LUMINANCE4_ALPHA4 0x8043 +#define GL_LUMINANCE6_ALPHA2 0x8044 +#define GL_LUMINANCE8_ALPHA8 0x8045 +#define GL_LUMINANCE12_ALPHA4 0x8046 +#define GL_LUMINANCE12_ALPHA12 0x8047 +#define GL_LUMINANCE16_ALPHA16 0x8048 +#define GL_INTENSITY 0x8049 +#define GL_INTENSITY4 0x804A +#define GL_INTENSITY8 0x804B +#define GL_INTENSITY12 0x804C +#define GL_INTENSITY16 0x804D +#define GL_V2F 0x2A20 +#define GL_V3F 0x2A21 +#define GL_C4UB_V2F 0x2A22 +#define GL_C4UB_V3F 0x2A23 +#define GL_C3F_V3F 0x2A24 +#define GL_N3F_V3F 0x2A25 +#define GL_C4F_N3F_V3F 0x2A26 +#define GL_T2F_V3F 0x2A27 +#define GL_T4F_V4F 0x2A28 +#define GL_T2F_C4UB_V3F 0x2A29 +#define GL_T2F_C3F_V3F 0x2A2A +#define GL_T2F_N3F_V3F 0x2A2B +#define GL_T2F_C4F_N3F_V3F 0x2A2C +#define GL_T4F_C4F_N3F_V4F 0x2A2D +#define GL_CLIP_PLANE0 0x3000 +#define GL_CLIP_PLANE1 0x3001 +#define GL_CLIP_PLANE2 0x3002 +#define GL_CLIP_PLANE3 0x3003 +#define GL_CLIP_PLANE4 0x3004 +#define GL_CLIP_PLANE5 0x3005 +#define GL_LIGHT0 0x4000 +#define GL_LIGHT1 0x4001 +#define GL_LIGHT2 0x4002 +#define GL_LIGHT3 0x4003 +#define GL_LIGHT4 0x4004 +#define GL_LIGHT5 0x4005 +#define GL_LIGHT6 0x4006 +#define GL_LIGHT7 0x4007 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_RESCALE_NORMAL 0x803A +#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define GL_SINGLE_COLOR 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define GL_MULTISAMPLE_BIT 0x20000000 +#define GL_NORMAL_MAP 0x8511 +#define GL_REFLECTION_MAP 0x8512 +#define GL_COMPRESSED_ALPHA 0x84E9 +#define GL_COMPRESSED_LUMINANCE 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define GL_COMPRESSED_INTENSITY 0x84EC +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_RGB 0x8582 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_RGB 0x8592 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_RGB_SCALE 0x8573 +#define GL_ADD_SIGNED 0x8574 +#define GL_INTERPOLATE 0x8575 +#define GL_SUBTRACT 0x84E7 +#define GL_CONSTANT 0x8576 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PREVIOUS 0x8578 +#define GL_DOT3_RGB 0x86AE +#define GL_DOT3_RGBA 0x86AF +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_GENERATE_MIPMAP 0x8191 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_FOG_COORDINATE_SOURCE 0x8450 +#define GL_FOG_COORDINATE 0x8451 +#define GL_FRAGMENT_DEPTH 0x8452 +#define GL_CURRENT_FOG_COORDINATE 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define GL_FOG_COORDINATE_ARRAY 0x8457 +#define GL_COLOR_SUM 0x8458 +#define GL_CURRENT_SECONDARY_COLOR 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define GL_SECONDARY_COLOR_ARRAY 0x845E +#define GL_TEXTURE_FILTER_CONTROL 0x8500 +#define GL_DEPTH_TEXTURE_MODE 0x884B +#define GL_COMPARE_R_TO_TEXTURE 0x884E +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_FOG_COORD_SRC 0x8450 +#define GL_FOG_COORD 0x8451 +#define GL_CURRENT_FOG_COORD 0x8453 +#define GL_FOG_COORD_ARRAY_TYPE 0x8454 +#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORD_ARRAY_POINTER 0x8456 +#define GL_FOG_COORD_ARRAY 0x8457 +#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D +#define GL_SRC0_RGB 0x8580 +#define GL_SRC1_RGB 0x8581 +#define GL_SRC2_RGB 0x8582 +#define GL_SRC0_ALPHA 0x8588 +#define GL_SRC2_ALPHA 0x858A +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_POINT_SPRITE 0x8861 +#define GL_COORD_REPLACE 0x8862 +#define GL_MAX_TEXTURE_COORDS 0x8871 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F +#define GL_SLUMINANCE_ALPHA 0x8C44 +#define GL_SLUMINANCE8_ALPHA8 0x8C45 +#define GL_SLUMINANCE 0x8C46 +#define GL_SLUMINANCE8 0x8C47 +#define GL_COMPRESSED_SLUMINANCE 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_COLOR_ATTACHMENT16 0x8CF0 +#define GL_COLOR_ATTACHMENT17 0x8CF1 +#define GL_COLOR_ATTACHMENT18 0x8CF2 +#define GL_COLOR_ATTACHMENT19 0x8CF3 +#define GL_COLOR_ATTACHMENT20 0x8CF4 +#define GL_COLOR_ATTACHMENT21 0x8CF5 +#define GL_COLOR_ATTACHMENT22 0x8CF6 +#define GL_COLOR_ATTACHMENT23 0x8CF7 +#define GL_COLOR_ATTACHMENT24 0x8CF8 +#define GL_COLOR_ATTACHMENT25 0x8CF9 +#define GL_COLOR_ATTACHMENT26 0x8CFA +#define GL_COLOR_ATTACHMENT27 0x8CFB +#define GL_COLOR_ATTACHMENT28 0x8CFC +#define GL_COLOR_ATTACHMENT29 0x8CFD +#define GL_COLOR_ATTACHMENT30 0x8CFE +#define GL_COLOR_ATTACHMENT31 0x8CFF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_INDEX 0x8222 +#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_CLAMP_VERTEX_COLOR 0x891A +#define GL_CLAMP_FRAGMENT_COLOR 0x891B +#define GL_ALPHA_INTEGER 0x8D97 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFF +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +#ifndef GL_VERSION_1_0 +#define GL_VERSION_1_0 1 +GLAPI int GLAD_GL_VERSION_1_0; +typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); +GLAPI PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); +GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); +GLAPI PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); +GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size); +GLAPI PFNGLPOINTSIZEPROC glad_glPointSize; +#define glPointSize glad_glPointSize +typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); +GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode; +#define glPolygonMode glad_glPolygonMode +typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params); +GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +#define glTexImage1D glad_glTexImage1D +typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf); +GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +#define glDrawBuffer glad_glDrawBuffer +typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); +GLAPI PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); +GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth); +GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth; +#define glClearDepth glad_glClearDepth +typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); +GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); +GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); +GLAPI PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); +GLAPI PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +typedef void (APIENTRYP PFNGLFINISHPROC)(); +GLAPI PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +typedef void (APIENTRYP PFNGLFLUSHPROC)(); +GLAPI PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode); +GLAPI PFNGLLOGICOPPROC glad_glLogicOp; +#define glLogicOp glad_glLogicOp +typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); +GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref; +#define glPixelStoref glad_glPixelStoref +typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src); +GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer; +#define glReadBuffer glad_glReadBuffer +typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); +GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data); +GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble *data); +GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev; +#define glGetDoublev glad_glGetDoublev +typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(); +GLAPI PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data); +GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data); +GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); +GLAPI PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +#define glGetTexImage glad_glGetTexImage +typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv +typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); +GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble near, GLdouble far); +GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange; +#define glDepthRange glad_glDepthRange +typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +typedef void (APIENTRYP PFNGLNEWLISTPROC)(GLuint list, GLenum mode); +GLAPI PFNGLNEWLISTPROC glad_glNewList; +#define glNewList glad_glNewList +typedef void (APIENTRYP PFNGLENDLISTPROC)(); +GLAPI PFNGLENDLISTPROC glad_glEndList; +#define glEndList glad_glEndList +typedef void (APIENTRYP PFNGLCALLLISTPROC)(GLuint list); +GLAPI PFNGLCALLLISTPROC glad_glCallList; +#define glCallList glad_glCallList +typedef void (APIENTRYP PFNGLCALLLISTSPROC)(GLsizei n, GLenum type, const void *lists); +GLAPI PFNGLCALLLISTSPROC glad_glCallLists; +#define glCallLists glad_glCallLists +typedef void (APIENTRYP PFNGLDELETELISTSPROC)(GLuint list, GLsizei range); +GLAPI PFNGLDELETELISTSPROC glad_glDeleteLists; +#define glDeleteLists glad_glDeleteLists +typedef GLuint (APIENTRYP PFNGLGENLISTSPROC)(GLsizei range); +GLAPI PFNGLGENLISTSPROC glad_glGenLists; +#define glGenLists glad_glGenLists +typedef void (APIENTRYP PFNGLLISTBASEPROC)(GLuint base); +GLAPI PFNGLLISTBASEPROC glad_glListBase; +#define glListBase glad_glListBase +typedef void (APIENTRYP PFNGLBEGINPROC)(GLenum mode); +GLAPI PFNGLBEGINPROC glad_glBegin; +#define glBegin glad_glBegin +typedef void (APIENTRYP PFNGLBITMAPPROC)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +GLAPI PFNGLBITMAPPROC glad_glBitmap; +#define glBitmap glad_glBitmap +typedef void (APIENTRYP PFNGLCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +GLAPI PFNGLCOLOR3BPROC glad_glColor3b; +#define glColor3b glad_glColor3b +typedef void (APIENTRYP PFNGLCOLOR3BVPROC)(const GLbyte *v); +GLAPI PFNGLCOLOR3BVPROC glad_glColor3bv; +#define glColor3bv glad_glColor3bv +typedef void (APIENTRYP PFNGLCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +GLAPI PFNGLCOLOR3DPROC glad_glColor3d; +#define glColor3d glad_glColor3d +typedef void (APIENTRYP PFNGLCOLOR3DVPROC)(const GLdouble *v); +GLAPI PFNGLCOLOR3DVPROC glad_glColor3dv; +#define glColor3dv glad_glColor3dv +typedef void (APIENTRYP PFNGLCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +GLAPI PFNGLCOLOR3FPROC glad_glColor3f; +#define glColor3f glad_glColor3f +typedef void (APIENTRYP PFNGLCOLOR3FVPROC)(const GLfloat *v); +GLAPI PFNGLCOLOR3FVPROC glad_glColor3fv; +#define glColor3fv glad_glColor3fv +typedef void (APIENTRYP PFNGLCOLOR3IPROC)(GLint red, GLint green, GLint blue); +GLAPI PFNGLCOLOR3IPROC glad_glColor3i; +#define glColor3i glad_glColor3i +typedef void (APIENTRYP PFNGLCOLOR3IVPROC)(const GLint *v); +GLAPI PFNGLCOLOR3IVPROC glad_glColor3iv; +#define glColor3iv glad_glColor3iv +typedef void (APIENTRYP PFNGLCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +GLAPI PFNGLCOLOR3SPROC glad_glColor3s; +#define glColor3s glad_glColor3s +typedef void (APIENTRYP PFNGLCOLOR3SVPROC)(const GLshort *v); +GLAPI PFNGLCOLOR3SVPROC glad_glColor3sv; +#define glColor3sv glad_glColor3sv +typedef void (APIENTRYP PFNGLCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +GLAPI PFNGLCOLOR3UBPROC glad_glColor3ub; +#define glColor3ub glad_glColor3ub +typedef void (APIENTRYP PFNGLCOLOR3UBVPROC)(const GLubyte *v); +GLAPI PFNGLCOLOR3UBVPROC glad_glColor3ubv; +#define glColor3ubv glad_glColor3ubv +typedef void (APIENTRYP PFNGLCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +GLAPI PFNGLCOLOR3UIPROC glad_glColor3ui; +#define glColor3ui glad_glColor3ui +typedef void (APIENTRYP PFNGLCOLOR3UIVPROC)(const GLuint *v); +GLAPI PFNGLCOLOR3UIVPROC glad_glColor3uiv; +#define glColor3uiv glad_glColor3uiv +typedef void (APIENTRYP PFNGLCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +GLAPI PFNGLCOLOR3USPROC glad_glColor3us; +#define glColor3us glad_glColor3us +typedef void (APIENTRYP PFNGLCOLOR3USVPROC)(const GLushort *v); +GLAPI PFNGLCOLOR3USVPROC glad_glColor3usv; +#define glColor3usv glad_glColor3usv +typedef void (APIENTRYP PFNGLCOLOR4BPROC)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +GLAPI PFNGLCOLOR4BPROC glad_glColor4b; +#define glColor4b glad_glColor4b +typedef void (APIENTRYP PFNGLCOLOR4BVPROC)(const GLbyte *v); +GLAPI PFNGLCOLOR4BVPROC glad_glColor4bv; +#define glColor4bv glad_glColor4bv +typedef void (APIENTRYP PFNGLCOLOR4DPROC)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +GLAPI PFNGLCOLOR4DPROC glad_glColor4d; +#define glColor4d glad_glColor4d +typedef void (APIENTRYP PFNGLCOLOR4DVPROC)(const GLdouble *v); +GLAPI PFNGLCOLOR4DVPROC glad_glColor4dv; +#define glColor4dv glad_glColor4dv +typedef void (APIENTRYP PFNGLCOLOR4FPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCOLOR4FPROC glad_glColor4f; +#define glColor4f glad_glColor4f +typedef void (APIENTRYP PFNGLCOLOR4FVPROC)(const GLfloat *v); +GLAPI PFNGLCOLOR4FVPROC glad_glColor4fv; +#define glColor4fv glad_glColor4fv +typedef void (APIENTRYP PFNGLCOLOR4IPROC)(GLint red, GLint green, GLint blue, GLint alpha); +GLAPI PFNGLCOLOR4IPROC glad_glColor4i; +#define glColor4i glad_glColor4i +typedef void (APIENTRYP PFNGLCOLOR4IVPROC)(const GLint *v); +GLAPI PFNGLCOLOR4IVPROC glad_glColor4iv; +#define glColor4iv glad_glColor4iv +typedef void (APIENTRYP PFNGLCOLOR4SPROC)(GLshort red, GLshort green, GLshort blue, GLshort alpha); +GLAPI PFNGLCOLOR4SPROC glad_glColor4s; +#define glColor4s glad_glColor4s +typedef void (APIENTRYP PFNGLCOLOR4SVPROC)(const GLshort *v); +GLAPI PFNGLCOLOR4SVPROC glad_glColor4sv; +#define glColor4sv glad_glColor4sv +typedef void (APIENTRYP PFNGLCOLOR4UBPROC)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +GLAPI PFNGLCOLOR4UBPROC glad_glColor4ub; +#define glColor4ub glad_glColor4ub +typedef void (APIENTRYP PFNGLCOLOR4UBVPROC)(const GLubyte *v); +GLAPI PFNGLCOLOR4UBVPROC glad_glColor4ubv; +#define glColor4ubv glad_glColor4ubv +typedef void (APIENTRYP PFNGLCOLOR4UIPROC)(GLuint red, GLuint green, GLuint blue, GLuint alpha); +GLAPI PFNGLCOLOR4UIPROC glad_glColor4ui; +#define glColor4ui glad_glColor4ui +typedef void (APIENTRYP PFNGLCOLOR4UIVPROC)(const GLuint *v); +GLAPI PFNGLCOLOR4UIVPROC glad_glColor4uiv; +#define glColor4uiv glad_glColor4uiv +typedef void (APIENTRYP PFNGLCOLOR4USPROC)(GLushort red, GLushort green, GLushort blue, GLushort alpha); +GLAPI PFNGLCOLOR4USPROC glad_glColor4us; +#define glColor4us glad_glColor4us +typedef void (APIENTRYP PFNGLCOLOR4USVPROC)(const GLushort *v); +GLAPI PFNGLCOLOR4USVPROC glad_glColor4usv; +#define glColor4usv glad_glColor4usv +typedef void (APIENTRYP PFNGLEDGEFLAGPROC)(GLboolean flag); +GLAPI PFNGLEDGEFLAGPROC glad_glEdgeFlag; +#define glEdgeFlag glad_glEdgeFlag +typedef void (APIENTRYP PFNGLEDGEFLAGVPROC)(const GLboolean *flag); +GLAPI PFNGLEDGEFLAGVPROC glad_glEdgeFlagv; +#define glEdgeFlagv glad_glEdgeFlagv +typedef void (APIENTRYP PFNGLENDPROC)(); +GLAPI PFNGLENDPROC glad_glEnd; +#define glEnd glad_glEnd +typedef void (APIENTRYP PFNGLINDEXDPROC)(GLdouble c); +GLAPI PFNGLINDEXDPROC glad_glIndexd; +#define glIndexd glad_glIndexd +typedef void (APIENTRYP PFNGLINDEXDVPROC)(const GLdouble *c); +GLAPI PFNGLINDEXDVPROC glad_glIndexdv; +#define glIndexdv glad_glIndexdv +typedef void (APIENTRYP PFNGLINDEXFPROC)(GLfloat c); +GLAPI PFNGLINDEXFPROC glad_glIndexf; +#define glIndexf glad_glIndexf +typedef void (APIENTRYP PFNGLINDEXFVPROC)(const GLfloat *c); +GLAPI PFNGLINDEXFVPROC glad_glIndexfv; +#define glIndexfv glad_glIndexfv +typedef void (APIENTRYP PFNGLINDEXIPROC)(GLint c); +GLAPI PFNGLINDEXIPROC glad_glIndexi; +#define glIndexi glad_glIndexi +typedef void (APIENTRYP PFNGLINDEXIVPROC)(const GLint *c); +GLAPI PFNGLINDEXIVPROC glad_glIndexiv; +#define glIndexiv glad_glIndexiv +typedef void (APIENTRYP PFNGLINDEXSPROC)(GLshort c); +GLAPI PFNGLINDEXSPROC glad_glIndexs; +#define glIndexs glad_glIndexs +typedef void (APIENTRYP PFNGLINDEXSVPROC)(const GLshort *c); +GLAPI PFNGLINDEXSVPROC glad_glIndexsv; +#define glIndexsv glad_glIndexsv +typedef void (APIENTRYP PFNGLNORMAL3BPROC)(GLbyte nx, GLbyte ny, GLbyte nz); +GLAPI PFNGLNORMAL3BPROC glad_glNormal3b; +#define glNormal3b glad_glNormal3b +typedef void (APIENTRYP PFNGLNORMAL3BVPROC)(const GLbyte *v); +GLAPI PFNGLNORMAL3BVPROC glad_glNormal3bv; +#define glNormal3bv glad_glNormal3bv +typedef void (APIENTRYP PFNGLNORMAL3DPROC)(GLdouble nx, GLdouble ny, GLdouble nz); +GLAPI PFNGLNORMAL3DPROC glad_glNormal3d; +#define glNormal3d glad_glNormal3d +typedef void (APIENTRYP PFNGLNORMAL3DVPROC)(const GLdouble *v); +GLAPI PFNGLNORMAL3DVPROC glad_glNormal3dv; +#define glNormal3dv glad_glNormal3dv +typedef void (APIENTRYP PFNGLNORMAL3FPROC)(GLfloat nx, GLfloat ny, GLfloat nz); +GLAPI PFNGLNORMAL3FPROC glad_glNormal3f; +#define glNormal3f glad_glNormal3f +typedef void (APIENTRYP PFNGLNORMAL3FVPROC)(const GLfloat *v); +GLAPI PFNGLNORMAL3FVPROC glad_glNormal3fv; +#define glNormal3fv glad_glNormal3fv +typedef void (APIENTRYP PFNGLNORMAL3IPROC)(GLint nx, GLint ny, GLint nz); +GLAPI PFNGLNORMAL3IPROC glad_glNormal3i; +#define glNormal3i glad_glNormal3i +typedef void (APIENTRYP PFNGLNORMAL3IVPROC)(const GLint *v); +GLAPI PFNGLNORMAL3IVPROC glad_glNormal3iv; +#define glNormal3iv glad_glNormal3iv +typedef void (APIENTRYP PFNGLNORMAL3SPROC)(GLshort nx, GLshort ny, GLshort nz); +GLAPI PFNGLNORMAL3SPROC glad_glNormal3s; +#define glNormal3s glad_glNormal3s +typedef void (APIENTRYP PFNGLNORMAL3SVPROC)(const GLshort *v); +GLAPI PFNGLNORMAL3SVPROC glad_glNormal3sv; +#define glNormal3sv glad_glNormal3sv +typedef void (APIENTRYP PFNGLRASTERPOS2DPROC)(GLdouble x, GLdouble y); +GLAPI PFNGLRASTERPOS2DPROC glad_glRasterPos2d; +#define glRasterPos2d glad_glRasterPos2d +typedef void (APIENTRYP PFNGLRASTERPOS2DVPROC)(const GLdouble *v); +GLAPI PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv; +#define glRasterPos2dv glad_glRasterPos2dv +typedef void (APIENTRYP PFNGLRASTERPOS2FPROC)(GLfloat x, GLfloat y); +GLAPI PFNGLRASTERPOS2FPROC glad_glRasterPos2f; +#define glRasterPos2f glad_glRasterPos2f +typedef void (APIENTRYP PFNGLRASTERPOS2FVPROC)(const GLfloat *v); +GLAPI PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv; +#define glRasterPos2fv glad_glRasterPos2fv +typedef void (APIENTRYP PFNGLRASTERPOS2IPROC)(GLint x, GLint y); +GLAPI PFNGLRASTERPOS2IPROC glad_glRasterPos2i; +#define glRasterPos2i glad_glRasterPos2i +typedef void (APIENTRYP PFNGLRASTERPOS2IVPROC)(const GLint *v); +GLAPI PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv; +#define glRasterPos2iv glad_glRasterPos2iv +typedef void (APIENTRYP PFNGLRASTERPOS2SPROC)(GLshort x, GLshort y); +GLAPI PFNGLRASTERPOS2SPROC glad_glRasterPos2s; +#define glRasterPos2s glad_glRasterPos2s +typedef void (APIENTRYP PFNGLRASTERPOS2SVPROC)(const GLshort *v); +GLAPI PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv; +#define glRasterPos2sv glad_glRasterPos2sv +typedef void (APIENTRYP PFNGLRASTERPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLRASTERPOS3DPROC glad_glRasterPos3d; +#define glRasterPos3d glad_glRasterPos3d +typedef void (APIENTRYP PFNGLRASTERPOS3DVPROC)(const GLdouble *v); +GLAPI PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv; +#define glRasterPos3dv glad_glRasterPos3dv +typedef void (APIENTRYP PFNGLRASTERPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLRASTERPOS3FPROC glad_glRasterPos3f; +#define glRasterPos3f glad_glRasterPos3f +typedef void (APIENTRYP PFNGLRASTERPOS3FVPROC)(const GLfloat *v); +GLAPI PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv; +#define glRasterPos3fv glad_glRasterPos3fv +typedef void (APIENTRYP PFNGLRASTERPOS3IPROC)(GLint x, GLint y, GLint z); +GLAPI PFNGLRASTERPOS3IPROC glad_glRasterPos3i; +#define glRasterPos3i glad_glRasterPos3i +typedef void (APIENTRYP PFNGLRASTERPOS3IVPROC)(const GLint *v); +GLAPI PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv; +#define glRasterPos3iv glad_glRasterPos3iv +typedef void (APIENTRYP PFNGLRASTERPOS3SPROC)(GLshort x, GLshort y, GLshort z); +GLAPI PFNGLRASTERPOS3SPROC glad_glRasterPos3s; +#define glRasterPos3s glad_glRasterPos3s +typedef void (APIENTRYP PFNGLRASTERPOS3SVPROC)(const GLshort *v); +GLAPI PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv; +#define glRasterPos3sv glad_glRasterPos3sv +typedef void (APIENTRYP PFNGLRASTERPOS4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLRASTERPOS4DPROC glad_glRasterPos4d; +#define glRasterPos4d glad_glRasterPos4d +typedef void (APIENTRYP PFNGLRASTERPOS4DVPROC)(const GLdouble *v); +GLAPI PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv; +#define glRasterPos4dv glad_glRasterPos4dv +typedef void (APIENTRYP PFNGLRASTERPOS4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLRASTERPOS4FPROC glad_glRasterPos4f; +#define glRasterPos4f glad_glRasterPos4f +typedef void (APIENTRYP PFNGLRASTERPOS4FVPROC)(const GLfloat *v); +GLAPI PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv; +#define glRasterPos4fv glad_glRasterPos4fv +typedef void (APIENTRYP PFNGLRASTERPOS4IPROC)(GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLRASTERPOS4IPROC glad_glRasterPos4i; +#define glRasterPos4i glad_glRasterPos4i +typedef void (APIENTRYP PFNGLRASTERPOS4IVPROC)(const GLint *v); +GLAPI PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv; +#define glRasterPos4iv glad_glRasterPos4iv +typedef void (APIENTRYP PFNGLRASTERPOS4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLRASTERPOS4SPROC glad_glRasterPos4s; +#define glRasterPos4s glad_glRasterPos4s +typedef void (APIENTRYP PFNGLRASTERPOS4SVPROC)(const GLshort *v); +GLAPI PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv; +#define glRasterPos4sv glad_glRasterPos4sv +typedef void (APIENTRYP PFNGLRECTDPROC)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +GLAPI PFNGLRECTDPROC glad_glRectd; +#define glRectd glad_glRectd +typedef void (APIENTRYP PFNGLRECTDVPROC)(const GLdouble *v1, const GLdouble *v2); +GLAPI PFNGLRECTDVPROC glad_glRectdv; +#define glRectdv glad_glRectdv +typedef void (APIENTRYP PFNGLRECTFPROC)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +GLAPI PFNGLRECTFPROC glad_glRectf; +#define glRectf glad_glRectf +typedef void (APIENTRYP PFNGLRECTFVPROC)(const GLfloat *v1, const GLfloat *v2); +GLAPI PFNGLRECTFVPROC glad_glRectfv; +#define glRectfv glad_glRectfv +typedef void (APIENTRYP PFNGLRECTIPROC)(GLint x1, GLint y1, GLint x2, GLint y2); +GLAPI PFNGLRECTIPROC glad_glRecti; +#define glRecti glad_glRecti +typedef void (APIENTRYP PFNGLRECTIVPROC)(const GLint *v1, const GLint *v2); +GLAPI PFNGLRECTIVPROC glad_glRectiv; +#define glRectiv glad_glRectiv +typedef void (APIENTRYP PFNGLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +GLAPI PFNGLRECTSPROC glad_glRects; +#define glRects glad_glRects +typedef void (APIENTRYP PFNGLRECTSVPROC)(const GLshort *v1, const GLshort *v2); +GLAPI PFNGLRECTSVPROC glad_glRectsv; +#define glRectsv glad_glRectsv +typedef void (APIENTRYP PFNGLTEXCOORD1DPROC)(GLdouble s); +GLAPI PFNGLTEXCOORD1DPROC glad_glTexCoord1d; +#define glTexCoord1d glad_glTexCoord1d +typedef void (APIENTRYP PFNGLTEXCOORD1DVPROC)(const GLdouble *v); +GLAPI PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv; +#define glTexCoord1dv glad_glTexCoord1dv +typedef void (APIENTRYP PFNGLTEXCOORD1FPROC)(GLfloat s); +GLAPI PFNGLTEXCOORD1FPROC glad_glTexCoord1f; +#define glTexCoord1f glad_glTexCoord1f +typedef void (APIENTRYP PFNGLTEXCOORD1FVPROC)(const GLfloat *v); +GLAPI PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv; +#define glTexCoord1fv glad_glTexCoord1fv +typedef void (APIENTRYP PFNGLTEXCOORD1IPROC)(GLint s); +GLAPI PFNGLTEXCOORD1IPROC glad_glTexCoord1i; +#define glTexCoord1i glad_glTexCoord1i +typedef void (APIENTRYP PFNGLTEXCOORD1IVPROC)(const GLint *v); +GLAPI PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv; +#define glTexCoord1iv glad_glTexCoord1iv +typedef void (APIENTRYP PFNGLTEXCOORD1SPROC)(GLshort s); +GLAPI PFNGLTEXCOORD1SPROC glad_glTexCoord1s; +#define glTexCoord1s glad_glTexCoord1s +typedef void (APIENTRYP PFNGLTEXCOORD1SVPROC)(const GLshort *v); +GLAPI PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv; +#define glTexCoord1sv glad_glTexCoord1sv +typedef void (APIENTRYP PFNGLTEXCOORD2DPROC)(GLdouble s, GLdouble t); +GLAPI PFNGLTEXCOORD2DPROC glad_glTexCoord2d; +#define glTexCoord2d glad_glTexCoord2d +typedef void (APIENTRYP PFNGLTEXCOORD2DVPROC)(const GLdouble *v); +GLAPI PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv; +#define glTexCoord2dv glad_glTexCoord2dv +typedef void (APIENTRYP PFNGLTEXCOORD2FPROC)(GLfloat s, GLfloat t); +GLAPI PFNGLTEXCOORD2FPROC glad_glTexCoord2f; +#define glTexCoord2f glad_glTexCoord2f +typedef void (APIENTRYP PFNGLTEXCOORD2FVPROC)(const GLfloat *v); +GLAPI PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv; +#define glTexCoord2fv glad_glTexCoord2fv +typedef void (APIENTRYP PFNGLTEXCOORD2IPROC)(GLint s, GLint t); +GLAPI PFNGLTEXCOORD2IPROC glad_glTexCoord2i; +#define glTexCoord2i glad_glTexCoord2i +typedef void (APIENTRYP PFNGLTEXCOORD2IVPROC)(const GLint *v); +GLAPI PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv; +#define glTexCoord2iv glad_glTexCoord2iv +typedef void (APIENTRYP PFNGLTEXCOORD2SPROC)(GLshort s, GLshort t); +GLAPI PFNGLTEXCOORD2SPROC glad_glTexCoord2s; +#define glTexCoord2s glad_glTexCoord2s +typedef void (APIENTRYP PFNGLTEXCOORD2SVPROC)(const GLshort *v); +GLAPI PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv; +#define glTexCoord2sv glad_glTexCoord2sv +typedef void (APIENTRYP PFNGLTEXCOORD3DPROC)(GLdouble s, GLdouble t, GLdouble r); +GLAPI PFNGLTEXCOORD3DPROC glad_glTexCoord3d; +#define glTexCoord3d glad_glTexCoord3d +typedef void (APIENTRYP PFNGLTEXCOORD3DVPROC)(const GLdouble *v); +GLAPI PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv; +#define glTexCoord3dv glad_glTexCoord3dv +typedef void (APIENTRYP PFNGLTEXCOORD3FPROC)(GLfloat s, GLfloat t, GLfloat r); +GLAPI PFNGLTEXCOORD3FPROC glad_glTexCoord3f; +#define glTexCoord3f glad_glTexCoord3f +typedef void (APIENTRYP PFNGLTEXCOORD3FVPROC)(const GLfloat *v); +GLAPI PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv; +#define glTexCoord3fv glad_glTexCoord3fv +typedef void (APIENTRYP PFNGLTEXCOORD3IPROC)(GLint s, GLint t, GLint r); +GLAPI PFNGLTEXCOORD3IPROC glad_glTexCoord3i; +#define glTexCoord3i glad_glTexCoord3i +typedef void (APIENTRYP PFNGLTEXCOORD3IVPROC)(const GLint *v); +GLAPI PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv; +#define glTexCoord3iv glad_glTexCoord3iv +typedef void (APIENTRYP PFNGLTEXCOORD3SPROC)(GLshort s, GLshort t, GLshort r); +GLAPI PFNGLTEXCOORD3SPROC glad_glTexCoord3s; +#define glTexCoord3s glad_glTexCoord3s +typedef void (APIENTRYP PFNGLTEXCOORD3SVPROC)(const GLshort *v); +GLAPI PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv; +#define glTexCoord3sv glad_glTexCoord3sv +typedef void (APIENTRYP PFNGLTEXCOORD4DPROC)(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI PFNGLTEXCOORD4DPROC glad_glTexCoord4d; +#define glTexCoord4d glad_glTexCoord4d +typedef void (APIENTRYP PFNGLTEXCOORD4DVPROC)(const GLdouble *v); +GLAPI PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv; +#define glTexCoord4dv glad_glTexCoord4dv +typedef void (APIENTRYP PFNGLTEXCOORD4FPROC)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI PFNGLTEXCOORD4FPROC glad_glTexCoord4f; +#define glTexCoord4f glad_glTexCoord4f +typedef void (APIENTRYP PFNGLTEXCOORD4FVPROC)(const GLfloat *v); +GLAPI PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv; +#define glTexCoord4fv glad_glTexCoord4fv +typedef void (APIENTRYP PFNGLTEXCOORD4IPROC)(GLint s, GLint t, GLint r, GLint q); +GLAPI PFNGLTEXCOORD4IPROC glad_glTexCoord4i; +#define glTexCoord4i glad_glTexCoord4i +typedef void (APIENTRYP PFNGLTEXCOORD4IVPROC)(const GLint *v); +GLAPI PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv; +#define glTexCoord4iv glad_glTexCoord4iv +typedef void (APIENTRYP PFNGLTEXCOORD4SPROC)(GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI PFNGLTEXCOORD4SPROC glad_glTexCoord4s; +#define glTexCoord4s glad_glTexCoord4s +typedef void (APIENTRYP PFNGLTEXCOORD4SVPROC)(const GLshort *v); +GLAPI PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv; +#define glTexCoord4sv glad_glTexCoord4sv +typedef void (APIENTRYP PFNGLVERTEX2DPROC)(GLdouble x, GLdouble y); +GLAPI PFNGLVERTEX2DPROC glad_glVertex2d; +#define glVertex2d glad_glVertex2d +typedef void (APIENTRYP PFNGLVERTEX2DVPROC)(const GLdouble *v); +GLAPI PFNGLVERTEX2DVPROC glad_glVertex2dv; +#define glVertex2dv glad_glVertex2dv +typedef void (APIENTRYP PFNGLVERTEX2FPROC)(GLfloat x, GLfloat y); +GLAPI PFNGLVERTEX2FPROC glad_glVertex2f; +#define glVertex2f glad_glVertex2f +typedef void (APIENTRYP PFNGLVERTEX2FVPROC)(const GLfloat *v); +GLAPI PFNGLVERTEX2FVPROC glad_glVertex2fv; +#define glVertex2fv glad_glVertex2fv +typedef void (APIENTRYP PFNGLVERTEX2IPROC)(GLint x, GLint y); +GLAPI PFNGLVERTEX2IPROC glad_glVertex2i; +#define glVertex2i glad_glVertex2i +typedef void (APIENTRYP PFNGLVERTEX2IVPROC)(const GLint *v); +GLAPI PFNGLVERTEX2IVPROC glad_glVertex2iv; +#define glVertex2iv glad_glVertex2iv +typedef void (APIENTRYP PFNGLVERTEX2SPROC)(GLshort x, GLshort y); +GLAPI PFNGLVERTEX2SPROC glad_glVertex2s; +#define glVertex2s glad_glVertex2s +typedef void (APIENTRYP PFNGLVERTEX2SVPROC)(const GLshort *v); +GLAPI PFNGLVERTEX2SVPROC glad_glVertex2sv; +#define glVertex2sv glad_glVertex2sv +typedef void (APIENTRYP PFNGLVERTEX3DPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLVERTEX3DPROC glad_glVertex3d; +#define glVertex3d glad_glVertex3d +typedef void (APIENTRYP PFNGLVERTEX3DVPROC)(const GLdouble *v); +GLAPI PFNGLVERTEX3DVPROC glad_glVertex3dv; +#define glVertex3dv glad_glVertex3dv +typedef void (APIENTRYP PFNGLVERTEX3FPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEX3FPROC glad_glVertex3f; +#define glVertex3f glad_glVertex3f +typedef void (APIENTRYP PFNGLVERTEX3FVPROC)(const GLfloat *v); +GLAPI PFNGLVERTEX3FVPROC glad_glVertex3fv; +#define glVertex3fv glad_glVertex3fv +typedef void (APIENTRYP PFNGLVERTEX3IPROC)(GLint x, GLint y, GLint z); +GLAPI PFNGLVERTEX3IPROC glad_glVertex3i; +#define glVertex3i glad_glVertex3i +typedef void (APIENTRYP PFNGLVERTEX3IVPROC)(const GLint *v); +GLAPI PFNGLVERTEX3IVPROC glad_glVertex3iv; +#define glVertex3iv glad_glVertex3iv +typedef void (APIENTRYP PFNGLVERTEX3SPROC)(GLshort x, GLshort y, GLshort z); +GLAPI PFNGLVERTEX3SPROC glad_glVertex3s; +#define glVertex3s glad_glVertex3s +typedef void (APIENTRYP PFNGLVERTEX3SVPROC)(const GLshort *v); +GLAPI PFNGLVERTEX3SVPROC glad_glVertex3sv; +#define glVertex3sv glad_glVertex3sv +typedef void (APIENTRYP PFNGLVERTEX4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLVERTEX4DPROC glad_glVertex4d; +#define glVertex4d glad_glVertex4d +typedef void (APIENTRYP PFNGLVERTEX4DVPROC)(const GLdouble *v); +GLAPI PFNGLVERTEX4DVPROC glad_glVertex4dv; +#define glVertex4dv glad_glVertex4dv +typedef void (APIENTRYP PFNGLVERTEX4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEX4FPROC glad_glVertex4f; +#define glVertex4f glad_glVertex4f +typedef void (APIENTRYP PFNGLVERTEX4FVPROC)(const GLfloat *v); +GLAPI PFNGLVERTEX4FVPROC glad_glVertex4fv; +#define glVertex4fv glad_glVertex4fv +typedef void (APIENTRYP PFNGLVERTEX4IPROC)(GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLVERTEX4IPROC glad_glVertex4i; +#define glVertex4i glad_glVertex4i +typedef void (APIENTRYP PFNGLVERTEX4IVPROC)(const GLint *v); +GLAPI PFNGLVERTEX4IVPROC glad_glVertex4iv; +#define glVertex4iv glad_glVertex4iv +typedef void (APIENTRYP PFNGLVERTEX4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLVERTEX4SPROC glad_glVertex4s; +#define glVertex4s glad_glVertex4s +typedef void (APIENTRYP PFNGLVERTEX4SVPROC)(const GLshort *v); +GLAPI PFNGLVERTEX4SVPROC glad_glVertex4sv; +#define glVertex4sv glad_glVertex4sv +typedef void (APIENTRYP PFNGLCLIPPLANEPROC)(GLenum plane, const GLdouble *equation); +GLAPI PFNGLCLIPPLANEPROC glad_glClipPlane; +#define glClipPlane glad_glClipPlane +typedef void (APIENTRYP PFNGLCOLORMATERIALPROC)(GLenum face, GLenum mode); +GLAPI PFNGLCOLORMATERIALPROC glad_glColorMaterial; +#define glColorMaterial glad_glColorMaterial +typedef void (APIENTRYP PFNGLFOGFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLFOGFPROC glad_glFogf; +#define glFogf glad_glFogf +typedef void (APIENTRYP PFNGLFOGFVPROC)(GLenum pname, const GLfloat *params); +GLAPI PFNGLFOGFVPROC glad_glFogfv; +#define glFogfv glad_glFogfv +typedef void (APIENTRYP PFNGLFOGIPROC)(GLenum pname, GLint param); +GLAPI PFNGLFOGIPROC glad_glFogi; +#define glFogi glad_glFogi +typedef void (APIENTRYP PFNGLFOGIVPROC)(GLenum pname, const GLint *params); +GLAPI PFNGLFOGIVPROC glad_glFogiv; +#define glFogiv glad_glFogiv +typedef void (APIENTRYP PFNGLLIGHTFPROC)(GLenum light, GLenum pname, GLfloat param); +GLAPI PFNGLLIGHTFPROC glad_glLightf; +#define glLightf glad_glLightf +typedef void (APIENTRYP PFNGLLIGHTFVPROC)(GLenum light, GLenum pname, const GLfloat *params); +GLAPI PFNGLLIGHTFVPROC glad_glLightfv; +#define glLightfv glad_glLightfv +typedef void (APIENTRYP PFNGLLIGHTIPROC)(GLenum light, GLenum pname, GLint param); +GLAPI PFNGLLIGHTIPROC glad_glLighti; +#define glLighti glad_glLighti +typedef void (APIENTRYP PFNGLLIGHTIVPROC)(GLenum light, GLenum pname, const GLint *params); +GLAPI PFNGLLIGHTIVPROC glad_glLightiv; +#define glLightiv glad_glLightiv +typedef void (APIENTRYP PFNGLLIGHTMODELFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLLIGHTMODELFPROC glad_glLightModelf; +#define glLightModelf glad_glLightModelf +typedef void (APIENTRYP PFNGLLIGHTMODELFVPROC)(GLenum pname, const GLfloat *params); +GLAPI PFNGLLIGHTMODELFVPROC glad_glLightModelfv; +#define glLightModelfv glad_glLightModelfv +typedef void (APIENTRYP PFNGLLIGHTMODELIPROC)(GLenum pname, GLint param); +GLAPI PFNGLLIGHTMODELIPROC glad_glLightModeli; +#define glLightModeli glad_glLightModeli +typedef void (APIENTRYP PFNGLLIGHTMODELIVPROC)(GLenum pname, const GLint *params); +GLAPI PFNGLLIGHTMODELIVPROC glad_glLightModeliv; +#define glLightModeliv glad_glLightModeliv +typedef void (APIENTRYP PFNGLLINESTIPPLEPROC)(GLint factor, GLushort pattern); +GLAPI PFNGLLINESTIPPLEPROC glad_glLineStipple; +#define glLineStipple glad_glLineStipple +typedef void (APIENTRYP PFNGLMATERIALFPROC)(GLenum face, GLenum pname, GLfloat param); +GLAPI PFNGLMATERIALFPROC glad_glMaterialf; +#define glMaterialf glad_glMaterialf +typedef void (APIENTRYP PFNGLMATERIALFVPROC)(GLenum face, GLenum pname, const GLfloat *params); +GLAPI PFNGLMATERIALFVPROC glad_glMaterialfv; +#define glMaterialfv glad_glMaterialfv +typedef void (APIENTRYP PFNGLMATERIALIPROC)(GLenum face, GLenum pname, GLint param); +GLAPI PFNGLMATERIALIPROC glad_glMateriali; +#define glMateriali glad_glMateriali +typedef void (APIENTRYP PFNGLMATERIALIVPROC)(GLenum face, GLenum pname, const GLint *params); +GLAPI PFNGLMATERIALIVPROC glad_glMaterialiv; +#define glMaterialiv glad_glMaterialiv +typedef void (APIENTRYP PFNGLPOLYGONSTIPPLEPROC)(const GLubyte *mask); +GLAPI PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple; +#define glPolygonStipple glad_glPolygonStipple +typedef void (APIENTRYP PFNGLSHADEMODELPROC)(GLenum mode); +GLAPI PFNGLSHADEMODELPROC glad_glShadeModel; +#define glShadeModel glad_glShadeModel +typedef void (APIENTRYP PFNGLTEXENVFPROC)(GLenum target, GLenum pname, GLfloat param); +GLAPI PFNGLTEXENVFPROC glad_glTexEnvf; +#define glTexEnvf glad_glTexEnvf +typedef void (APIENTRYP PFNGLTEXENVFVPROC)(GLenum target, GLenum pname, const GLfloat *params); +GLAPI PFNGLTEXENVFVPROC glad_glTexEnvfv; +#define glTexEnvfv glad_glTexEnvfv +typedef void (APIENTRYP PFNGLTEXENVIPROC)(GLenum target, GLenum pname, GLint param); +GLAPI PFNGLTEXENVIPROC glad_glTexEnvi; +#define glTexEnvi glad_glTexEnvi +typedef void (APIENTRYP PFNGLTEXENVIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXENVIVPROC glad_glTexEnviv; +#define glTexEnviv glad_glTexEnviv +typedef void (APIENTRYP PFNGLTEXGENDPROC)(GLenum coord, GLenum pname, GLdouble param); +GLAPI PFNGLTEXGENDPROC glad_glTexGend; +#define glTexGend glad_glTexGend +typedef void (APIENTRYP PFNGLTEXGENDVPROC)(GLenum coord, GLenum pname, const GLdouble *params); +GLAPI PFNGLTEXGENDVPROC glad_glTexGendv; +#define glTexGendv glad_glTexGendv +typedef void (APIENTRYP PFNGLTEXGENFPROC)(GLenum coord, GLenum pname, GLfloat param); +GLAPI PFNGLTEXGENFPROC glad_glTexGenf; +#define glTexGenf glad_glTexGenf +typedef void (APIENTRYP PFNGLTEXGENFVPROC)(GLenum coord, GLenum pname, const GLfloat *params); +GLAPI PFNGLTEXGENFVPROC glad_glTexGenfv; +#define glTexGenfv glad_glTexGenfv +typedef void (APIENTRYP PFNGLTEXGENIPROC)(GLenum coord, GLenum pname, GLint param); +GLAPI PFNGLTEXGENIPROC glad_glTexGeni; +#define glTexGeni glad_glTexGeni +typedef void (APIENTRYP PFNGLTEXGENIVPROC)(GLenum coord, GLenum pname, const GLint *params); +GLAPI PFNGLTEXGENIVPROC glad_glTexGeniv; +#define glTexGeniv glad_glTexGeniv +typedef void (APIENTRYP PFNGLFEEDBACKBUFFERPROC)(GLsizei size, GLenum type, GLfloat *buffer); +GLAPI PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer; +#define glFeedbackBuffer glad_glFeedbackBuffer +typedef void (APIENTRYP PFNGLSELECTBUFFERPROC)(GLsizei size, GLuint *buffer); +GLAPI PFNGLSELECTBUFFERPROC glad_glSelectBuffer; +#define glSelectBuffer glad_glSelectBuffer +typedef GLint (APIENTRYP PFNGLRENDERMODEPROC)(GLenum mode); +GLAPI PFNGLRENDERMODEPROC glad_glRenderMode; +#define glRenderMode glad_glRenderMode +typedef void (APIENTRYP PFNGLINITNAMESPROC)(); +GLAPI PFNGLINITNAMESPROC glad_glInitNames; +#define glInitNames glad_glInitNames +typedef void (APIENTRYP PFNGLLOADNAMEPROC)(GLuint name); +GLAPI PFNGLLOADNAMEPROC glad_glLoadName; +#define glLoadName glad_glLoadName +typedef void (APIENTRYP PFNGLPASSTHROUGHPROC)(GLfloat token); +GLAPI PFNGLPASSTHROUGHPROC glad_glPassThrough; +#define glPassThrough glad_glPassThrough +typedef void (APIENTRYP PFNGLPOPNAMEPROC)(); +GLAPI PFNGLPOPNAMEPROC glad_glPopName; +#define glPopName glad_glPopName +typedef void (APIENTRYP PFNGLPUSHNAMEPROC)(GLuint name); +GLAPI PFNGLPUSHNAMEPROC glad_glPushName; +#define glPushName glad_glPushName +typedef void (APIENTRYP PFNGLCLEARACCUMPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCLEARACCUMPROC glad_glClearAccum; +#define glClearAccum glad_glClearAccum +typedef void (APIENTRYP PFNGLCLEARINDEXPROC)(GLfloat c); +GLAPI PFNGLCLEARINDEXPROC glad_glClearIndex; +#define glClearIndex glad_glClearIndex +typedef void (APIENTRYP PFNGLINDEXMASKPROC)(GLuint mask); +GLAPI PFNGLINDEXMASKPROC glad_glIndexMask; +#define glIndexMask glad_glIndexMask +typedef void (APIENTRYP PFNGLACCUMPROC)(GLenum op, GLfloat value); +GLAPI PFNGLACCUMPROC glad_glAccum; +#define glAccum glad_glAccum +typedef void (APIENTRYP PFNGLPOPATTRIBPROC)(); +GLAPI PFNGLPOPATTRIBPROC glad_glPopAttrib; +#define glPopAttrib glad_glPopAttrib +typedef void (APIENTRYP PFNGLPUSHATTRIBPROC)(GLbitfield mask); +GLAPI PFNGLPUSHATTRIBPROC glad_glPushAttrib; +#define glPushAttrib glad_glPushAttrib +typedef void (APIENTRYP PFNGLMAP1DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +GLAPI PFNGLMAP1DPROC glad_glMap1d; +#define glMap1d glad_glMap1d +typedef void (APIENTRYP PFNGLMAP1FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +GLAPI PFNGLMAP1FPROC glad_glMap1f; +#define glMap1f glad_glMap1f +typedef void (APIENTRYP PFNGLMAP2DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +GLAPI PFNGLMAP2DPROC glad_glMap2d; +#define glMap2d glad_glMap2d +typedef void (APIENTRYP PFNGLMAP2FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +GLAPI PFNGLMAP2FPROC glad_glMap2f; +#define glMap2f glad_glMap2f +typedef void (APIENTRYP PFNGLMAPGRID1DPROC)(GLint un, GLdouble u1, GLdouble u2); +GLAPI PFNGLMAPGRID1DPROC glad_glMapGrid1d; +#define glMapGrid1d glad_glMapGrid1d +typedef void (APIENTRYP PFNGLMAPGRID1FPROC)(GLint un, GLfloat u1, GLfloat u2); +GLAPI PFNGLMAPGRID1FPROC glad_glMapGrid1f; +#define glMapGrid1f glad_glMapGrid1f +typedef void (APIENTRYP PFNGLMAPGRID2DPROC)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +GLAPI PFNGLMAPGRID2DPROC glad_glMapGrid2d; +#define glMapGrid2d glad_glMapGrid2d +typedef void (APIENTRYP PFNGLMAPGRID2FPROC)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +GLAPI PFNGLMAPGRID2FPROC glad_glMapGrid2f; +#define glMapGrid2f glad_glMapGrid2f +typedef void (APIENTRYP PFNGLEVALCOORD1DPROC)(GLdouble u); +GLAPI PFNGLEVALCOORD1DPROC glad_glEvalCoord1d; +#define glEvalCoord1d glad_glEvalCoord1d +typedef void (APIENTRYP PFNGLEVALCOORD1DVPROC)(const GLdouble *u); +GLAPI PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv; +#define glEvalCoord1dv glad_glEvalCoord1dv +typedef void (APIENTRYP PFNGLEVALCOORD1FPROC)(GLfloat u); +GLAPI PFNGLEVALCOORD1FPROC glad_glEvalCoord1f; +#define glEvalCoord1f glad_glEvalCoord1f +typedef void (APIENTRYP PFNGLEVALCOORD1FVPROC)(const GLfloat *u); +GLAPI PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv; +#define glEvalCoord1fv glad_glEvalCoord1fv +typedef void (APIENTRYP PFNGLEVALCOORD2DPROC)(GLdouble u, GLdouble v); +GLAPI PFNGLEVALCOORD2DPROC glad_glEvalCoord2d; +#define glEvalCoord2d glad_glEvalCoord2d +typedef void (APIENTRYP PFNGLEVALCOORD2DVPROC)(const GLdouble *u); +GLAPI PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv; +#define glEvalCoord2dv glad_glEvalCoord2dv +typedef void (APIENTRYP PFNGLEVALCOORD2FPROC)(GLfloat u, GLfloat v); +GLAPI PFNGLEVALCOORD2FPROC glad_glEvalCoord2f; +#define glEvalCoord2f glad_glEvalCoord2f +typedef void (APIENTRYP PFNGLEVALCOORD2FVPROC)(const GLfloat *u); +GLAPI PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv; +#define glEvalCoord2fv glad_glEvalCoord2fv +typedef void (APIENTRYP PFNGLEVALMESH1PROC)(GLenum mode, GLint i1, GLint i2); +GLAPI PFNGLEVALMESH1PROC glad_glEvalMesh1; +#define glEvalMesh1 glad_glEvalMesh1 +typedef void (APIENTRYP PFNGLEVALPOINT1PROC)(GLint i); +GLAPI PFNGLEVALPOINT1PROC glad_glEvalPoint1; +#define glEvalPoint1 glad_glEvalPoint1 +typedef void (APIENTRYP PFNGLEVALMESH2PROC)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +GLAPI PFNGLEVALMESH2PROC glad_glEvalMesh2; +#define glEvalMesh2 glad_glEvalMesh2 +typedef void (APIENTRYP PFNGLEVALPOINT2PROC)(GLint i, GLint j); +GLAPI PFNGLEVALPOINT2PROC glad_glEvalPoint2; +#define glEvalPoint2 glad_glEvalPoint2 +typedef void (APIENTRYP PFNGLALPHAFUNCPROC)(GLenum func, GLfloat ref); +GLAPI PFNGLALPHAFUNCPROC glad_glAlphaFunc; +#define glAlphaFunc glad_glAlphaFunc +typedef void (APIENTRYP PFNGLPIXELZOOMPROC)(GLfloat xfactor, GLfloat yfactor); +GLAPI PFNGLPIXELZOOMPROC glad_glPixelZoom; +#define glPixelZoom glad_glPixelZoom +typedef void (APIENTRYP PFNGLPIXELTRANSFERFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf; +#define glPixelTransferf glad_glPixelTransferf +typedef void (APIENTRYP PFNGLPIXELTRANSFERIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi; +#define glPixelTransferi glad_glPixelTransferi +typedef void (APIENTRYP PFNGLPIXELMAPFVPROC)(GLenum map, GLsizei mapsize, const GLfloat *values); +GLAPI PFNGLPIXELMAPFVPROC glad_glPixelMapfv; +#define glPixelMapfv glad_glPixelMapfv +typedef void (APIENTRYP PFNGLPIXELMAPUIVPROC)(GLenum map, GLsizei mapsize, const GLuint *values); +GLAPI PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv; +#define glPixelMapuiv glad_glPixelMapuiv +typedef void (APIENTRYP PFNGLPIXELMAPUSVPROC)(GLenum map, GLsizei mapsize, const GLushort *values); +GLAPI PFNGLPIXELMAPUSVPROC glad_glPixelMapusv; +#define glPixelMapusv glad_glPixelMapusv +typedef void (APIENTRYP PFNGLCOPYPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +GLAPI PFNGLCOPYPIXELSPROC glad_glCopyPixels; +#define glCopyPixels glad_glCopyPixels +typedef void (APIENTRYP PFNGLDRAWPIXELSPROC)(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLDRAWPIXELSPROC glad_glDrawPixels; +#define glDrawPixels glad_glDrawPixels +typedef void (APIENTRYP PFNGLGETCLIPPLANEPROC)(GLenum plane, GLdouble *equation); +GLAPI PFNGLGETCLIPPLANEPROC glad_glGetClipPlane; +#define glGetClipPlane glad_glGetClipPlane +typedef void (APIENTRYP PFNGLGETLIGHTFVPROC)(GLenum light, GLenum pname, GLfloat *params); +GLAPI PFNGLGETLIGHTFVPROC glad_glGetLightfv; +#define glGetLightfv glad_glGetLightfv +typedef void (APIENTRYP PFNGLGETLIGHTIVPROC)(GLenum light, GLenum pname, GLint *params); +GLAPI PFNGLGETLIGHTIVPROC glad_glGetLightiv; +#define glGetLightiv glad_glGetLightiv +typedef void (APIENTRYP PFNGLGETMAPDVPROC)(GLenum target, GLenum query, GLdouble *v); +GLAPI PFNGLGETMAPDVPROC glad_glGetMapdv; +#define glGetMapdv glad_glGetMapdv +typedef void (APIENTRYP PFNGLGETMAPFVPROC)(GLenum target, GLenum query, GLfloat *v); +GLAPI PFNGLGETMAPFVPROC glad_glGetMapfv; +#define glGetMapfv glad_glGetMapfv +typedef void (APIENTRYP PFNGLGETMAPIVPROC)(GLenum target, GLenum query, GLint *v); +GLAPI PFNGLGETMAPIVPROC glad_glGetMapiv; +#define glGetMapiv glad_glGetMapiv +typedef void (APIENTRYP PFNGLGETMATERIALFVPROC)(GLenum face, GLenum pname, GLfloat *params); +GLAPI PFNGLGETMATERIALFVPROC glad_glGetMaterialfv; +#define glGetMaterialfv glad_glGetMaterialfv +typedef void (APIENTRYP PFNGLGETMATERIALIVPROC)(GLenum face, GLenum pname, GLint *params); +GLAPI PFNGLGETMATERIALIVPROC glad_glGetMaterialiv; +#define glGetMaterialiv glad_glGetMaterialiv +typedef void (APIENTRYP PFNGLGETPIXELMAPFVPROC)(GLenum map, GLfloat *values); +GLAPI PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv; +#define glGetPixelMapfv glad_glGetPixelMapfv +typedef void (APIENTRYP PFNGLGETPIXELMAPUIVPROC)(GLenum map, GLuint *values); +GLAPI PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv; +#define glGetPixelMapuiv glad_glGetPixelMapuiv +typedef void (APIENTRYP PFNGLGETPIXELMAPUSVPROC)(GLenum map, GLushort *values); +GLAPI PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv; +#define glGetPixelMapusv glad_glGetPixelMapusv +typedef void (APIENTRYP PFNGLGETPOLYGONSTIPPLEPROC)(GLubyte *mask); +GLAPI PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; +#define glGetPolygonStipple glad_glGetPolygonStipple +typedef void (APIENTRYP PFNGLGETTEXENVFVPROC)(GLenum target, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv; +#define glGetTexEnvfv glad_glGetTexEnvfv +typedef void (APIENTRYP PFNGLGETTEXENVIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXENVIVPROC glad_glGetTexEnviv; +#define glGetTexEnviv glad_glGetTexEnviv +typedef void (APIENTRYP PFNGLGETTEXGENDVPROC)(GLenum coord, GLenum pname, GLdouble *params); +GLAPI PFNGLGETTEXGENDVPROC glad_glGetTexGendv; +#define glGetTexGendv glad_glGetTexGendv +typedef void (APIENTRYP PFNGLGETTEXGENFVPROC)(GLenum coord, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXGENFVPROC glad_glGetTexGenfv; +#define glGetTexGenfv glad_glGetTexGenfv +typedef void (APIENTRYP PFNGLGETTEXGENIVPROC)(GLenum coord, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXGENIVPROC glad_glGetTexGeniv; +#define glGetTexGeniv glad_glGetTexGeniv +typedef GLboolean (APIENTRYP PFNGLISLISTPROC)(GLuint list); +GLAPI PFNGLISLISTPROC glad_glIsList; +#define glIsList glad_glIsList +typedef void (APIENTRYP PFNGLFRUSTUMPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI PFNGLFRUSTUMPROC glad_glFrustum; +#define glFrustum glad_glFrustum +typedef void (APIENTRYP PFNGLLOADIDENTITYPROC)(); +GLAPI PFNGLLOADIDENTITYPROC glad_glLoadIdentity; +#define glLoadIdentity glad_glLoadIdentity +typedef void (APIENTRYP PFNGLLOADMATRIXFPROC)(const GLfloat *m); +GLAPI PFNGLLOADMATRIXFPROC glad_glLoadMatrixf; +#define glLoadMatrixf glad_glLoadMatrixf +typedef void (APIENTRYP PFNGLLOADMATRIXDPROC)(const GLdouble *m); +GLAPI PFNGLLOADMATRIXDPROC glad_glLoadMatrixd; +#define glLoadMatrixd glad_glLoadMatrixd +typedef void (APIENTRYP PFNGLMATRIXMODEPROC)(GLenum mode); +GLAPI PFNGLMATRIXMODEPROC glad_glMatrixMode; +#define glMatrixMode glad_glMatrixMode +typedef void (APIENTRYP PFNGLMULTMATRIXFPROC)(const GLfloat *m); +GLAPI PFNGLMULTMATRIXFPROC glad_glMultMatrixf; +#define glMultMatrixf glad_glMultMatrixf +typedef void (APIENTRYP PFNGLMULTMATRIXDPROC)(const GLdouble *m); +GLAPI PFNGLMULTMATRIXDPROC glad_glMultMatrixd; +#define glMultMatrixd glad_glMultMatrixd +typedef void (APIENTRYP PFNGLORTHOPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI PFNGLORTHOPROC glad_glOrtho; +#define glOrtho glad_glOrtho +typedef void (APIENTRYP PFNGLPOPMATRIXPROC)(); +GLAPI PFNGLPOPMATRIXPROC glad_glPopMatrix; +#define glPopMatrix glad_glPopMatrix +typedef void (APIENTRYP PFNGLPUSHMATRIXPROC)(); +GLAPI PFNGLPUSHMATRIXPROC glad_glPushMatrix; +#define glPushMatrix glad_glPushMatrix +typedef void (APIENTRYP PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLROTATEDPROC glad_glRotated; +#define glRotated glad_glRotated +typedef void (APIENTRYP PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLROTATEFPROC glad_glRotatef; +#define glRotatef glad_glRotatef +typedef void (APIENTRYP PFNGLSCALEDPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLSCALEDPROC glad_glScaled; +#define glScaled glad_glScaled +typedef void (APIENTRYP PFNGLSCALEFPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLSCALEFPROC glad_glScalef; +#define glScalef glad_glScalef +typedef void (APIENTRYP PFNGLTRANSLATEDPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLTRANSLATEDPROC glad_glTranslated; +#define glTranslated glad_glTranslated +typedef void (APIENTRYP PFNGLTRANSLATEFPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLTRANSLATEFPROC glad_glTranslatef; +#define glTranslatef glad_glTranslatef +#endif +#ifndef GL_VERSION_1_1 +#define GL_VERSION_1_1 1 +GLAPI int GLAD_GL_VERSION_1_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices); +GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +typedef void (APIENTRYP PFNGLGETPOINTERVPROC)(GLenum pname, void **params); +GLAPI PFNGLGETPOINTERVPROC glad_glGetPointerv; +#define glGetPointerv glad_glGetPointerv +typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +#define glCopyTexImage1D glad_glCopyTexImage1D +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +#define glCopyTexSubImage1D glad_glCopyTexSubImage1D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +#define glTexSubImage1D glad_glTexSubImage1D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures); +GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures); +GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); +GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +typedef void (APIENTRYP PFNGLARRAYELEMENTPROC)(GLint i); +GLAPI PFNGLARRAYELEMENTPROC glad_glArrayElement; +#define glArrayElement glad_glArrayElement +typedef void (APIENTRYP PFNGLCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLCOLORPOINTERPROC glad_glColorPointer; +#define glColorPointer glad_glColorPointer +typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEPROC)(GLenum array); +GLAPI PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState; +#define glDisableClientState glad_glDisableClientState +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERPROC)(GLsizei stride, const void *pointer); +GLAPI PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer; +#define glEdgeFlagPointer glad_glEdgeFlagPointer +typedef void (APIENTRYP PFNGLENABLECLIENTSTATEPROC)(GLenum array); +GLAPI PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState; +#define glEnableClientState glad_glEnableClientState +typedef void (APIENTRYP PFNGLINDEXPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLINDEXPOINTERPROC glad_glIndexPointer; +#define glIndexPointer glad_glIndexPointer +typedef void (APIENTRYP PFNGLINTERLEAVEDARRAYSPROC)(GLenum format, GLsizei stride, const void *pointer); +GLAPI PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays; +#define glInterleavedArrays glad_glInterleavedArrays +typedef void (APIENTRYP PFNGLNORMALPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLNORMALPOINTERPROC glad_glNormalPointer; +#define glNormalPointer glad_glNormalPointer +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer; +#define glTexCoordPointer glad_glTexCoordPointer +typedef void (APIENTRYP PFNGLVERTEXPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXPOINTERPROC glad_glVertexPointer; +#define glVertexPointer glad_glVertexPointer +typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTPROC)(GLsizei n, const GLuint *textures, GLboolean *residences); +GLAPI PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident; +#define glAreTexturesResident glad_glAreTexturesResident +typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint *textures, const GLfloat *priorities); +GLAPI PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; +#define glPrioritizeTextures glad_glPrioritizeTextures +typedef void (APIENTRYP PFNGLINDEXUBPROC)(GLubyte c); +GLAPI PFNGLINDEXUBPROC glad_glIndexub; +#define glIndexub glad_glIndexub +typedef void (APIENTRYP PFNGLINDEXUBVPROC)(const GLubyte *c); +GLAPI PFNGLINDEXUBVPROC glad_glIndexubv; +#define glIndexubv glad_glIndexubv +typedef void (APIENTRYP PFNGLPOPCLIENTATTRIBPROC)(); +GLAPI PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib; +#define glPopClientAttrib glad_glPopClientAttrib +typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBPROC)(GLbitfield mask); +GLAPI PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib; +#define glPushClientAttrib glad_glPushClientAttrib +#endif +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +GLAPI int GLAD_GL_VERSION_1_2; +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +#define glDrawRangeElements glad_glDrawRangeElements +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +#define glTexImage3D glad_glTexImage3D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +#define glTexSubImage3D glad_glTexSubImage3D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +#define glCopyTexSubImage3D glad_glCopyTexSubImage3D +#endif +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +GLAPI int GLAD_GL_VERSION_1_3; +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); +GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +#define glCompressedTexImage3D glad_glCompressedTexImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +#define glCompressedTexImage1D glad_glCompressedTexImage1D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void *img); +GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +#define glGetCompressedTexImage glad_glGetCompressedTexImage +typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC)(GLenum texture); +GLAPI PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture; +#define glClientActiveTexture glad_glClientActiveTexture +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC)(GLenum target, GLdouble s); +GLAPI PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d; +#define glMultiTexCoord1d glad_glMultiTexCoord1d +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC)(GLenum target, const GLdouble *v); +GLAPI PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv; +#define glMultiTexCoord1dv glad_glMultiTexCoord1dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC)(GLenum target, GLfloat s); +GLAPI PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f; +#define glMultiTexCoord1f glad_glMultiTexCoord1f +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC)(GLenum target, const GLfloat *v); +GLAPI PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv; +#define glMultiTexCoord1fv glad_glMultiTexCoord1fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC)(GLenum target, GLint s); +GLAPI PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i; +#define glMultiTexCoord1i glad_glMultiTexCoord1i +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC)(GLenum target, const GLint *v); +GLAPI PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv; +#define glMultiTexCoord1iv glad_glMultiTexCoord1iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC)(GLenum target, GLshort s); +GLAPI PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s; +#define glMultiTexCoord1s glad_glMultiTexCoord1s +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC)(GLenum target, const GLshort *v); +GLAPI PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv; +#define glMultiTexCoord1sv glad_glMultiTexCoord1sv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC)(GLenum target, GLdouble s, GLdouble t); +GLAPI PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d; +#define glMultiTexCoord2d glad_glMultiTexCoord2d +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC)(GLenum target, const GLdouble *v); +GLAPI PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv; +#define glMultiTexCoord2dv glad_glMultiTexCoord2dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC)(GLenum target, GLfloat s, GLfloat t); +GLAPI PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f; +#define glMultiTexCoord2f glad_glMultiTexCoord2f +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC)(GLenum target, const GLfloat *v); +GLAPI PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv; +#define glMultiTexCoord2fv glad_glMultiTexCoord2fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC)(GLenum target, GLint s, GLint t); +GLAPI PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i; +#define glMultiTexCoord2i glad_glMultiTexCoord2i +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC)(GLenum target, const GLint *v); +GLAPI PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv; +#define glMultiTexCoord2iv glad_glMultiTexCoord2iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC)(GLenum target, GLshort s, GLshort t); +GLAPI PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s; +#define glMultiTexCoord2s glad_glMultiTexCoord2s +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC)(GLenum target, const GLshort *v); +GLAPI PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv; +#define glMultiTexCoord2sv glad_glMultiTexCoord2sv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r); +GLAPI PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d; +#define glMultiTexCoord3d glad_glMultiTexCoord3d +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC)(GLenum target, const GLdouble *v); +GLAPI PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv; +#define glMultiTexCoord3dv glad_glMultiTexCoord3dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r); +GLAPI PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f; +#define glMultiTexCoord3f glad_glMultiTexCoord3f +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC)(GLenum target, const GLfloat *v); +GLAPI PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv; +#define glMultiTexCoord3fv glad_glMultiTexCoord3fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC)(GLenum target, GLint s, GLint t, GLint r); +GLAPI PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i; +#define glMultiTexCoord3i glad_glMultiTexCoord3i +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC)(GLenum target, const GLint *v); +GLAPI PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv; +#define glMultiTexCoord3iv glad_glMultiTexCoord3iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC)(GLenum target, GLshort s, GLshort t, GLshort r); +GLAPI PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s; +#define glMultiTexCoord3s glad_glMultiTexCoord3s +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC)(GLenum target, const GLshort *v); +GLAPI PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv; +#define glMultiTexCoord3sv glad_glMultiTexCoord3sv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d; +#define glMultiTexCoord4d glad_glMultiTexCoord4d +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC)(GLenum target, const GLdouble *v); +GLAPI PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv; +#define glMultiTexCoord4dv glad_glMultiTexCoord4dv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f; +#define glMultiTexCoord4f glad_glMultiTexCoord4f +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC)(GLenum target, const GLfloat *v); +GLAPI PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv; +#define glMultiTexCoord4fv glad_glMultiTexCoord4fv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q); +GLAPI PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i; +#define glMultiTexCoord4i glad_glMultiTexCoord4i +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC)(GLenum target, const GLint *v); +GLAPI PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv; +#define glMultiTexCoord4iv glad_glMultiTexCoord4iv +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s; +#define glMultiTexCoord4s glad_glMultiTexCoord4s +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC)(GLenum target, const GLshort *v); +GLAPI PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv; +#define glMultiTexCoord4sv glad_glMultiTexCoord4sv +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC)(const GLfloat *m); +GLAPI PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf; +#define glLoadTransposeMatrixf glad_glLoadTransposeMatrixf +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC)(const GLdouble *m); +GLAPI PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd; +#define glLoadTransposeMatrixd glad_glLoadTransposeMatrixd +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC)(const GLfloat *m); +GLAPI PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf; +#define glMultTransposeMatrixf glad_glMultTransposeMatrixf +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC)(const GLdouble *m); +GLAPI PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd; +#define glMultTransposeMatrixd glad_glMultTransposeMatrixd +#endif +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +GLAPI int GLAD_GL_VERSION_1_4; +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +#define glMultiDrawArrays glad_glMultiDrawArrays +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +#define glMultiDrawElements glad_glMultiDrawElements +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +#define glPointParameterf glad_glPointParameterf +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat *params); +GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +#define glPointParameterfv glad_glPointParameterfv +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +#define glPointParameteri glad_glPointParameteri +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint *params); +GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +#define glPointParameteriv glad_glPointParameteriv +typedef void (APIENTRYP PFNGLFOGCOORDFPROC)(GLfloat coord); +GLAPI PFNGLFOGCOORDFPROC glad_glFogCoordf; +#define glFogCoordf glad_glFogCoordf +typedef void (APIENTRYP PFNGLFOGCOORDFVPROC)(const GLfloat *coord); +GLAPI PFNGLFOGCOORDFVPROC glad_glFogCoordfv; +#define glFogCoordfv glad_glFogCoordfv +typedef void (APIENTRYP PFNGLFOGCOORDDPROC)(GLdouble coord); +GLAPI PFNGLFOGCOORDDPROC glad_glFogCoordd; +#define glFogCoordd glad_glFogCoordd +typedef void (APIENTRYP PFNGLFOGCOORDDVPROC)(const GLdouble *coord); +GLAPI PFNGLFOGCOORDDVPROC glad_glFogCoorddv; +#define glFogCoorddv glad_glFogCoorddv +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer; +#define glFogCoordPointer glad_glFogCoordPointer +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +GLAPI PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b; +#define glSecondaryColor3b glad_glSecondaryColor3b +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC)(const GLbyte *v); +GLAPI PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv; +#define glSecondaryColor3bv glad_glSecondaryColor3bv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +GLAPI PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d; +#define glSecondaryColor3d glad_glSecondaryColor3d +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC)(const GLdouble *v); +GLAPI PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv; +#define glSecondaryColor3dv glad_glSecondaryColor3dv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +GLAPI PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f; +#define glSecondaryColor3f glad_glSecondaryColor3f +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC)(const GLfloat *v); +GLAPI PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv; +#define glSecondaryColor3fv glad_glSecondaryColor3fv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC)(GLint red, GLint green, GLint blue); +GLAPI PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i; +#define glSecondaryColor3i glad_glSecondaryColor3i +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC)(const GLint *v); +GLAPI PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv; +#define glSecondaryColor3iv glad_glSecondaryColor3iv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +GLAPI PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s; +#define glSecondaryColor3s glad_glSecondaryColor3s +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC)(const GLshort *v); +GLAPI PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv; +#define glSecondaryColor3sv glad_glSecondaryColor3sv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +GLAPI PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub; +#define glSecondaryColor3ub glad_glSecondaryColor3ub +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC)(const GLubyte *v); +GLAPI PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv; +#define glSecondaryColor3ubv glad_glSecondaryColor3ubv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +GLAPI PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui; +#define glSecondaryColor3ui glad_glSecondaryColor3ui +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC)(const GLuint *v); +GLAPI PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv; +#define glSecondaryColor3uiv glad_glSecondaryColor3uiv +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +GLAPI PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us; +#define glSecondaryColor3us glad_glSecondaryColor3us +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC)(const GLushort *v); +GLAPI PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv; +#define glSecondaryColor3usv glad_glSecondaryColor3usv +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer; +#define glSecondaryColorPointer glad_glSecondaryColorPointer +typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC)(GLdouble x, GLdouble y); +GLAPI PFNGLWINDOWPOS2DPROC glad_glWindowPos2d; +#define glWindowPos2d glad_glWindowPos2d +typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC)(const GLdouble *v); +GLAPI PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv; +#define glWindowPos2dv glad_glWindowPos2dv +typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC)(GLfloat x, GLfloat y); +GLAPI PFNGLWINDOWPOS2FPROC glad_glWindowPos2f; +#define glWindowPos2f glad_glWindowPos2f +typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC)(const GLfloat *v); +GLAPI PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv; +#define glWindowPos2fv glad_glWindowPos2fv +typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC)(GLint x, GLint y); +GLAPI PFNGLWINDOWPOS2IPROC glad_glWindowPos2i; +#define glWindowPos2i glad_glWindowPos2i +typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC)(const GLint *v); +GLAPI PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv; +#define glWindowPos2iv glad_glWindowPos2iv +typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC)(GLshort x, GLshort y); +GLAPI PFNGLWINDOWPOS2SPROC glad_glWindowPos2s; +#define glWindowPos2s glad_glWindowPos2s +typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC)(const GLshort *v); +GLAPI PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv; +#define glWindowPos2sv glad_glWindowPos2sv +typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLWINDOWPOS3DPROC glad_glWindowPos3d; +#define glWindowPos3d glad_glWindowPos3d +typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC)(const GLdouble *v); +GLAPI PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv; +#define glWindowPos3dv glad_glWindowPos3dv +typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLWINDOWPOS3FPROC glad_glWindowPos3f; +#define glWindowPos3f glad_glWindowPos3f +typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC)(const GLfloat *v); +GLAPI PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv; +#define glWindowPos3fv glad_glWindowPos3fv +typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z); +GLAPI PFNGLWINDOWPOS3IPROC glad_glWindowPos3i; +#define glWindowPos3i glad_glWindowPos3i +typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC)(const GLint *v); +GLAPI PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv; +#define glWindowPos3iv glad_glWindowPos3iv +typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z); +GLAPI PFNGLWINDOWPOS3SPROC glad_glWindowPos3s; +#define glWindowPos3s glad_glWindowPos3s +typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC)(const GLshort *v); +GLAPI PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv; +#define glWindowPos3sv glad_glWindowPos3sv +typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); +GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +#endif +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +GLAPI int GLAD_GL_VERSION_1_5; +typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint *ids); +GLAPI PFNGLGENQUERIESPROC glad_glGenQueries; +#define glGenQueries glad_glGenQueries +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint *ids); +GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +#define glDeleteQueries glad_glDeleteQueries +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id); +GLAPI PFNGLISQUERYPROC glad_glIsQuery; +#define glIsQuery glad_glIsQuery +typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); +GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery; +#define glBeginQuery glad_glBeginQuery +typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target); +GLAPI PFNGLENDQUERYPROC glad_glEndQuery; +#define glEndQuery glad_glEndQuery +typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv; +#define glGetQueryiv glad_glGetQueryiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint *params); +GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +#define glGetQueryObjectiv glad_glGetQueryObjectiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint *params); +GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +#define glGetQueryObjectuiv glad_glGetQueryObjectuiv +typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers); +GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers); +GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); +GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); +GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void *data); +GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +#define glGetBufferSubData glad_glGetBufferSubData +typedef void * (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); +GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer; +#define glMapBuffer glad_glMapBuffer +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target); +GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +#define glUnmapBuffer glad_glUnmapBuffer +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void **params); +GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +#define glGetBufferPointerv glad_glGetBufferPointerv +#endif +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +GLAPI int GLAD_GL_VERSION_2_0; +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs); +GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +#define glDrawBuffers glad_glDrawBuffers +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name); +GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); +GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(); +GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); +GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); +GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); +GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params); +GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params); +GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params); +GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params); +GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble *params); +GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +#define glGetVertexAttribdv glad_glGetVertexAttribdv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params); +GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer); +GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); +GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); +GLAPI PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); +GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); +GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); +GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); +GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +#define glVertexAttrib1d glad_glVertexAttrib1d +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +#define glVertexAttrib1dv glad_glVertexAttrib1dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); +GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +#define glVertexAttrib1s glad_glVertexAttrib1s +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +#define glVertexAttrib1sv glad_glVertexAttrib1sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); +GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +#define glVertexAttrib2d glad_glVertexAttrib2d +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +#define glVertexAttrib2dv glad_glVertexAttrib2dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); +GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +#define glVertexAttrib2s glad_glVertexAttrib2s +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +#define glVertexAttrib2sv glad_glVertexAttrib2sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +#define glVertexAttrib3d glad_glVertexAttrib3d +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +#define glVertexAttrib3dv glad_glVertexAttrib3dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +#define glVertexAttrib3s glad_glVertexAttrib3s +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +#define glVertexAttrib3sv glad_glVertexAttrib3sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +#define glVertexAttrib4Niv glad_glVertexAttrib4Niv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +#define glVertexAttrib4Nub glad_glVertexAttrib4Nub +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +#define glVertexAttrib4bv glad_glVertexAttrib4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +#define glVertexAttrib4d glad_glVertexAttrib4d +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +#define glVertexAttrib4dv glad_glVertexAttrib4dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +#define glVertexAttrib4iv glad_glVertexAttrib4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +#define glVertexAttrib4s glad_glVertexAttrib4s +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +#define glVertexAttrib4sv glad_glVertexAttrib4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +#define glVertexAttrib4ubv glad_glVertexAttrib4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +#define glVertexAttrib4uiv glad_glVertexAttrib4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +#define glVertexAttrib4usv glad_glVertexAttrib4usv +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +#endif +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +GLAPI int GLAD_GL_VERSION_2_1; +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv +#endif +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +GLAPI int GLAD_GL_VERSION_3_0; +typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski; +#define glColorMaski glad_glColorMaski +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean *data); +GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +#define glGetBooleani_v glad_glGetBooleani_v +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint *data); +GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +#define glGetIntegeri_v glad_glGetIntegeri_v +typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLENABLEIPROC glad_glEnablei; +#define glEnablei glad_glEnablei +typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLDISABLEIPROC glad_glDisablei; +#define glDisablei glad_glDisablei +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index); +GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi; +#define glIsEnabledi glad_glIsEnabledi +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); +GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +#define glBeginTransformFeedback glad_glBeginTransformFeedback +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(); +GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +#define glEndTransformFeedback glad_glEndTransformFeedback +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +#define glBindBufferRange glad_glBindBufferRange +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); +GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +#define glBindBufferBase glad_glBindBufferBase +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); +GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor; +#define glClampColor glad_glClampColor +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); +GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +#define glBeginConditionalRender glad_glBeginConditionalRender +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(); +GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +#define glEndConditionalRender glad_glEndConditionalRender +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +#define glVertexAttribIPointer glad_glVertexAttribIPointer +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +#define glGetVertexAttribIiv glad_glGetVertexAttribIiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint *params); +GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); +GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +#define glVertexAttribI1i glad_glVertexAttribI1i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); +GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +#define glVertexAttribI2i glad_glVertexAttribI2i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); +GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +#define glVertexAttribI3i glad_glVertexAttribI3i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +#define glVertexAttribI4i glad_glVertexAttribI4i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); +GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +#define glVertexAttribI1ui glad_glVertexAttribI1ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); +GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +#define glVertexAttribI2ui glad_glVertexAttribI2ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +#define glVertexAttribI3ui glad_glVertexAttribI3ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +#define glVertexAttribI4ui glad_glVertexAttribI4ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +#define glVertexAttribI1iv glad_glVertexAttribI1iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +#define glVertexAttribI2iv glad_glVertexAttribI2iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +#define glVertexAttribI3iv glad_glVertexAttribI3iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +#define glVertexAttribI4iv glad_glVertexAttribI4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +#define glVertexAttribI1uiv glad_glVertexAttribI1uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +#define glVertexAttribI2uiv glad_glVertexAttribI2uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +#define glVertexAttribI3uiv glad_glVertexAttribI3uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +#define glVertexAttribI4uiv glad_glVertexAttribI4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +#define glVertexAttribI4bv glad_glVertexAttribI4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +#define glVertexAttribI4sv glad_glVertexAttribI4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +#define glVertexAttribI4ubv glad_glVertexAttribI4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +#define glVertexAttribI4usv glad_glVertexAttribI4usv +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint *params); +GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +#define glGetUniformuiv glad_glGetUniformuiv +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar *name); +GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +#define glBindFragDataLocation glad_glBindFragDataLocation +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +#define glGetFragDataLocation glad_glGetFragDataLocation +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); +GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui; +#define glUniform1ui glad_glUniform1ui +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); +GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui; +#define glUniform2ui glad_glUniform2ui +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui; +#define glUniform3ui glad_glUniform3ui +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui; +#define glUniform4ui glad_glUniform4ui +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +#define glUniform1uiv glad_glUniform1uiv +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +#define glUniform2uiv glad_glUniform2uiv +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +#define glUniform3uiv glad_glUniform3uiv +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +#define glUniform4uiv glad_glUniform4uiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +#define glTexParameterIiv glad_glTexParameterIiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint *params); +GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +#define glTexParameterIuiv glad_glTexParameterIuiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +#define glGetTexParameterIiv glad_glGetTexParameterIiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint *params); +GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +#define glGetTexParameterIuiv glad_glGetTexParameterIuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint *value); +GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +#define glClearBufferiv glad_glClearBufferiv +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint *value); +GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +#define glClearBufferuiv glad_glClearBufferuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat *value); +GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +#define glClearBufferfv glad_glClearBufferfv +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +#define glClearBufferfi glad_glClearBufferfi +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); +GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi; +#define glGetStringi glad_glGetStringi +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers); +GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers); +GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers); +GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); +GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +#define glFramebufferTexture1D glad_glFramebufferTexture1D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +#define glFramebufferTexture3D glad_glFramebufferTexture3D +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); +GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +#define glBlitFramebuffer glad_glBlitFramebuffer +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +#define glFramebufferTextureLayer glad_glFramebufferTextureLayer +typedef void * (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +#define glMapBufferRange glad_glMapBufferRange +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); +GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +#define glFlushMappedBufferRange glad_glFlushMappedBufferRange +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +#define glBindVertexArray glad_glBindVertexArray +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint *arrays); +GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +#define glDeleteVertexArrays glad_glDeleteVertexArrays +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays); +GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +#define glGenVertexArrays glad_glGenVertexArrays +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +#define glIsVertexArray glad_glIsVertexArray +#endif +#ifndef GL_VERSION_3_1 +#define GL_VERSION_3_1 1 +GLAPI int GLAD_GL_VERSION_3_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; +#define glDrawArraysInstanced glad_glDrawArraysInstanced +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; +#define glDrawElementsInstanced glad_glDrawElementsInstanced +typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); +GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer; +#define glTexBuffer glad_glTexBuffer +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); +GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; +#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; +#define glCopyBufferSubData glad_glCopyBufferSubData +typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; +#define glGetUniformIndices glad_glGetUniformIndices +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; +#define glGetActiveUniformsiv glad_glGetActiveUniformsiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; +#define glGetActiveUniformName glad_glGetActiveUniformName +typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar *uniformBlockName); +GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; +#define glGetUniformBlockIndex glad_glGetUniformBlockIndex +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; +#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; +#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName +typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; +#define glUniformBlockBinding glad_glUniformBlockBinding +#endif +#ifndef GL_VERSION_3_2 +#define GL_VERSION_3_2 1 +GLAPI int GLAD_GL_VERSION_3_2; +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; +#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; +#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); +GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; +#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); +GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; +#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode); +GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; +#define glProvokingVertex glad_glProvokingVertex +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); +GLAPI PFNGLFENCESYNCPROC glad_glFenceSync; +#define glFenceSync glad_glFenceSync +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync); +GLAPI PFNGLISSYNCPROC glad_glIsSync; +#define glIsSync glad_glIsSync +typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); +GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync; +#define glDeleteSync glad_glDeleteSync +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +#define glClientWaitSync glad_glClientWaitSync +typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLWAITSYNCPROC glad_glWaitSync; +#define glWaitSync glad_glWaitSync +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 *data); +GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +#define glGetInteger64v glad_glGetInteger64v +typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv; +#define glGetSynciv glad_glGetSynciv +typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 *data); +GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; +#define glGetInteger64i_v glad_glGetInteger64i_v +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 *params); +GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; +#define glGetBufferParameteri64v glad_glGetBufferParameteri64v +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; +#define glFramebufferTexture glad_glFramebufferTexture +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +#define glTexImage2DMultisample glad_glTexImage2DMultisample +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +#define glTexImage3DMultisample glad_glTexImage3DMultisample +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat *val); +GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +#define glGetMultisamplefv glad_glGetMultisamplefv +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); +GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +#define glSampleMaski glad_glSampleMaski +#endif +#define GL_MULTISAMPLE_ARB 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F +#define GL_SAMPLE_COVERAGE_ARB 0x80A0 +#define GL_SAMPLE_BUFFERS_ARB 0x80A8 +#define GL_SAMPLES_ARB 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB +#define GL_MULTISAMPLE_BIT_ARB 0x20000000 +#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 +#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245 +#define GL_DEBUG_SOURCE_API_KHR 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A +#define GL_DEBUG_SOURCE_OTHER_KHR 0x824B +#define GL_DEBUG_TYPE_ERROR_KHR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250 +#define GL_DEBUG_TYPE_OTHER_KHR 0x8251 +#define GL_DEBUG_TYPE_MARKER_KHR 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D +#define GL_BUFFER_KHR 0x82E0 +#define GL_SHADER_KHR 0x82E1 +#define GL_PROGRAM_KHR 0x82E2 +#define GL_VERTEX_ARRAY_KHR 0x8074 +#define GL_QUERY_KHR 0x82E3 +#define GL_PROGRAM_PIPELINE_KHR 0x82E4 +#define GL_SAMPLER_KHR 0x82E6 +#define GL_MAX_LABEL_LENGTH_KHR 0x82E8 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_KHR 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147 +#define GL_DEBUG_SEVERITY_LOW_KHR 0x9148 +#define GL_DEBUG_OUTPUT_KHR 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 +#define GL_STACK_OVERFLOW_KHR 0x0503 +#define GL_STACK_UNDERFLOW_KHR 0x0504 +#define GL_DISPLAY_LIST 0x82E7 +#ifndef GL_ARB_multisample +#define GL_ARB_multisample 1 +GLAPI int GLAD_GL_ARB_multisample; +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC)(GLfloat value, GLboolean invert); +GLAPI PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB; +#define glSampleCoverageARB glad_glSampleCoverageARB +#endif +#ifndef GL_ARB_robustness +#define GL_ARB_robustness 1 +GLAPI int GLAD_GL_ARB_robustness; +typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC)(); +GLAPI PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB; +#define glGetGraphicsResetStatusARB glad_glGetGraphicsResetStatusARB +typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC)(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); +GLAPI PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB; +#define glGetnTexImageARB glad_glGetnTexImageARB +typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +GLAPI PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB; +#define glReadnPixelsARB glad_glReadnPixelsARB +typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC)(GLenum target, GLint lod, GLsizei bufSize, void *img); +GLAPI PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB; +#define glGetnCompressedTexImageARB glad_glGetnCompressedTexImageARB +typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +GLAPI PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB; +#define glGetnUniformfvARB glad_glGetnUniformfvARB +typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLint *params); +GLAPI PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB; +#define glGetnUniformivARB glad_glGetnUniformivARB +typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint *params); +GLAPI PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB; +#define glGetnUniformuivARB glad_glGetnUniformuivARB +typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +GLAPI PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB; +#define glGetnUniformdvARB glad_glGetnUniformdvARB +typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); +GLAPI PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB; +#define glGetnMapdvARB glad_glGetnMapdvARB +typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); +GLAPI PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB; +#define glGetnMapfvARB glad_glGetnMapfvARB +typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLint *v); +GLAPI PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB; +#define glGetnMapivARB glad_glGetnMapivARB +typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC)(GLenum map, GLsizei bufSize, GLfloat *values); +GLAPI PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB; +#define glGetnPixelMapfvARB glad_glGetnPixelMapfvARB +typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC)(GLenum map, GLsizei bufSize, GLuint *values); +GLAPI PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB; +#define glGetnPixelMapuivARB glad_glGetnPixelMapuivARB +typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC)(GLenum map, GLsizei bufSize, GLushort *values); +GLAPI PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB; +#define glGetnPixelMapusvARB glad_glGetnPixelMapusvARB +typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC)(GLsizei bufSize, GLubyte *pattern); +GLAPI PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB; +#define glGetnPolygonStippleARB glad_glGetnPolygonStippleARB +typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); +GLAPI PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB; +#define glGetnColorTableARB glad_glGetnColorTableARB +typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); +GLAPI PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB; +#define glGetnConvolutionFilterARB glad_glGetnConvolutionFilterARB +typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); +GLAPI PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB; +#define glGetnSeparableFilterARB glad_glGetnSeparableFilterARB +typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +GLAPI PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB; +#define glGetnHistogramARB glad_glGetnHistogramARB +typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +GLAPI PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB; +#define glGetnMinmaxARB glad_glGetnMinmaxARB +#endif +#ifndef GL_KHR_debug +#define GL_KHR_debug 1 +GLAPI int GLAD_GL_KHR_debug; +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl; +#define glDebugMessageControl glad_glDebugMessageControl +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert; +#define glDebugMessageInsert glad_glDebugMessageInsert +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void *userParam); +GLAPI PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback; +#define glDebugMessageCallback glad_glDebugMessageCallback +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog; +#define glGetDebugMessageLog glad_glGetDebugMessageLog +typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message); +GLAPI PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup; +#define glPushDebugGroup glad_glPushDebugGroup +typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC)(); +GLAPI PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup; +#define glPopDebugGroup glad_glPopDebugGroup +typedef void (APIENTRYP PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +GLAPI PFNGLOBJECTLABELPROC glad_glObjectLabel; +#define glObjectLabel glad_glObjectLabel +typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel; +#define glGetObjectLabel glad_glGetObjectLabel +typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC)(const void *ptr, GLsizei length, const GLchar *label); +GLAPI PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel; +#define glObjectPtrLabel glad_glObjectPtrLabel +typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel; +#define glGetObjectPtrLabel glad_glGetObjectPtrLabel +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLKHRPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR; +#define glDebugMessageControlKHR glad_glDebugMessageControlKHR +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTKHRPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR; +#define glDebugMessageInsertKHR glad_glDebugMessageInsertKHR +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKKHRPROC)(GLDEBUGPROCKHR callback, const void *userParam); +GLAPI PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR; +#define glDebugMessageCallbackKHR glad_glDebugMessageCallbackKHR +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGKHRPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR; +#define glGetDebugMessageLogKHR glad_glGetDebugMessageLogKHR +typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPKHRPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message); +GLAPI PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR; +#define glPushDebugGroupKHR glad_glPushDebugGroupKHR +typedef void (APIENTRYP PFNGLPOPDEBUGGROUPKHRPROC)(); +GLAPI PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR; +#define glPopDebugGroupKHR glad_glPopDebugGroupKHR +typedef void (APIENTRYP PFNGLOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +GLAPI PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR; +#define glObjectLabelKHR glad_glObjectLabelKHR +typedef void (APIENTRYP PFNGLGETOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR; +#define glGetObjectLabelKHR glad_glGetObjectLabelKHR +typedef void (APIENTRYP PFNGLOBJECTPTRLABELKHRPROC)(const void *ptr, GLsizei length, const GLchar *label); +GLAPI PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR; +#define glObjectPtrLabelKHR glad_glObjectPtrLabelKHR +typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELKHRPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR; +#define glGetObjectPtrLabelKHR glad_glGetObjectPtrLabelKHR +typedef void (APIENTRYP PFNGLGETPOINTERVKHRPROC)(GLenum pname, void **params); +GLAPI PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR; +#define glGetPointervKHR glad_glGetPointervKHR +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/glfw/deps/linmath.h b/src/external/glfw/deps/linmath.h new file mode 100644 index 00000000..9c2e2a0a --- /dev/null +++ b/src/external/glfw/deps/linmath.h @@ -0,0 +1,574 @@ +#ifndef LINMATH_H +#define LINMATH_H + +#include + +#ifdef _MSC_VER +#define inline __inline +#endif + +#define LINMATH_H_DEFINE_VEC(n) \ +typedef float vec##n[n]; \ +static inline void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \ +{ \ + int i; \ + for(i=0; i 1e-4) { + mat4x4 T, C, S = {{0}}; + + vec3_norm(u, u); + mat4x4_from_vec3_mul_outer(T, u, u); + + S[1][2] = u[0]; + S[2][1] = -u[0]; + S[2][0] = u[1]; + S[0][2] = -u[1]; + S[0][1] = u[2]; + S[1][0] = -u[2]; + + mat4x4_scale(S, S, s); + + mat4x4_identity(C); + mat4x4_sub(C, C, T); + + mat4x4_scale(C, C, c); + + mat4x4_add(T, T, C); + mat4x4_add(T, T, S); + + T[3][3] = 1.; + mat4x4_mul(R, M, T); + } else { + mat4x4_dup(R, M); + } +} +static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle) +{ + float s = sinf(angle); + float c = cosf(angle); + mat4x4 R = { + {1.f, 0.f, 0.f, 0.f}, + {0.f, c, s, 0.f}, + {0.f, -s, c, 0.f}, + {0.f, 0.f, 0.f, 1.f} + }; + mat4x4_mul(Q, M, R); +} +static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle) +{ + float s = sinf(angle); + float c = cosf(angle); + mat4x4 R = { + { c, 0.f, s, 0.f}, + { 0.f, 1.f, 0.f, 0.f}, + { -s, 0.f, c, 0.f}, + { 0.f, 0.f, 0.f, 1.f} + }; + mat4x4_mul(Q, M, R); +} +static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle) +{ + float s = sinf(angle); + float c = cosf(angle); + mat4x4 R = { + { c, s, 0.f, 0.f}, + { -s, c, 0.f, 0.f}, + { 0.f, 0.f, 1.f, 0.f}, + { 0.f, 0.f, 0.f, 1.f} + }; + mat4x4_mul(Q, M, R); +} +static inline void mat4x4_invert(mat4x4 T, mat4x4 M) +{ + float idet; + float s[6]; + float c[6]; + s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1]; + s[1] = M[0][0]*M[1][2] - M[1][0]*M[0][2]; + s[2] = M[0][0]*M[1][3] - M[1][0]*M[0][3]; + s[3] = M[0][1]*M[1][2] - M[1][1]*M[0][2]; + s[4] = M[0][1]*M[1][3] - M[1][1]*M[0][3]; + s[5] = M[0][2]*M[1][3] - M[1][2]*M[0][3]; + + c[0] = M[2][0]*M[3][1] - M[3][0]*M[2][1]; + c[1] = M[2][0]*M[3][2] - M[3][0]*M[2][2]; + c[2] = M[2][0]*M[3][3] - M[3][0]*M[2][3]; + c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2]; + c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3]; + c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3]; + + /* Assumes it is invertible */ + idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] ); + + T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet; + T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet; + T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet; + T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet; + + T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet; + T[1][1] = ( M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet; + T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet; + T[1][3] = ( M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet; + + T[2][0] = ( M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet; + T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet; + T[2][2] = ( M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet; + T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet; + + T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet; + T[3][1] = ( M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet; + T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet; + T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet; +} +static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M) +{ + float s = 1.; + vec3 h; + + mat4x4_dup(R, M); + vec3_norm(R[2], R[2]); + + s = vec3_mul_inner(R[1], R[2]); + vec3_scale(h, R[2], s); + vec3_sub(R[1], R[1], h); + vec3_norm(R[2], R[2]); + + s = vec3_mul_inner(R[1], R[2]); + vec3_scale(h, R[2], s); + vec3_sub(R[1], R[1], h); + vec3_norm(R[1], R[1]); + + s = vec3_mul_inner(R[0], R[1]); + vec3_scale(h, R[1], s); + vec3_sub(R[0], R[0], h); + vec3_norm(R[0], R[0]); +} + +static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f) +{ + M[0][0] = 2.f*n/(r-l); + M[0][1] = M[0][2] = M[0][3] = 0.f; + + M[1][1] = 2.f*n/(t-b); + M[1][0] = M[1][2] = M[1][3] = 0.f; + + M[2][0] = (r+l)/(r-l); + M[2][1] = (t+b)/(t-b); + M[2][2] = -(f+n)/(f-n); + M[2][3] = -1.f; + + M[3][2] = -2.f*(f*n)/(f-n); + M[3][0] = M[3][1] = M[3][3] = 0.f; +} +static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f) +{ + M[0][0] = 2.f/(r-l); + M[0][1] = M[0][2] = M[0][3] = 0.f; + + M[1][1] = 2.f/(t-b); + M[1][0] = M[1][2] = M[1][3] = 0.f; + + M[2][2] = -2.f/(f-n); + M[2][0] = M[2][1] = M[2][3] = 0.f; + + M[3][0] = -(r+l)/(r-l); + M[3][1] = -(t+b)/(t-b); + M[3][2] = -(f+n)/(f-n); + M[3][3] = 1.f; +} +static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f) +{ + /* NOTE: Degrees are an unhandy unit to work with. + * linmath.h uses radians for everything! */ + float const a = 1.f / (float) tan(y_fov / 2.f); + + m[0][0] = a / aspect; + m[0][1] = 0.f; + m[0][2] = 0.f; + m[0][3] = 0.f; + + m[1][0] = 0.f; + m[1][1] = a; + m[1][2] = 0.f; + m[1][3] = 0.f; + + m[2][0] = 0.f; + m[2][1] = 0.f; + m[2][2] = -((f + n) / (f - n)); + m[2][3] = -1.f; + + m[3][0] = 0.f; + m[3][1] = 0.f; + m[3][2] = -((2.f * f * n) / (f - n)); + m[3][3] = 0.f; +} +static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up) +{ + /* Adapted from Android's OpenGL Matrix.java. */ + /* See the OpenGL GLUT documentation for gluLookAt for a description */ + /* of the algorithm. We implement it in a straightforward way: */ + + /* TODO: The negation of of can be spared by swapping the order of + * operands in the following cross products in the right way. */ + vec3 f; + vec3 s; + vec3 t; + + vec3_sub(f, center, eye); + vec3_norm(f, f); + + vec3_mul_cross(s, f, up); + vec3_norm(s, s); + + vec3_mul_cross(t, s, f); + + m[0][0] = s[0]; + m[0][1] = t[0]; + m[0][2] = -f[0]; + m[0][3] = 0.f; + + m[1][0] = s[1]; + m[1][1] = t[1]; + m[1][2] = -f[1]; + m[1][3] = 0.f; + + m[2][0] = s[2]; + m[2][1] = t[2]; + m[2][2] = -f[2]; + m[2][3] = 0.f; + + m[3][0] = 0.f; + m[3][1] = 0.f; + m[3][2] = 0.f; + m[3][3] = 1.f; + + mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]); +} + +typedef float quat[4]; +static inline void quat_identity(quat q) +{ + q[0] = q[1] = q[2] = 0.f; + q[3] = 1.f; +} +static inline void quat_add(quat r, quat a, quat b) +{ + int i; + for(i=0; i<4; ++i) + r[i] = a[i] + b[i]; +} +static inline void quat_sub(quat r, quat a, quat b) +{ + int i; + for(i=0; i<4; ++i) + r[i] = a[i] - b[i]; +} +static inline void quat_mul(quat r, quat p, quat q) +{ + vec3 w; + vec3_mul_cross(r, p, q); + vec3_scale(w, p, q[3]); + vec3_add(r, r, w); + vec3_scale(w, q, p[3]); + vec3_add(r, r, w); + r[3] = p[3]*q[3] - vec3_mul_inner(p, q); +} +static inline void quat_scale(quat r, quat v, float s) +{ + int i; + for(i=0; i<4; ++i) + r[i] = v[i] * s; +} +static inline float quat_inner_product(quat a, quat b) +{ + float p = 0.f; + int i; + for(i=0; i<4; ++i) + p += b[i]*a[i]; + return p; +} +static inline void quat_conj(quat r, quat q) +{ + int i; + for(i=0; i<3; ++i) + r[i] = -q[i]; + r[3] = q[3]; +} +static inline void quat_rotate(quat r, float angle, vec3 axis) { + int i; + vec3 v; + vec3_scale(v, axis, sinf(angle / 2)); + for(i=0; i<3; ++i) + r[i] = v[i]; + r[3] = cosf(angle / 2); +} +#define quat_norm vec4_norm +static inline void quat_mul_vec3(vec3 r, quat q, vec3 v) +{ +/* + * Method by Fabian 'ryg' Giessen (of Farbrausch) +t = 2 * cross(q.xyz, v) +v' = v + q.w * t + cross(q.xyz, t) + */ + vec3 t = {q[0], q[1], q[2]}; + vec3 u = {q[0], q[1], q[2]}; + + vec3_mul_cross(t, t, v); + vec3_scale(t, t, 2); + + vec3_mul_cross(u, u, t); + vec3_scale(t, t, q[3]); + + vec3_add(r, v, t); + vec3_add(r, r, u); +} +static inline void mat4x4_from_quat(mat4x4 M, quat q) +{ + float a = q[3]; + float b = q[0]; + float c = q[1]; + float d = q[2]; + float a2 = a*a; + float b2 = b*b; + float c2 = c*c; + float d2 = d*d; + + M[0][0] = a2 + b2 - c2 - d2; + M[0][1] = 2.f*(b*c + a*d); + M[0][2] = 2.f*(b*d - a*c); + M[0][3] = 0.f; + + M[1][0] = 2*(b*c - a*d); + M[1][1] = a2 - b2 + c2 - d2; + M[1][2] = 2.f*(c*d + a*b); + M[1][3] = 0.f; + + M[2][0] = 2.f*(b*d + a*c); + M[2][1] = 2.f*(c*d - a*b); + M[2][2] = a2 - b2 - c2 + d2; + M[2][3] = 0.f; + + M[3][0] = M[3][1] = M[3][2] = 0.f; + M[3][3] = 1.f; +} + +static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q) +{ +/* XXX: The way this is written only works for othogonal matrices. */ +/* TODO: Take care of non-orthogonal case. */ + quat_mul_vec3(R[0], q, M[0]); + quat_mul_vec3(R[1], q, M[1]); + quat_mul_vec3(R[2], q, M[2]); + + R[3][0] = R[3][1] = R[3][2] = 0.f; + R[3][3] = 1.f; +} +static inline void quat_from_mat4x4(quat q, mat4x4 M) +{ + float r=0.f; + int i; + + int perm[] = { 0, 1, 2, 0, 1 }; + int *p = perm; + + for(i = 0; i<3; i++) { + float m = M[i][i]; + if( m < r ) + continue; + m = r; + p = &perm[i]; + } + + r = (float) sqrt(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] ); + + if(r < 1e-6) { + q[0] = 1.f; + q[1] = q[2] = q[3] = 0.f; + return; + } + + q[0] = r/2.f; + q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]])/(2.f*r); + q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]])/(2.f*r); + q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r); +} + +#endif diff --git a/src/external/glfw/deps/mingw/_mingw_dxhelper.h b/src/external/glfw/deps/mingw/_mingw_dxhelper.h new file mode 100644 index 00000000..849e2914 --- /dev/null +++ b/src/external/glfw/deps/mingw/_mingw_dxhelper.h @@ -0,0 +1,117 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#if defined(_MSC_VER) && !defined(_MSC_EXTENSIONS) +#define NONAMELESSUNION 1 +#endif +#if defined(NONAMELESSSTRUCT) && \ + !defined(NONAMELESSUNION) +#define NONAMELESSUNION 1 +#endif +#if defined(NONAMELESSUNION) && \ + !defined(NONAMELESSSTRUCT) +#define NONAMELESSSTRUCT 1 +#endif +#if !defined(__GNU_EXTENSION) +#if defined(__GNUC__) || defined(__GNUG__) +#define __GNU_EXTENSION __extension__ +#else +#define __GNU_EXTENSION +#endif +#endif /* __extension__ */ + +#ifndef __ANONYMOUS_DEFINED +#define __ANONYMOUS_DEFINED +#if defined(__GNUC__) || defined(__GNUG__) +#define _ANONYMOUS_UNION __extension__ +#define _ANONYMOUS_STRUCT __extension__ +#else +#define _ANONYMOUS_UNION +#define _ANONYMOUS_STRUCT +#endif +#ifndef NONAMELESSUNION +#define _UNION_NAME(x) +#define _STRUCT_NAME(x) +#else /* NONAMELESSUNION */ +#define _UNION_NAME(x) x +#define _STRUCT_NAME(x) x +#endif +#endif /* __ANONYMOUS_DEFINED */ + +#ifndef DUMMYUNIONNAME +# ifdef NONAMELESSUNION +# define DUMMYUNIONNAME u +# define DUMMYUNIONNAME1 u1 /* Wine uses this variant */ +# define DUMMYUNIONNAME2 u2 +# define DUMMYUNIONNAME3 u3 +# define DUMMYUNIONNAME4 u4 +# define DUMMYUNIONNAME5 u5 +# define DUMMYUNIONNAME6 u6 +# define DUMMYUNIONNAME7 u7 +# define DUMMYUNIONNAME8 u8 +# define DUMMYUNIONNAME9 u9 +# else /* NONAMELESSUNION */ +# define DUMMYUNIONNAME +# define DUMMYUNIONNAME1 /* Wine uses this variant */ +# define DUMMYUNIONNAME2 +# define DUMMYUNIONNAME3 +# define DUMMYUNIONNAME4 +# define DUMMYUNIONNAME5 +# define DUMMYUNIONNAME6 +# define DUMMYUNIONNAME7 +# define DUMMYUNIONNAME8 +# define DUMMYUNIONNAME9 +# endif +#endif /* DUMMYUNIONNAME */ + +#if !defined(DUMMYUNIONNAME1) /* MinGW does not define this one */ +# ifdef NONAMELESSUNION +# define DUMMYUNIONNAME1 u1 /* Wine uses this variant */ +# else +# define DUMMYUNIONNAME1 /* Wine uses this variant */ +# endif +#endif /* DUMMYUNIONNAME1 */ + +#ifndef DUMMYSTRUCTNAME +# ifdef NONAMELESSUNION +# define DUMMYSTRUCTNAME s +# define DUMMYSTRUCTNAME1 s1 /* Wine uses this variant */ +# define DUMMYSTRUCTNAME2 s2 +# define DUMMYSTRUCTNAME3 s3 +# define DUMMYSTRUCTNAME4 s4 +# define DUMMYSTRUCTNAME5 s5 +# else +# define DUMMYSTRUCTNAME +# define DUMMYSTRUCTNAME1 /* Wine uses this variant */ +# define DUMMYSTRUCTNAME2 +# define DUMMYSTRUCTNAME3 +# define DUMMYSTRUCTNAME4 +# define DUMMYSTRUCTNAME5 +# endif +#endif /* DUMMYSTRUCTNAME */ + +/* These are for compatibility with the Wine source tree */ + +#ifndef WINELIB_NAME_AW +# ifdef __MINGW_NAME_AW +# define WINELIB_NAME_AW __MINGW_NAME_AW +# else +# ifdef UNICODE +# define WINELIB_NAME_AW(func) func##W +# else +# define WINELIB_NAME_AW(func) func##A +# endif +# endif +#endif /* WINELIB_NAME_AW */ + +#ifndef DECL_WINELIB_TYPE_AW +# ifdef __MINGW_TYPEDEF_AW +# define DECL_WINELIB_TYPE_AW __MINGW_TYPEDEF_AW +# else +# define DECL_WINELIB_TYPE_AW(type) typedef WINELIB_NAME_AW(type) type; +# endif +#endif /* DECL_WINELIB_TYPE_AW */ + diff --git a/src/external/glfw/deps/mingw/dinput.h b/src/external/glfw/deps/mingw/dinput.h new file mode 100644 index 00000000..b5754802 --- /dev/null +++ b/src/external/glfw/deps/mingw/dinput.h @@ -0,0 +1,2467 @@ +/* + * Copyright (C) the Wine project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __DINPUT_INCLUDED__ +#define __DINPUT_INCLUDED__ + +#define COM_NO_WINDOWS_H +#include +#include <_mingw_dxhelper.h> + +#ifndef DIRECTINPUT_VERSION +#define DIRECTINPUT_VERSION 0x0800 +#endif + +/* Classes */ +DEFINE_GUID(CLSID_DirectInput, 0x25E609E0,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(CLSID_DirectInputDevice, 0x25E609E1,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +DEFINE_GUID(CLSID_DirectInput8, 0x25E609E4,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(CLSID_DirectInputDevice8, 0x25E609E5,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/* Interfaces */ +DEFINE_GUID(IID_IDirectInputA, 0x89521360,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputW, 0x89521361,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInput2A, 0x5944E662,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInput2W, 0x5944E663,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInput7A, 0x9A4CB684,0x236D,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInput7W, 0x9A4CB685,0x236D,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInput8A, 0xBF798030,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00); +DEFINE_GUID(IID_IDirectInput8W, 0xBF798031,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00); +DEFINE_GUID(IID_IDirectInputDeviceA, 0x5944E680,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDeviceW, 0x5944E681,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDevice2A, 0x5944E682,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDevice2W, 0x5944E683,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDevice7A, 0x57D7C6BC,0x2356,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInputDevice7W, 0x57D7C6BD,0x2356,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE); +DEFINE_GUID(IID_IDirectInputDevice8A, 0x54D41080,0xDC15,0x4833,0xA4,0x1B,0x74,0x8F,0x73,0xA3,0x81,0x79); +DEFINE_GUID(IID_IDirectInputDevice8W, 0x54D41081,0xDC15,0x4833,0xA4,0x1B,0x74,0x8F,0x73,0xA3,0x81,0x79); +DEFINE_GUID(IID_IDirectInputEffect, 0xE7E1F7C0,0x88D2,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); + +/* Predefined object types */ +DEFINE_GUID(GUID_XAxis, 0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_YAxis, 0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_ZAxis, 0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RxAxis,0xA36D02F4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RyAxis,0xA36D02F5,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RzAxis,0xA36D02E3,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Slider,0xA36D02E4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Button,0xA36D02F0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Key, 0x55728220,0xD33C,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_POV, 0xA36D02F2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Unknown,0xA36D02F3,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/* Predefined product GUIDs */ +DEFINE_GUID(GUID_SysMouse, 0x6F1D2B60,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysKeyboard, 0x6F1D2B61,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Joystick, 0x6F1D2B70,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysMouseEm, 0x6F1D2B80,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysMouseEm2, 0x6F1D2B81,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysKeyboardEm, 0x6F1D2B82,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysKeyboardEm2,0x6F1D2B83,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/* predefined forcefeedback effects */ +DEFINE_GUID(GUID_ConstantForce, 0x13541C20,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_RampForce, 0x13541C21,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Square, 0x13541C22,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Sine, 0x13541C23,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Triangle, 0x13541C24,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_SawtoothUp, 0x13541C25,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_SawtoothDown, 0x13541C26,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Spring, 0x13541C27,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Damper, 0x13541C28,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Inertia, 0x13541C29,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Friction, 0x13541C2A,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_CustomForce, 0x13541C2B,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); + +typedef struct IDirectInputA *LPDIRECTINPUTA; +typedef struct IDirectInputW *LPDIRECTINPUTW; +typedef struct IDirectInput2A *LPDIRECTINPUT2A; +typedef struct IDirectInput2W *LPDIRECTINPUT2W; +typedef struct IDirectInput7A *LPDIRECTINPUT7A; +typedef struct IDirectInput7W *LPDIRECTINPUT7W; +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct IDirectInput8A *LPDIRECTINPUT8A; +typedef struct IDirectInput8W *LPDIRECTINPUT8W; +#endif /* DI8 */ +typedef struct IDirectInputDeviceA *LPDIRECTINPUTDEVICEA; +typedef struct IDirectInputDeviceW *LPDIRECTINPUTDEVICEW; +#if DIRECTINPUT_VERSION >= 0x0500 +typedef struct IDirectInputDevice2A *LPDIRECTINPUTDEVICE2A; +typedef struct IDirectInputDevice2W *LPDIRECTINPUTDEVICE2W; +#endif /* DI5 */ +#if DIRECTINPUT_VERSION >= 0x0700 +typedef struct IDirectInputDevice7A *LPDIRECTINPUTDEVICE7A; +typedef struct IDirectInputDevice7W *LPDIRECTINPUTDEVICE7W; +#endif /* DI7 */ +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct IDirectInputDevice8A *LPDIRECTINPUTDEVICE8A; +typedef struct IDirectInputDevice8W *LPDIRECTINPUTDEVICE8W; +#endif /* DI8 */ +#if DIRECTINPUT_VERSION >= 0x0500 +typedef struct IDirectInputEffect *LPDIRECTINPUTEFFECT; +#endif /* DI5 */ +typedef struct SysKeyboardA *LPSYSKEYBOARDA; +typedef struct SysMouseA *LPSYSMOUSEA; + +#define IID_IDirectInput WINELIB_NAME_AW(IID_IDirectInput) +#define IDirectInput WINELIB_NAME_AW(IDirectInput) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT) +#define IID_IDirectInput2 WINELIB_NAME_AW(IID_IDirectInput2) +#define IDirectInput2 WINELIB_NAME_AW(IDirectInput2) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT2) +#define IID_IDirectInput7 WINELIB_NAME_AW(IID_IDirectInput7) +#define IDirectInput7 WINELIB_NAME_AW(IDirectInput7) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT7) +#if DIRECTINPUT_VERSION >= 0x0800 +#define IID_IDirectInput8 WINELIB_NAME_AW(IID_IDirectInput8) +#define IDirectInput8 WINELIB_NAME_AW(IDirectInput8) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUT8) +#endif /* DI8 */ +#define IID_IDirectInputDevice WINELIB_NAME_AW(IID_IDirectInputDevice) +#define IDirectInputDevice WINELIB_NAME_AW(IDirectInputDevice) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE) +#if DIRECTINPUT_VERSION >= 0x0500 +#define IID_IDirectInputDevice2 WINELIB_NAME_AW(IID_IDirectInputDevice2) +#define IDirectInputDevice2 WINELIB_NAME_AW(IDirectInputDevice2) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE2) +#endif /* DI5 */ +#if DIRECTINPUT_VERSION >= 0x0700 +#define IID_IDirectInputDevice7 WINELIB_NAME_AW(IID_IDirectInputDevice7) +#define IDirectInputDevice7 WINELIB_NAME_AW(IDirectInputDevice7) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE7) +#endif /* DI7 */ +#if DIRECTINPUT_VERSION >= 0x0800 +#define IID_IDirectInputDevice8 WINELIB_NAME_AW(IID_IDirectInputDevice8) +#define IDirectInputDevice8 WINELIB_NAME_AW(IDirectInputDevice8) +DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE8) +#endif /* DI8 */ + +#define DI_OK S_OK +#define DI_NOTATTACHED S_FALSE +#define DI_BUFFEROVERFLOW S_FALSE +#define DI_PROPNOEFFECT S_FALSE +#define DI_NOEFFECT S_FALSE +#define DI_POLLEDDEVICE ((HRESULT)0x00000002L) +#define DI_DOWNLOADSKIPPED ((HRESULT)0x00000003L) +#define DI_EFFECTRESTARTED ((HRESULT)0x00000004L) +#define DI_TRUNCATED ((HRESULT)0x00000008L) +#define DI_SETTINGSNOTSAVED ((HRESULT)0x0000000BL) +#define DI_TRUNCATEDANDRESTARTED ((HRESULT)0x0000000CL) +#define DI_WRITEPROTECT ((HRESULT)0x00000013L) + +#define DIERR_OLDDIRECTINPUTVERSION \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_OLD_WIN_VERSION) +#define DIERR_BETADIRECTINPUTVERSION \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_RMODE_APP) +#define DIERR_BADDRIVERVER \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BAD_DRIVER_LEVEL) +#define DIERR_DEVICENOTREG REGDB_E_CLASSNOTREG +#define DIERR_NOTFOUND \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND) +#define DIERR_OBJECTNOTFOUND \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND) +#define DIERR_INVALIDPARAM E_INVALIDARG +#define DIERR_NOINTERFACE E_NOINTERFACE +#define DIERR_GENERIC E_FAIL +#define DIERR_OUTOFMEMORY E_OUTOFMEMORY +#define DIERR_UNSUPPORTED E_NOTIMPL +#define DIERR_NOTINITIALIZED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_READY) +#define DIERR_ALREADYINITIALIZED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_ALREADY_INITIALIZED) +#define DIERR_NOAGGREGATION CLASS_E_NOAGGREGATION +#define DIERR_OTHERAPPHASPRIO E_ACCESSDENIED +#define DIERR_INPUTLOST \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_READ_FAULT) +#define DIERR_ACQUIRED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BUSY) +#define DIERR_NOTACQUIRED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_ACCESS) +#define DIERR_READONLY E_ACCESSDENIED +#define DIERR_HANDLEEXISTS E_ACCESSDENIED +#ifndef E_PENDING +#define E_PENDING 0x8000000AL +#endif +#define DIERR_INSUFFICIENTPRIVS 0x80040200L +#define DIERR_DEVICEFULL 0x80040201L +#define DIERR_MOREDATA 0x80040202L +#define DIERR_NOTDOWNLOADED 0x80040203L +#define DIERR_HASEFFECTS 0x80040204L +#define DIERR_NOTEXCLUSIVEACQUIRED 0x80040205L +#define DIERR_INCOMPLETEEFFECT 0x80040206L +#define DIERR_NOTBUFFERED 0x80040207L +#define DIERR_EFFECTPLAYING 0x80040208L +#define DIERR_UNPLUGGED 0x80040209L +#define DIERR_REPORTFULL 0x8004020AL +#define DIERR_MAPFILEFAIL 0x8004020BL + +#define DIENUM_STOP 0 +#define DIENUM_CONTINUE 1 + +#define DIEDFL_ALLDEVICES 0x00000000 +#define DIEDFL_ATTACHEDONLY 0x00000001 +#define DIEDFL_FORCEFEEDBACK 0x00000100 +#define DIEDFL_INCLUDEALIASES 0x00010000 +#define DIEDFL_INCLUDEPHANTOMS 0x00020000 +#define DIEDFL_INCLUDEHIDDEN 0x00040000 + +#define DIDEVTYPE_DEVICE 1 +#define DIDEVTYPE_MOUSE 2 +#define DIDEVTYPE_KEYBOARD 3 +#define DIDEVTYPE_JOYSTICK 4 +#define DIDEVTYPE_HID 0x00010000 + +#define DI8DEVCLASS_ALL 0 +#define DI8DEVCLASS_DEVICE 1 +#define DI8DEVCLASS_POINTER 2 +#define DI8DEVCLASS_KEYBOARD 3 +#define DI8DEVCLASS_GAMECTRL 4 + +#define DI8DEVTYPE_DEVICE 0x11 +#define DI8DEVTYPE_MOUSE 0x12 +#define DI8DEVTYPE_KEYBOARD 0x13 +#define DI8DEVTYPE_JOYSTICK 0x14 +#define DI8DEVTYPE_GAMEPAD 0x15 +#define DI8DEVTYPE_DRIVING 0x16 +#define DI8DEVTYPE_FLIGHT 0x17 +#define DI8DEVTYPE_1STPERSON 0x18 +#define DI8DEVTYPE_DEVICECTRL 0x19 +#define DI8DEVTYPE_SCREENPOINTER 0x1A +#define DI8DEVTYPE_REMOTE 0x1B +#define DI8DEVTYPE_SUPPLEMENTAL 0x1C + +#define DIDEVTYPEMOUSE_UNKNOWN 1 +#define DIDEVTYPEMOUSE_TRADITIONAL 2 +#define DIDEVTYPEMOUSE_FINGERSTICK 3 +#define DIDEVTYPEMOUSE_TOUCHPAD 4 +#define DIDEVTYPEMOUSE_TRACKBALL 5 + +#define DIDEVTYPEKEYBOARD_UNKNOWN 0 +#define DIDEVTYPEKEYBOARD_PCXT 1 +#define DIDEVTYPEKEYBOARD_OLIVETTI 2 +#define DIDEVTYPEKEYBOARD_PCAT 3 +#define DIDEVTYPEKEYBOARD_PCENH 4 +#define DIDEVTYPEKEYBOARD_NOKIA1050 5 +#define DIDEVTYPEKEYBOARD_NOKIA9140 6 +#define DIDEVTYPEKEYBOARD_NEC98 7 +#define DIDEVTYPEKEYBOARD_NEC98LAPTOP 8 +#define DIDEVTYPEKEYBOARD_NEC98106 9 +#define DIDEVTYPEKEYBOARD_JAPAN106 10 +#define DIDEVTYPEKEYBOARD_JAPANAX 11 +#define DIDEVTYPEKEYBOARD_J3100 12 + +#define DIDEVTYPEJOYSTICK_UNKNOWN 1 +#define DIDEVTYPEJOYSTICK_TRADITIONAL 2 +#define DIDEVTYPEJOYSTICK_FLIGHTSTICK 3 +#define DIDEVTYPEJOYSTICK_GAMEPAD 4 +#define DIDEVTYPEJOYSTICK_RUDDER 5 +#define DIDEVTYPEJOYSTICK_WHEEL 6 +#define DIDEVTYPEJOYSTICK_HEADTRACKER 7 + +#define DI8DEVTYPEMOUSE_UNKNOWN 1 +#define DI8DEVTYPEMOUSE_TRADITIONAL 2 +#define DI8DEVTYPEMOUSE_FINGERSTICK 3 +#define DI8DEVTYPEMOUSE_TOUCHPAD 4 +#define DI8DEVTYPEMOUSE_TRACKBALL 5 +#define DI8DEVTYPEMOUSE_ABSOLUTE 6 + +#define DI8DEVTYPEKEYBOARD_UNKNOWN 0 +#define DI8DEVTYPEKEYBOARD_PCXT 1 +#define DI8DEVTYPEKEYBOARD_OLIVETTI 2 +#define DI8DEVTYPEKEYBOARD_PCAT 3 +#define DI8DEVTYPEKEYBOARD_PCENH 4 +#define DI8DEVTYPEKEYBOARD_NOKIA1050 5 +#define DI8DEVTYPEKEYBOARD_NOKIA9140 6 +#define DI8DEVTYPEKEYBOARD_NEC98 7 +#define DI8DEVTYPEKEYBOARD_NEC98LAPTOP 8 +#define DI8DEVTYPEKEYBOARD_NEC98106 9 +#define DI8DEVTYPEKEYBOARD_JAPAN106 10 +#define DI8DEVTYPEKEYBOARD_JAPANAX 11 +#define DI8DEVTYPEKEYBOARD_J3100 12 + +#define DI8DEVTYPE_LIMITEDGAMESUBTYPE 1 + +#define DI8DEVTYPEJOYSTICK_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEJOYSTICK_STANDARD 2 + +#define DI8DEVTYPEGAMEPAD_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEGAMEPAD_STANDARD 2 +#define DI8DEVTYPEGAMEPAD_TILT 3 + +#define DI8DEVTYPEDRIVING_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEDRIVING_COMBINEDPEDALS 2 +#define DI8DEVTYPEDRIVING_DUALPEDALS 3 +#define DI8DEVTYPEDRIVING_THREEPEDALS 4 +#define DI8DEVTYPEDRIVING_HANDHELD 5 + +#define DI8DEVTYPEFLIGHT_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPEFLIGHT_STICK 2 +#define DI8DEVTYPEFLIGHT_YOKE 3 +#define DI8DEVTYPEFLIGHT_RC 4 + +#define DI8DEVTYPE1STPERSON_LIMITED DI8DEVTYPE_LIMITEDGAMESUBTYPE +#define DI8DEVTYPE1STPERSON_UNKNOWN 2 +#define DI8DEVTYPE1STPERSON_SIXDOF 3 +#define DI8DEVTYPE1STPERSON_SHOOTER 4 + +#define DI8DEVTYPESCREENPTR_UNKNOWN 2 +#define DI8DEVTYPESCREENPTR_LIGHTGUN 3 +#define DI8DEVTYPESCREENPTR_LIGHTPEN 4 +#define DI8DEVTYPESCREENPTR_TOUCH 5 + +#define DI8DEVTYPEREMOTE_UNKNOWN 2 + +#define DI8DEVTYPEDEVICECTRL_UNKNOWN 2 +#define DI8DEVTYPEDEVICECTRL_COMMSSELECTION 3 +#define DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED 4 + +#define DI8DEVTYPESUPPLEMENTAL_UNKNOWN 2 +#define DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER 3 +#define DI8DEVTYPESUPPLEMENTAL_HEADTRACKER 4 +#define DI8DEVTYPESUPPLEMENTAL_HANDTRACKER 5 +#define DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE 6 +#define DI8DEVTYPESUPPLEMENTAL_SHIFTER 7 +#define DI8DEVTYPESUPPLEMENTAL_THROTTLE 8 +#define DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE 9 +#define DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS 10 +#define DI8DEVTYPESUPPLEMENTAL_DUALPEDALS 11 +#define DI8DEVTYPESUPPLEMENTAL_THREEPEDALS 12 +#define DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS 13 + +#define GET_DIDEVICE_TYPE(dwDevType) LOBYTE(dwDevType) +#define GET_DIDEVICE_SUBTYPE(dwDevType) HIBYTE(dwDevType) + +typedef struct DIDEVICEOBJECTINSTANCE_DX3A { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + CHAR tszName[MAX_PATH]; +} DIDEVICEOBJECTINSTANCE_DX3A, *LPDIDEVICEOBJECTINSTANCE_DX3A; +typedef const DIDEVICEOBJECTINSTANCE_DX3A *LPCDIDEVICEOBJECTINSTANCE_DX3A; +typedef struct DIDEVICEOBJECTINSTANCE_DX3W { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + WCHAR tszName[MAX_PATH]; +} DIDEVICEOBJECTINSTANCE_DX3W, *LPDIDEVICEOBJECTINSTANCE_DX3W; +typedef const DIDEVICEOBJECTINSTANCE_DX3W *LPCDIDEVICEOBJECTINSTANCE_DX3W; + +DECL_WINELIB_TYPE_AW(DIDEVICEOBJECTINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPDIDEVICEOBJECTINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEOBJECTINSTANCE_DX3) + +typedef struct DIDEVICEOBJECTINSTANCEA { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + CHAR tszName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFMaxForce; + DWORD dwFFForceResolution; + WORD wCollectionNumber; + WORD wDesignatorIndex; + WORD wUsagePage; + WORD wUsage; + DWORD dwDimension; + WORD wExponent; + WORD wReserved; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEOBJECTINSTANCEA, *LPDIDEVICEOBJECTINSTANCEA; +typedef const DIDEVICEOBJECTINSTANCEA *LPCDIDEVICEOBJECTINSTANCEA; + +typedef struct DIDEVICEOBJECTINSTANCEW { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + WCHAR tszName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFMaxForce; + DWORD dwFFForceResolution; + WORD wCollectionNumber; + WORD wDesignatorIndex; + WORD wUsagePage; + WORD wUsage; + DWORD dwDimension; + WORD wExponent; + WORD wReserved; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEOBJECTINSTANCEW, *LPDIDEVICEOBJECTINSTANCEW; +typedef const DIDEVICEOBJECTINSTANCEW *LPCDIDEVICEOBJECTINSTANCEW; + +DECL_WINELIB_TYPE_AW(DIDEVICEOBJECTINSTANCE) +DECL_WINELIB_TYPE_AW(LPDIDEVICEOBJECTINSTANCE) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEOBJECTINSTANCE) + +typedef struct DIDEVICEINSTANCE_DX3A { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + CHAR tszInstanceName[MAX_PATH]; + CHAR tszProductName[MAX_PATH]; +} DIDEVICEINSTANCE_DX3A, *LPDIDEVICEINSTANCE_DX3A; +typedef const DIDEVICEINSTANCE_DX3A *LPCDIDEVICEINSTANCE_DX3A; +typedef struct DIDEVICEINSTANCE_DX3W { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + WCHAR tszInstanceName[MAX_PATH]; + WCHAR tszProductName[MAX_PATH]; +} DIDEVICEINSTANCE_DX3W, *LPDIDEVICEINSTANCE_DX3W; +typedef const DIDEVICEINSTANCE_DX3W *LPCDIDEVICEINSTANCE_DX3W; + +DECL_WINELIB_TYPE_AW(DIDEVICEINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPDIDEVICEINSTANCE_DX3) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEINSTANCE_DX3) + +typedef struct DIDEVICEINSTANCEA { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + CHAR tszInstanceName[MAX_PATH]; + CHAR tszProductName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + GUID guidFFDriver; + WORD wUsagePage; + WORD wUsage; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEINSTANCEA, *LPDIDEVICEINSTANCEA; +typedef const DIDEVICEINSTANCEA *LPCDIDEVICEINSTANCEA; + +typedef struct DIDEVICEINSTANCEW { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + WCHAR tszInstanceName[MAX_PATH]; + WCHAR tszProductName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + GUID guidFFDriver; + WORD wUsagePage; + WORD wUsage; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEINSTANCEW, *LPDIDEVICEINSTANCEW; +typedef const DIDEVICEINSTANCEW *LPCDIDEVICEINSTANCEW; + +DECL_WINELIB_TYPE_AW(DIDEVICEINSTANCE) +DECL_WINELIB_TYPE_AW(LPDIDEVICEINSTANCE) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEINSTANCE) + +typedef BOOL (CALLBACK *LPDIENUMDEVICESCALLBACKA)(LPCDIDEVICEINSTANCEA,LPVOID); +typedef BOOL (CALLBACK *LPDIENUMDEVICESCALLBACKW)(LPCDIDEVICEINSTANCEW,LPVOID); +DECL_WINELIB_TYPE_AW(LPDIENUMDEVICESCALLBACK) + +#define DIEDBS_MAPPEDPRI1 0x00000001 +#define DIEDBS_MAPPEDPRI2 0x00000002 +#define DIEDBS_RECENTDEVICE 0x00000010 +#define DIEDBS_NEWDEVICE 0x00000020 + +#define DIEDBSFL_ATTACHEDONLY 0x00000000 +#define DIEDBSFL_THISUSER 0x00000010 +#define DIEDBSFL_FORCEFEEDBACK DIEDFL_FORCEFEEDBACK +#define DIEDBSFL_AVAILABLEDEVICES 0x00001000 +#define DIEDBSFL_MULTIMICEKEYBOARDS 0x00002000 +#define DIEDBSFL_NONGAMINGDEVICES 0x00004000 +#define DIEDBSFL_VALID 0x00007110 + +#if DIRECTINPUT_VERSION >= 0x0800 +typedef BOOL (CALLBACK *LPDIENUMDEVICESBYSEMANTICSCBA)(LPCDIDEVICEINSTANCEA,LPDIRECTINPUTDEVICE8A,DWORD,DWORD,LPVOID); +typedef BOOL (CALLBACK *LPDIENUMDEVICESBYSEMANTICSCBW)(LPCDIDEVICEINSTANCEW,LPDIRECTINPUTDEVICE8W,DWORD,DWORD,LPVOID); +DECL_WINELIB_TYPE_AW(LPDIENUMDEVICESBYSEMANTICSCB) +#endif + +typedef BOOL (CALLBACK *LPDICONFIGUREDEVICESCALLBACK)(LPUNKNOWN,LPVOID); + +typedef BOOL (CALLBACK *LPDIENUMDEVICEOBJECTSCALLBACKA)(LPCDIDEVICEOBJECTINSTANCEA,LPVOID); +typedef BOOL (CALLBACK *LPDIENUMDEVICEOBJECTSCALLBACKW)(LPCDIDEVICEOBJECTINSTANCEW,LPVOID); +DECL_WINELIB_TYPE_AW(LPDIENUMDEVICEOBJECTSCALLBACK) + +#if DIRECTINPUT_VERSION >= 0x0500 +typedef BOOL (CALLBACK *LPDIENUMCREATEDEFFECTOBJECTSCALLBACK)(LPDIRECTINPUTEFFECT, LPVOID); +#endif + +#define DIK_ESCAPE 0x01 +#define DIK_1 0x02 +#define DIK_2 0x03 +#define DIK_3 0x04 +#define DIK_4 0x05 +#define DIK_5 0x06 +#define DIK_6 0x07 +#define DIK_7 0x08 +#define DIK_8 0x09 +#define DIK_9 0x0A +#define DIK_0 0x0B +#define DIK_MINUS 0x0C /* - on main keyboard */ +#define DIK_EQUALS 0x0D +#define DIK_BACK 0x0E /* backspace */ +#define DIK_TAB 0x0F +#define DIK_Q 0x10 +#define DIK_W 0x11 +#define DIK_E 0x12 +#define DIK_R 0x13 +#define DIK_T 0x14 +#define DIK_Y 0x15 +#define DIK_U 0x16 +#define DIK_I 0x17 +#define DIK_O 0x18 +#define DIK_P 0x19 +#define DIK_LBRACKET 0x1A +#define DIK_RBRACKET 0x1B +#define DIK_RETURN 0x1C /* Enter on main keyboard */ +#define DIK_LCONTROL 0x1D +#define DIK_A 0x1E +#define DIK_S 0x1F +#define DIK_D 0x20 +#define DIK_F 0x21 +#define DIK_G 0x22 +#define DIK_H 0x23 +#define DIK_J 0x24 +#define DIK_K 0x25 +#define DIK_L 0x26 +#define DIK_SEMICOLON 0x27 +#define DIK_APOSTROPHE 0x28 +#define DIK_GRAVE 0x29 /* accent grave */ +#define DIK_LSHIFT 0x2A +#define DIK_BACKSLASH 0x2B +#define DIK_Z 0x2C +#define DIK_X 0x2D +#define DIK_C 0x2E +#define DIK_V 0x2F +#define DIK_B 0x30 +#define DIK_N 0x31 +#define DIK_M 0x32 +#define DIK_COMMA 0x33 +#define DIK_PERIOD 0x34 /* . on main keyboard */ +#define DIK_SLASH 0x35 /* / on main keyboard */ +#define DIK_RSHIFT 0x36 +#define DIK_MULTIPLY 0x37 /* * on numeric keypad */ +#define DIK_LMENU 0x38 /* left Alt */ +#define DIK_SPACE 0x39 +#define DIK_CAPITAL 0x3A +#define DIK_F1 0x3B +#define DIK_F2 0x3C +#define DIK_F3 0x3D +#define DIK_F4 0x3E +#define DIK_F5 0x3F +#define DIK_F6 0x40 +#define DIK_F7 0x41 +#define DIK_F8 0x42 +#define DIK_F9 0x43 +#define DIK_F10 0x44 +#define DIK_NUMLOCK 0x45 +#define DIK_SCROLL 0x46 /* Scroll Lock */ +#define DIK_NUMPAD7 0x47 +#define DIK_NUMPAD8 0x48 +#define DIK_NUMPAD9 0x49 +#define DIK_SUBTRACT 0x4A /* - on numeric keypad */ +#define DIK_NUMPAD4 0x4B +#define DIK_NUMPAD5 0x4C +#define DIK_NUMPAD6 0x4D +#define DIK_ADD 0x4E /* + on numeric keypad */ +#define DIK_NUMPAD1 0x4F +#define DIK_NUMPAD2 0x50 +#define DIK_NUMPAD3 0x51 +#define DIK_NUMPAD0 0x52 +#define DIK_DECIMAL 0x53 /* . on numeric keypad */ +#define DIK_OEM_102 0x56 /* < > | on UK/Germany keyboards */ +#define DIK_F11 0x57 +#define DIK_F12 0x58 +#define DIK_F13 0x64 /* (NEC PC98) */ +#define DIK_F14 0x65 /* (NEC PC98) */ +#define DIK_F15 0x66 /* (NEC PC98) */ +#define DIK_KANA 0x70 /* (Japanese keyboard) */ +#define DIK_ABNT_C1 0x73 /* / ? on Portugese (Brazilian) keyboards */ +#define DIK_CONVERT 0x79 /* (Japanese keyboard) */ +#define DIK_NOCONVERT 0x7B /* (Japanese keyboard) */ +#define DIK_YEN 0x7D /* (Japanese keyboard) */ +#define DIK_ABNT_C2 0x7E /* Numpad . on Portugese (Brazilian) keyboards */ +#define DIK_NUMPADEQUALS 0x8D /* = on numeric keypad (NEC PC98) */ +#define DIK_CIRCUMFLEX 0x90 /* (Japanese keyboard) */ +#define DIK_AT 0x91 /* (NEC PC98) */ +#define DIK_COLON 0x92 /* (NEC PC98) */ +#define DIK_UNDERLINE 0x93 /* (NEC PC98) */ +#define DIK_KANJI 0x94 /* (Japanese keyboard) */ +#define DIK_STOP 0x95 /* (NEC PC98) */ +#define DIK_AX 0x96 /* (Japan AX) */ +#define DIK_UNLABELED 0x97 /* (J3100) */ +#define DIK_NEXTTRACK 0x99 /* Next Track */ +#define DIK_NUMPADENTER 0x9C /* Enter on numeric keypad */ +#define DIK_RCONTROL 0x9D +#define DIK_MUTE 0xA0 /* Mute */ +#define DIK_CALCULATOR 0xA1 /* Calculator */ +#define DIK_PLAYPAUSE 0xA2 /* Play / Pause */ +#define DIK_MEDIASTOP 0xA4 /* Media Stop */ +#define DIK_VOLUMEDOWN 0xAE /* Volume - */ +#define DIK_VOLUMEUP 0xB0 /* Volume + */ +#define DIK_WEBHOME 0xB2 /* Web home */ +#define DIK_NUMPADCOMMA 0xB3 /* , on numeric keypad (NEC PC98) */ +#define DIK_DIVIDE 0xB5 /* / on numeric keypad */ +#define DIK_SYSRQ 0xB7 +#define DIK_RMENU 0xB8 /* right Alt */ +#define DIK_PAUSE 0xC5 /* Pause */ +#define DIK_HOME 0xC7 /* Home on arrow keypad */ +#define DIK_UP 0xC8 /* UpArrow on arrow keypad */ +#define DIK_PRIOR 0xC9 /* PgUp on arrow keypad */ +#define DIK_LEFT 0xCB /* LeftArrow on arrow keypad */ +#define DIK_RIGHT 0xCD /* RightArrow on arrow keypad */ +#define DIK_END 0xCF /* End on arrow keypad */ +#define DIK_DOWN 0xD0 /* DownArrow on arrow keypad */ +#define DIK_NEXT 0xD1 /* PgDn on arrow keypad */ +#define DIK_INSERT 0xD2 /* Insert on arrow keypad */ +#define DIK_DELETE 0xD3 /* Delete on arrow keypad */ +#define DIK_LWIN 0xDB /* Left Windows key */ +#define DIK_RWIN 0xDC /* Right Windows key */ +#define DIK_APPS 0xDD /* AppMenu key */ +#define DIK_POWER 0xDE +#define DIK_SLEEP 0xDF +#define DIK_WAKE 0xE3 /* System Wake */ +#define DIK_WEBSEARCH 0xE5 /* Web Search */ +#define DIK_WEBFAVORITES 0xE6 /* Web Favorites */ +#define DIK_WEBREFRESH 0xE7 /* Web Refresh */ +#define DIK_WEBSTOP 0xE8 /* Web Stop */ +#define DIK_WEBFORWARD 0xE9 /* Web Forward */ +#define DIK_WEBBACK 0xEA /* Web Back */ +#define DIK_MYCOMPUTER 0xEB /* My Computer */ +#define DIK_MAIL 0xEC /* Mail */ +#define DIK_MEDIASELECT 0xED /* Media Select */ + +#define DIK_BACKSPACE DIK_BACK /* backspace */ +#define DIK_NUMPADSTAR DIK_MULTIPLY /* * on numeric keypad */ +#define DIK_LALT DIK_LMENU /* left Alt */ +#define DIK_CAPSLOCK DIK_CAPITAL /* CapsLock */ +#define DIK_NUMPADMINUS DIK_SUBTRACT /* - on numeric keypad */ +#define DIK_NUMPADPLUS DIK_ADD /* + on numeric keypad */ +#define DIK_NUMPADPERIOD DIK_DECIMAL /* . on numeric keypad */ +#define DIK_NUMPADSLASH DIK_DIVIDE /* / on numeric keypad */ +#define DIK_RALT DIK_RMENU /* right Alt */ +#define DIK_UPARROW DIK_UP /* UpArrow on arrow keypad */ +#define DIK_PGUP DIK_PRIOR /* PgUp on arrow keypad */ +#define DIK_LEFTARROW DIK_LEFT /* LeftArrow on arrow keypad */ +#define DIK_RIGHTARROW DIK_RIGHT /* RightArrow on arrow keypad */ +#define DIK_DOWNARROW DIK_DOWN /* DownArrow on arrow keypad */ +#define DIK_PGDN DIK_NEXT /* PgDn on arrow keypad */ + +#define DIDFT_ALL 0x00000000 +#define DIDFT_RELAXIS 0x00000001 +#define DIDFT_ABSAXIS 0x00000002 +#define DIDFT_AXIS 0x00000003 +#define DIDFT_PSHBUTTON 0x00000004 +#define DIDFT_TGLBUTTON 0x00000008 +#define DIDFT_BUTTON 0x0000000C +#define DIDFT_POV 0x00000010 +#define DIDFT_COLLECTION 0x00000040 +#define DIDFT_NODATA 0x00000080 +#define DIDFT_ANYINSTANCE 0x00FFFF00 +#define DIDFT_INSTANCEMASK DIDFT_ANYINSTANCE +#define DIDFT_MAKEINSTANCE(n) ((WORD)(n) << 8) +#define DIDFT_GETTYPE(n) LOBYTE(n) +#define DIDFT_GETINSTANCE(n) LOWORD((n) >> 8) +#define DIDFT_FFACTUATOR 0x01000000 +#define DIDFT_FFEFFECTTRIGGER 0x02000000 +#if DIRECTINPUT_VERSION >= 0x050a +#define DIDFT_OUTPUT 0x10000000 +#define DIDFT_VENDORDEFINED 0x04000000 +#define DIDFT_ALIAS 0x08000000 +#endif /* DI5a */ +#ifndef DIDFT_OPTIONAL +#define DIDFT_OPTIONAL 0x80000000 +#endif +#define DIDFT_ENUMCOLLECTION(n) ((WORD)(n) << 8) +#define DIDFT_NOCOLLECTION 0x00FFFF00 + +#define DIDF_ABSAXIS 0x00000001 +#define DIDF_RELAXIS 0x00000002 + +#define DIGDD_PEEK 0x00000001 + +#define DISEQUENCE_COMPARE(dwSq1,cmp,dwSq2) ((int)((dwSq1) - (dwSq2)) cmp 0) + +typedef struct DIDEVICEOBJECTDATA_DX3 { + DWORD dwOfs; + DWORD dwData; + DWORD dwTimeStamp; + DWORD dwSequence; +} DIDEVICEOBJECTDATA_DX3,*LPDIDEVICEOBJECTDATA_DX3; +typedef const DIDEVICEOBJECTDATA_DX3 *LPCDIDEVICEOBJECTDATA_DX3; + +typedef struct DIDEVICEOBJECTDATA { + DWORD dwOfs; + DWORD dwData; + DWORD dwTimeStamp; + DWORD dwSequence; +#if(DIRECTINPUT_VERSION >= 0x0800) + UINT_PTR uAppData; +#endif /* DIRECTINPUT_VERSION >= 0x0800 */ +} DIDEVICEOBJECTDATA, *LPDIDEVICEOBJECTDATA; +typedef const DIDEVICEOBJECTDATA *LPCDIDEVICEOBJECTDATA; + +typedef struct _DIOBJECTDATAFORMAT { + const GUID *pguid; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; +} DIOBJECTDATAFORMAT, *LPDIOBJECTDATAFORMAT; +typedef const DIOBJECTDATAFORMAT *LPCDIOBJECTDATAFORMAT; + +typedef struct _DIDATAFORMAT { + DWORD dwSize; + DWORD dwObjSize; + DWORD dwFlags; + DWORD dwDataSize; + DWORD dwNumObjs; + LPDIOBJECTDATAFORMAT rgodf; +} DIDATAFORMAT, *LPDIDATAFORMAT; +typedef const DIDATAFORMAT *LPCDIDATAFORMAT; + +#if DIRECTINPUT_VERSION >= 0x0500 +#define DIDOI_FFACTUATOR 0x00000001 +#define DIDOI_FFEFFECTTRIGGER 0x00000002 +#define DIDOI_POLLED 0x00008000 +#define DIDOI_ASPECTPOSITION 0x00000100 +#define DIDOI_ASPECTVELOCITY 0x00000200 +#define DIDOI_ASPECTACCEL 0x00000300 +#define DIDOI_ASPECTFORCE 0x00000400 +#define DIDOI_ASPECTMASK 0x00000F00 +#endif /* DI5 */ +#if DIRECTINPUT_VERSION >= 0x050a +#define DIDOI_GUIDISUSAGE 0x00010000 +#endif /* DI5a */ + +typedef struct DIPROPHEADER { + DWORD dwSize; + DWORD dwHeaderSize; + DWORD dwObj; + DWORD dwHow; +} DIPROPHEADER,*LPDIPROPHEADER; +typedef const DIPROPHEADER *LPCDIPROPHEADER; + +#define DIPH_DEVICE 0 +#define DIPH_BYOFFSET 1 +#define DIPH_BYID 2 +#if DIRECTINPUT_VERSION >= 0x050a +#define DIPH_BYUSAGE 3 + +#define DIMAKEUSAGEDWORD(UsagePage, Usage) (DWORD)MAKELONG(Usage, UsagePage) +#endif /* DI5a */ + +typedef struct DIPROPDWORD { + DIPROPHEADER diph; + DWORD dwData; +} DIPROPDWORD, *LPDIPROPDWORD; +typedef const DIPROPDWORD *LPCDIPROPDWORD; + +typedef struct DIPROPRANGE { + DIPROPHEADER diph; + LONG lMin; + LONG lMax; +} DIPROPRANGE, *LPDIPROPRANGE; +typedef const DIPROPRANGE *LPCDIPROPRANGE; + +#define DIPROPRANGE_NOMIN ((LONG)0x80000000) +#define DIPROPRANGE_NOMAX ((LONG)0x7FFFFFFF) + +#if DIRECTINPUT_VERSION >= 0x050a +typedef struct DIPROPCAL { + DIPROPHEADER diph; + LONG lMin; + LONG lCenter; + LONG lMax; +} DIPROPCAL, *LPDIPROPCAL; +typedef const DIPROPCAL *LPCDIPROPCAL; + +typedef struct DIPROPCALPOV { + DIPROPHEADER diph; + LONG lMin[5]; + LONG lMax[5]; +} DIPROPCALPOV, *LPDIPROPCALPOV; +typedef const DIPROPCALPOV *LPCDIPROPCALPOV; + +typedef struct DIPROPGUIDANDPATH { + DIPROPHEADER diph; + GUID guidClass; + WCHAR wszPath[MAX_PATH]; +} DIPROPGUIDANDPATH, *LPDIPROPGUIDANDPATH; +typedef const DIPROPGUIDANDPATH *LPCDIPROPGUIDANDPATH; + +typedef struct DIPROPSTRING { + DIPROPHEADER diph; + WCHAR wsz[MAX_PATH]; +} DIPROPSTRING, *LPDIPROPSTRING; +typedef const DIPROPSTRING *LPCDIPROPSTRING; +#endif /* DI5a */ + +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct DIPROPPOINTER { + DIPROPHEADER diph; + UINT_PTR uData; +} DIPROPPOINTER, *LPDIPROPPOINTER; +typedef const DIPROPPOINTER *LPCDIPROPPOINTER; +#endif /* DI8 */ + +/* special property GUIDs */ +#ifdef __cplusplus +#define MAKEDIPROP(prop) (*(const GUID *)(prop)) +#else +#define MAKEDIPROP(prop) ((REFGUID)(prop)) +#endif +#define DIPROP_BUFFERSIZE MAKEDIPROP(1) +#define DIPROP_AXISMODE MAKEDIPROP(2) + +#define DIPROPAXISMODE_ABS 0 +#define DIPROPAXISMODE_REL 1 + +#define DIPROP_GRANULARITY MAKEDIPROP(3) +#define DIPROP_RANGE MAKEDIPROP(4) +#define DIPROP_DEADZONE MAKEDIPROP(5) +#define DIPROP_SATURATION MAKEDIPROP(6) +#define DIPROP_FFGAIN MAKEDIPROP(7) +#define DIPROP_FFLOAD MAKEDIPROP(8) +#define DIPROP_AUTOCENTER MAKEDIPROP(9) + +#define DIPROPAUTOCENTER_OFF 0 +#define DIPROPAUTOCENTER_ON 1 + +#define DIPROP_CALIBRATIONMODE MAKEDIPROP(10) + +#define DIPROPCALIBRATIONMODE_COOKED 0 +#define DIPROPCALIBRATIONMODE_RAW 1 + +#if DIRECTINPUT_VERSION >= 0x050a +#define DIPROP_CALIBRATION MAKEDIPROP(11) +#define DIPROP_GUIDANDPATH MAKEDIPROP(12) +#define DIPROP_INSTANCENAME MAKEDIPROP(13) +#define DIPROP_PRODUCTNAME MAKEDIPROP(14) +#endif + +#if DIRECTINPUT_VERSION >= 0x5B2 +#define DIPROP_JOYSTICKID MAKEDIPROP(15) +#define DIPROP_GETPORTDISPLAYNAME MAKEDIPROP(16) +#endif + +#if DIRECTINPUT_VERSION >= 0x0700 +#define DIPROP_PHYSICALRANGE MAKEDIPROP(18) +#define DIPROP_LOGICALRANGE MAKEDIPROP(19) +#endif + +#if(DIRECTINPUT_VERSION >= 0x0800) +#define DIPROP_KEYNAME MAKEDIPROP(20) +#define DIPROP_CPOINTS MAKEDIPROP(21) +#define DIPROP_APPDATA MAKEDIPROP(22) +#define DIPROP_SCANCODE MAKEDIPROP(23) +#define DIPROP_VIDPID MAKEDIPROP(24) +#define DIPROP_USERNAME MAKEDIPROP(25) +#define DIPROP_TYPENAME MAKEDIPROP(26) + +#define MAXCPOINTSNUM 8 + +typedef struct _CPOINT { + LONG lP; + DWORD dwLog; +} CPOINT, *PCPOINT; + +typedef struct DIPROPCPOINTS { + DIPROPHEADER diph; + DWORD dwCPointsNum; + CPOINT cp[MAXCPOINTSNUM]; +} DIPROPCPOINTS, *LPDIPROPCPOINTS; +typedef const DIPROPCPOINTS *LPCDIPROPCPOINTS; +#endif /* DI8 */ + + +typedef struct DIDEVCAPS_DX3 { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDevType; + DWORD dwAxes; + DWORD dwButtons; + DWORD dwPOVs; +} DIDEVCAPS_DX3, *LPDIDEVCAPS_DX3; + +typedef struct DIDEVCAPS { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDevType; + DWORD dwAxes; + DWORD dwButtons; + DWORD dwPOVs; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFSamplePeriod; + DWORD dwFFMinTimeResolution; + DWORD dwFirmwareRevision; + DWORD dwHardwareRevision; + DWORD dwFFDriverVersion; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVCAPS,*LPDIDEVCAPS; + +#define DIDC_ATTACHED 0x00000001 +#define DIDC_POLLEDDEVICE 0x00000002 +#define DIDC_EMULATED 0x00000004 +#define DIDC_POLLEDDATAFORMAT 0x00000008 +#define DIDC_FORCEFEEDBACK 0x00000100 +#define DIDC_FFATTACK 0x00000200 +#define DIDC_FFFADE 0x00000400 +#define DIDC_SATURATION 0x00000800 +#define DIDC_POSNEGCOEFFICIENTS 0x00001000 +#define DIDC_POSNEGSATURATION 0x00002000 +#define DIDC_DEADBAND 0x00004000 +#define DIDC_STARTDELAY 0x00008000 +#define DIDC_ALIAS 0x00010000 +#define DIDC_PHANTOM 0x00020000 +#define DIDC_HIDDEN 0x00040000 + + +/* SetCooperativeLevel dwFlags */ +#define DISCL_EXCLUSIVE 0x00000001 +#define DISCL_NONEXCLUSIVE 0x00000002 +#define DISCL_FOREGROUND 0x00000004 +#define DISCL_BACKGROUND 0x00000008 +#define DISCL_NOWINKEY 0x00000010 + +#if (DIRECTINPUT_VERSION >= 0x0500) +/* Device FF flags */ +#define DISFFC_RESET 0x00000001 +#define DISFFC_STOPALL 0x00000002 +#define DISFFC_PAUSE 0x00000004 +#define DISFFC_CONTINUE 0x00000008 +#define DISFFC_SETACTUATORSON 0x00000010 +#define DISFFC_SETACTUATORSOFF 0x00000020 + +#define DIGFFS_EMPTY 0x00000001 +#define DIGFFS_STOPPED 0x00000002 +#define DIGFFS_PAUSED 0x00000004 +#define DIGFFS_ACTUATORSON 0x00000010 +#define DIGFFS_ACTUATORSOFF 0x00000020 +#define DIGFFS_POWERON 0x00000040 +#define DIGFFS_POWEROFF 0x00000080 +#define DIGFFS_SAFETYSWITCHON 0x00000100 +#define DIGFFS_SAFETYSWITCHOFF 0x00000200 +#define DIGFFS_USERFFSWITCHON 0x00000400 +#define DIGFFS_USERFFSWITCHOFF 0x00000800 +#define DIGFFS_DEVICELOST 0x80000000 + +/* Effect flags */ +#define DIEFT_ALL 0x00000000 + +#define DIEFT_CONSTANTFORCE 0x00000001 +#define DIEFT_RAMPFORCE 0x00000002 +#define DIEFT_PERIODIC 0x00000003 +#define DIEFT_CONDITION 0x00000004 +#define DIEFT_CUSTOMFORCE 0x00000005 +#define DIEFT_HARDWARE 0x000000FF +#define DIEFT_FFATTACK 0x00000200 +#define DIEFT_FFFADE 0x00000400 +#define DIEFT_SATURATION 0x00000800 +#define DIEFT_POSNEGCOEFFICIENTS 0x00001000 +#define DIEFT_POSNEGSATURATION 0x00002000 +#define DIEFT_DEADBAND 0x00004000 +#define DIEFT_STARTDELAY 0x00008000 +#define DIEFT_GETTYPE(n) LOBYTE(n) + +#define DIEFF_OBJECTIDS 0x00000001 +#define DIEFF_OBJECTOFFSETS 0x00000002 +#define DIEFF_CARTESIAN 0x00000010 +#define DIEFF_POLAR 0x00000020 +#define DIEFF_SPHERICAL 0x00000040 + +#define DIEP_DURATION 0x00000001 +#define DIEP_SAMPLEPERIOD 0x00000002 +#define DIEP_GAIN 0x00000004 +#define DIEP_TRIGGERBUTTON 0x00000008 +#define DIEP_TRIGGERREPEATINTERVAL 0x00000010 +#define DIEP_AXES 0x00000020 +#define DIEP_DIRECTION 0x00000040 +#define DIEP_ENVELOPE 0x00000080 +#define DIEP_TYPESPECIFICPARAMS 0x00000100 +#if(DIRECTINPUT_VERSION >= 0x0600) +#define DIEP_STARTDELAY 0x00000200 +#define DIEP_ALLPARAMS_DX5 0x000001FF +#define DIEP_ALLPARAMS 0x000003FF +#else +#define DIEP_ALLPARAMS 0x000001FF +#endif /* DIRECTINPUT_VERSION >= 0x0600 */ +#define DIEP_START 0x20000000 +#define DIEP_NORESTART 0x40000000 +#define DIEP_NODOWNLOAD 0x80000000 +#define DIEB_NOTRIGGER 0xFFFFFFFF + +#define DIES_SOLO 0x00000001 +#define DIES_NODOWNLOAD 0x80000000 + +#define DIEGES_PLAYING 0x00000001 +#define DIEGES_EMULATED 0x00000002 + +#define DI_DEGREES 100 +#define DI_FFNOMINALMAX 10000 +#define DI_SECONDS 1000000 + +typedef struct DICONSTANTFORCE { + LONG lMagnitude; +} DICONSTANTFORCE, *LPDICONSTANTFORCE; +typedef const DICONSTANTFORCE *LPCDICONSTANTFORCE; + +typedef struct DIRAMPFORCE { + LONG lStart; + LONG lEnd; +} DIRAMPFORCE, *LPDIRAMPFORCE; +typedef const DIRAMPFORCE *LPCDIRAMPFORCE; + +typedef struct DIPERIODIC { + DWORD dwMagnitude; + LONG lOffset; + DWORD dwPhase; + DWORD dwPeriod; +} DIPERIODIC, *LPDIPERIODIC; +typedef const DIPERIODIC *LPCDIPERIODIC; + +typedef struct DICONDITION { + LONG lOffset; + LONG lPositiveCoefficient; + LONG lNegativeCoefficient; + DWORD dwPositiveSaturation; + DWORD dwNegativeSaturation; + LONG lDeadBand; +} DICONDITION, *LPDICONDITION; +typedef const DICONDITION *LPCDICONDITION; + +typedef struct DICUSTOMFORCE { + DWORD cChannels; + DWORD dwSamplePeriod; + DWORD cSamples; + LPLONG rglForceData; +} DICUSTOMFORCE, *LPDICUSTOMFORCE; +typedef const DICUSTOMFORCE *LPCDICUSTOMFORCE; + +typedef struct DIENVELOPE { + DWORD dwSize; + DWORD dwAttackLevel; + DWORD dwAttackTime; + DWORD dwFadeLevel; + DWORD dwFadeTime; +} DIENVELOPE, *LPDIENVELOPE; +typedef const DIENVELOPE *LPCDIENVELOPE; + +typedef struct DIEFFECT_DX5 { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDuration; + DWORD dwSamplePeriod; + DWORD dwGain; + DWORD dwTriggerButton; + DWORD dwTriggerRepeatInterval; + DWORD cAxes; + LPDWORD rgdwAxes; + LPLONG rglDirection; + LPDIENVELOPE lpEnvelope; + DWORD cbTypeSpecificParams; + LPVOID lpvTypeSpecificParams; +} DIEFFECT_DX5, *LPDIEFFECT_DX5; +typedef const DIEFFECT_DX5 *LPCDIEFFECT_DX5; + +typedef struct DIEFFECT { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDuration; + DWORD dwSamplePeriod; + DWORD dwGain; + DWORD dwTriggerButton; + DWORD dwTriggerRepeatInterval; + DWORD cAxes; + LPDWORD rgdwAxes; + LPLONG rglDirection; + LPDIENVELOPE lpEnvelope; + DWORD cbTypeSpecificParams; + LPVOID lpvTypeSpecificParams; +#if(DIRECTINPUT_VERSION >= 0x0600) + DWORD dwStartDelay; +#endif /* DIRECTINPUT_VERSION >= 0x0600 */ +} DIEFFECT, *LPDIEFFECT; +typedef const DIEFFECT *LPCDIEFFECT; +typedef DIEFFECT DIEFFECT_DX6; +typedef LPDIEFFECT LPDIEFFECT_DX6; + +typedef struct DIEFFECTINFOA { + DWORD dwSize; + GUID guid; + DWORD dwEffType; + DWORD dwStaticParams; + DWORD dwDynamicParams; + CHAR tszName[MAX_PATH]; +} DIEFFECTINFOA, *LPDIEFFECTINFOA; +typedef const DIEFFECTINFOA *LPCDIEFFECTINFOA; + +typedef struct DIEFFECTINFOW { + DWORD dwSize; + GUID guid; + DWORD dwEffType; + DWORD dwStaticParams; + DWORD dwDynamicParams; + WCHAR tszName[MAX_PATH]; +} DIEFFECTINFOW, *LPDIEFFECTINFOW; +typedef const DIEFFECTINFOW *LPCDIEFFECTINFOW; + +DECL_WINELIB_TYPE_AW(DIEFFECTINFO) +DECL_WINELIB_TYPE_AW(LPDIEFFECTINFO) +DECL_WINELIB_TYPE_AW(LPCDIEFFECTINFO) + +typedef BOOL (CALLBACK *LPDIENUMEFFECTSCALLBACKA)(LPCDIEFFECTINFOA, LPVOID); +typedef BOOL (CALLBACK *LPDIENUMEFFECTSCALLBACKW)(LPCDIEFFECTINFOW, LPVOID); + +typedef struct DIEFFESCAPE { + DWORD dwSize; + DWORD dwCommand; + LPVOID lpvInBuffer; + DWORD cbInBuffer; + LPVOID lpvOutBuffer; + DWORD cbOutBuffer; +} DIEFFESCAPE, *LPDIEFFESCAPE; + +typedef struct DIJOYSTATE { + LONG lX; + LONG lY; + LONG lZ; + LONG lRx; + LONG lRy; + LONG lRz; + LONG rglSlider[2]; + DWORD rgdwPOV[4]; + BYTE rgbButtons[32]; +} DIJOYSTATE, *LPDIJOYSTATE; + +typedef struct DIJOYSTATE2 { + LONG lX; + LONG lY; + LONG lZ; + LONG lRx; + LONG lRy; + LONG lRz; + LONG rglSlider[2]; + DWORD rgdwPOV[4]; + BYTE rgbButtons[128]; + LONG lVX; /* 'v' as in velocity */ + LONG lVY; + LONG lVZ; + LONG lVRx; + LONG lVRy; + LONG lVRz; + LONG rglVSlider[2]; + LONG lAX; /* 'a' as in acceleration */ + LONG lAY; + LONG lAZ; + LONG lARx; + LONG lARy; + LONG lARz; + LONG rglASlider[2]; + LONG lFX; /* 'f' as in force */ + LONG lFY; + LONG lFZ; + LONG lFRx; /* 'fr' as in rotational force aka torque */ + LONG lFRy; + LONG lFRz; + LONG rglFSlider[2]; +} DIJOYSTATE2, *LPDIJOYSTATE2; + +#define DIJOFS_X FIELD_OFFSET(DIJOYSTATE, lX) +#define DIJOFS_Y FIELD_OFFSET(DIJOYSTATE, lY) +#define DIJOFS_Z FIELD_OFFSET(DIJOYSTATE, lZ) +#define DIJOFS_RX FIELD_OFFSET(DIJOYSTATE, lRx) +#define DIJOFS_RY FIELD_OFFSET(DIJOYSTATE, lRy) +#define DIJOFS_RZ FIELD_OFFSET(DIJOYSTATE, lRz) +#define DIJOFS_SLIDER(n) (FIELD_OFFSET(DIJOYSTATE, rglSlider) + \ + (n) * sizeof(LONG)) +#define DIJOFS_POV(n) (FIELD_OFFSET(DIJOYSTATE, rgdwPOV) + \ + (n) * sizeof(DWORD)) +#define DIJOFS_BUTTON(n) (FIELD_OFFSET(DIJOYSTATE, rgbButtons) + (n)) +#define DIJOFS_BUTTON0 DIJOFS_BUTTON(0) +#define DIJOFS_BUTTON1 DIJOFS_BUTTON(1) +#define DIJOFS_BUTTON2 DIJOFS_BUTTON(2) +#define DIJOFS_BUTTON3 DIJOFS_BUTTON(3) +#define DIJOFS_BUTTON4 DIJOFS_BUTTON(4) +#define DIJOFS_BUTTON5 DIJOFS_BUTTON(5) +#define DIJOFS_BUTTON6 DIJOFS_BUTTON(6) +#define DIJOFS_BUTTON7 DIJOFS_BUTTON(7) +#define DIJOFS_BUTTON8 DIJOFS_BUTTON(8) +#define DIJOFS_BUTTON9 DIJOFS_BUTTON(9) +#define DIJOFS_BUTTON10 DIJOFS_BUTTON(10) +#define DIJOFS_BUTTON11 DIJOFS_BUTTON(11) +#define DIJOFS_BUTTON12 DIJOFS_BUTTON(12) +#define DIJOFS_BUTTON13 DIJOFS_BUTTON(13) +#define DIJOFS_BUTTON14 DIJOFS_BUTTON(14) +#define DIJOFS_BUTTON15 DIJOFS_BUTTON(15) +#define DIJOFS_BUTTON16 DIJOFS_BUTTON(16) +#define DIJOFS_BUTTON17 DIJOFS_BUTTON(17) +#define DIJOFS_BUTTON18 DIJOFS_BUTTON(18) +#define DIJOFS_BUTTON19 DIJOFS_BUTTON(19) +#define DIJOFS_BUTTON20 DIJOFS_BUTTON(20) +#define DIJOFS_BUTTON21 DIJOFS_BUTTON(21) +#define DIJOFS_BUTTON22 DIJOFS_BUTTON(22) +#define DIJOFS_BUTTON23 DIJOFS_BUTTON(23) +#define DIJOFS_BUTTON24 DIJOFS_BUTTON(24) +#define DIJOFS_BUTTON25 DIJOFS_BUTTON(25) +#define DIJOFS_BUTTON26 DIJOFS_BUTTON(26) +#define DIJOFS_BUTTON27 DIJOFS_BUTTON(27) +#define DIJOFS_BUTTON28 DIJOFS_BUTTON(28) +#define DIJOFS_BUTTON29 DIJOFS_BUTTON(29) +#define DIJOFS_BUTTON30 DIJOFS_BUTTON(30) +#define DIJOFS_BUTTON31 DIJOFS_BUTTON(31) +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ + +/* DInput 7 structures, types */ +#if(DIRECTINPUT_VERSION >= 0x0700) +typedef struct DIFILEEFFECT { + DWORD dwSize; + GUID GuidEffect; + LPCDIEFFECT lpDiEffect; + CHAR szFriendlyName[MAX_PATH]; +} DIFILEEFFECT, *LPDIFILEEFFECT; + +typedef const DIFILEEFFECT *LPCDIFILEEFFECT; +typedef BOOL (CALLBACK *LPDIENUMEFFECTSINFILECALLBACK)(LPCDIFILEEFFECT , LPVOID); +#endif /* DIRECTINPUT_VERSION >= 0x0700 */ + +/* DInput 8 structures and types */ +#if DIRECTINPUT_VERSION >= 0x0800 +typedef struct _DIACTIONA { + UINT_PTR uAppData; + DWORD dwSemantic; + DWORD dwFlags; + __GNU_EXTENSION union { + LPCSTR lptszActionName; + UINT uResIdString; + } DUMMYUNIONNAME; + GUID guidInstance; + DWORD dwObjID; + DWORD dwHow; +} DIACTIONA, *LPDIACTIONA; +typedef const DIACTIONA *LPCDIACTIONA; + +typedef struct _DIACTIONW { + UINT_PTR uAppData; + DWORD dwSemantic; + DWORD dwFlags; + __GNU_EXTENSION union { + LPCWSTR lptszActionName; + UINT uResIdString; + } DUMMYUNIONNAME; + GUID guidInstance; + DWORD dwObjID; + DWORD dwHow; +} DIACTIONW, *LPDIACTIONW; +typedef const DIACTIONW *LPCDIACTIONW; + +DECL_WINELIB_TYPE_AW(DIACTION) +DECL_WINELIB_TYPE_AW(LPDIACTION) +DECL_WINELIB_TYPE_AW(LPCDIACTION) + +#define DIA_FORCEFEEDBACK 0x00000001 +#define DIA_APPMAPPED 0x00000002 +#define DIA_APPNOMAP 0x00000004 +#define DIA_NORANGE 0x00000008 +#define DIA_APPFIXED 0x00000010 + +#define DIAH_UNMAPPED 0x00000000 +#define DIAH_USERCONFIG 0x00000001 +#define DIAH_APPREQUESTED 0x00000002 +#define DIAH_HWAPP 0x00000004 +#define DIAH_HWDEFAULT 0x00000008 +#define DIAH_DEFAULT 0x00000020 +#define DIAH_ERROR 0x80000000 + +typedef struct _DIACTIONFORMATA { + DWORD dwSize; + DWORD dwActionSize; + DWORD dwDataSize; + DWORD dwNumActions; + LPDIACTIONA rgoAction; + GUID guidActionMap; + DWORD dwGenre; + DWORD dwBufferSize; + LONG lAxisMin; + LONG lAxisMax; + HINSTANCE hInstString; + FILETIME ftTimeStamp; + DWORD dwCRC; + CHAR tszActionMap[MAX_PATH]; +} DIACTIONFORMATA, *LPDIACTIONFORMATA; +typedef const DIACTIONFORMATA *LPCDIACTIONFORMATA; + +typedef struct _DIACTIONFORMATW { + DWORD dwSize; + DWORD dwActionSize; + DWORD dwDataSize; + DWORD dwNumActions; + LPDIACTIONW rgoAction; + GUID guidActionMap; + DWORD dwGenre; + DWORD dwBufferSize; + LONG lAxisMin; + LONG lAxisMax; + HINSTANCE hInstString; + FILETIME ftTimeStamp; + DWORD dwCRC; + WCHAR tszActionMap[MAX_PATH]; +} DIACTIONFORMATW, *LPDIACTIONFORMATW; +typedef const DIACTIONFORMATW *LPCDIACTIONFORMATW; + +DECL_WINELIB_TYPE_AW(DIACTIONFORMAT) +DECL_WINELIB_TYPE_AW(LPDIACTIONFORMAT) +DECL_WINELIB_TYPE_AW(LPCDIACTIONFORMAT) + +#define DIAFTS_NEWDEVICELOW 0xFFFFFFFF +#define DIAFTS_NEWDEVICEHIGH 0xFFFFFFFF +#define DIAFTS_UNUSEDDEVICELOW 0x00000000 +#define DIAFTS_UNUSEDDEVICEHIGH 0x00000000 + +#define DIDBAM_DEFAULT 0x00000000 +#define DIDBAM_PRESERVE 0x00000001 +#define DIDBAM_INITIALIZE 0x00000002 +#define DIDBAM_HWDEFAULTS 0x00000004 + +#define DIDSAM_DEFAULT 0x00000000 +#define DIDSAM_NOUSER 0x00000001 +#define DIDSAM_FORCESAVE 0x00000002 + +#define DICD_DEFAULT 0x00000000 +#define DICD_EDIT 0x00000001 + +#ifndef D3DCOLOR_DEFINED +typedef DWORD D3DCOLOR; +#define D3DCOLOR_DEFINED +#endif + +typedef struct _DICOLORSET { + DWORD dwSize; + D3DCOLOR cTextFore; + D3DCOLOR cTextHighlight; + D3DCOLOR cCalloutLine; + D3DCOLOR cCalloutHighlight; + D3DCOLOR cBorder; + D3DCOLOR cControlFill; + D3DCOLOR cHighlightFill; + D3DCOLOR cAreaFill; +} DICOLORSET, *LPDICOLORSET; +typedef const DICOLORSET *LPCDICOLORSET; + +typedef struct _DICONFIGUREDEVICESPARAMSA { + DWORD dwSize; + DWORD dwcUsers; + LPSTR lptszUserNames; + DWORD dwcFormats; + LPDIACTIONFORMATA lprgFormats; + HWND hwnd; + DICOLORSET dics; + LPUNKNOWN lpUnkDDSTarget; +} DICONFIGUREDEVICESPARAMSA, *LPDICONFIGUREDEVICESPARAMSA; +typedef const DICONFIGUREDEVICESPARAMSA *LPCDICONFIGUREDEVICESPARAMSA; + +typedef struct _DICONFIGUREDEVICESPARAMSW { + DWORD dwSize; + DWORD dwcUsers; + LPWSTR lptszUserNames; + DWORD dwcFormats; + LPDIACTIONFORMATW lprgFormats; + HWND hwnd; + DICOLORSET dics; + LPUNKNOWN lpUnkDDSTarget; +} DICONFIGUREDEVICESPARAMSW, *LPDICONFIGUREDEVICESPARAMSW; +typedef const DICONFIGUREDEVICESPARAMSW *LPCDICONFIGUREDEVICESPARAMSW; + +DECL_WINELIB_TYPE_AW(DICONFIGUREDEVICESPARAMS) +DECL_WINELIB_TYPE_AW(LPDICONFIGUREDEVICESPARAMS) +DECL_WINELIB_TYPE_AW(LPCDICONFIGUREDEVICESPARAMS) + +#define DIDIFT_CONFIGURATION 0x00000001 +#define DIDIFT_OVERLAY 0x00000002 + +#define DIDAL_CENTERED 0x00000000 +#define DIDAL_LEFTALIGNED 0x00000001 +#define DIDAL_RIGHTALIGNED 0x00000002 +#define DIDAL_MIDDLE 0x00000000 +#define DIDAL_TOPALIGNED 0x00000004 +#define DIDAL_BOTTOMALIGNED 0x00000008 + +typedef struct _DIDEVICEIMAGEINFOA { + CHAR tszImagePath[MAX_PATH]; + DWORD dwFlags; + DWORD dwViewID; + RECT rcOverlay; + DWORD dwObjID; + DWORD dwcValidPts; + POINT rgptCalloutLine[5]; + RECT rcCalloutRect; + DWORD dwTextAlign; +} DIDEVICEIMAGEINFOA, *LPDIDEVICEIMAGEINFOA; +typedef const DIDEVICEIMAGEINFOA *LPCDIDEVICEIMAGEINFOA; + +typedef struct _DIDEVICEIMAGEINFOW { + WCHAR tszImagePath[MAX_PATH]; + DWORD dwFlags; + DWORD dwViewID; + RECT rcOverlay; + DWORD dwObjID; + DWORD dwcValidPts; + POINT rgptCalloutLine[5]; + RECT rcCalloutRect; + DWORD dwTextAlign; +} DIDEVICEIMAGEINFOW, *LPDIDEVICEIMAGEINFOW; +typedef const DIDEVICEIMAGEINFOW *LPCDIDEVICEIMAGEINFOW; + +DECL_WINELIB_TYPE_AW(DIDEVICEIMAGEINFO) +DECL_WINELIB_TYPE_AW(LPDIDEVICEIMAGEINFO) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEIMAGEINFO) + +typedef struct _DIDEVICEIMAGEINFOHEADERA { + DWORD dwSize; + DWORD dwSizeImageInfo; + DWORD dwcViews; + DWORD dwcButtons; + DWORD dwcAxes; + DWORD dwcPOVs; + DWORD dwBufferSize; + DWORD dwBufferUsed; + LPDIDEVICEIMAGEINFOA lprgImageInfoArray; +} DIDEVICEIMAGEINFOHEADERA, *LPDIDEVICEIMAGEINFOHEADERA; +typedef const DIDEVICEIMAGEINFOHEADERA *LPCDIDEVICEIMAGEINFOHEADERA; + +typedef struct _DIDEVICEIMAGEINFOHEADERW { + DWORD dwSize; + DWORD dwSizeImageInfo; + DWORD dwcViews; + DWORD dwcButtons; + DWORD dwcAxes; + DWORD dwcPOVs; + DWORD dwBufferSize; + DWORD dwBufferUsed; + LPDIDEVICEIMAGEINFOW lprgImageInfoArray; +} DIDEVICEIMAGEINFOHEADERW, *LPDIDEVICEIMAGEINFOHEADERW; +typedef const DIDEVICEIMAGEINFOHEADERW *LPCDIDEVICEIMAGEINFOHEADERW; + +DECL_WINELIB_TYPE_AW(DIDEVICEIMAGEINFOHEADER) +DECL_WINELIB_TYPE_AW(LPDIDEVICEIMAGEINFOHEADER) +DECL_WINELIB_TYPE_AW(LPCDIDEVICEIMAGEINFOHEADER) + +#endif /* DI8 */ + + +/***************************************************************************** + * IDirectInputEffect interface + */ +#if (DIRECTINPUT_VERSION >= 0x0500) +#undef INTERFACE +#define INTERFACE IDirectInputEffect +DECLARE_INTERFACE_(IDirectInputEffect,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputEffect methods ***/ + STDMETHOD(Initialize)(THIS_ HINSTANCE, DWORD, REFGUID) PURE; + STDMETHOD(GetEffectGuid)(THIS_ LPGUID) PURE; + STDMETHOD(GetParameters)(THIS_ LPDIEFFECT, DWORD) PURE; + STDMETHOD(SetParameters)(THIS_ LPCDIEFFECT, DWORD) PURE; + STDMETHOD(Start)(THIS_ DWORD, DWORD) PURE; + STDMETHOD(Stop)(THIS) PURE; + STDMETHOD(GetEffectStatus)(THIS_ LPDWORD) PURE; + STDMETHOD(Download)(THIS) PURE; + STDMETHOD(Unload)(THIS) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputEffect_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputEffect_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputEffect_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputEffect methods ***/ +#define IDirectInputEffect_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +#define IDirectInputEffect_GetEffectGuid(p,a) (p)->lpVtbl->GetEffectGuid(p,a) +#define IDirectInputEffect_GetParameters(p,a,b) (p)->lpVtbl->GetParameters(p,a,b) +#define IDirectInputEffect_SetParameters(p,a,b) (p)->lpVtbl->SetParameters(p,a,b) +#define IDirectInputEffect_Start(p,a,b) (p)->lpVtbl->Start(p,a,b) +#define IDirectInputEffect_Stop(p) (p)->lpVtbl->Stop(p) +#define IDirectInputEffect_GetEffectStatus(p,a) (p)->lpVtbl->GetEffectStatus(p,a) +#define IDirectInputEffect_Download(p) (p)->lpVtbl->Download(p) +#define IDirectInputEffect_Unload(p) (p)->lpVtbl->Unload(p) +#define IDirectInputEffect_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#else +/*** IUnknown methods ***/ +#define IDirectInputEffect_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputEffect_AddRef(p) (p)->AddRef() +#define IDirectInputEffect_Release(p) (p)->Release() +/*** IDirectInputEffect methods ***/ +#define IDirectInputEffect_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +#define IDirectInputEffect_GetEffectGuid(p,a) (p)->GetEffectGuid(a) +#define IDirectInputEffect_GetParameters(p,a,b) (p)->GetParameters(a,b) +#define IDirectInputEffect_SetParameters(p,a,b) (p)->SetParameters(a,b) +#define IDirectInputEffect_Start(p,a,b) (p)->Start(a,b) +#define IDirectInputEffect_Stop(p) (p)->Stop() +#define IDirectInputEffect_GetEffectStatus(p,a) (p)->GetEffectStatus(a) +#define IDirectInputEffect_Download(p) (p)->Download() +#define IDirectInputEffect_Unload(p) (p)->Unload() +#define IDirectInputEffect_Escape(p,a) (p)->Escape(a) +#endif + +#endif /* DI5 */ + + +/***************************************************************************** + * IDirectInputDeviceA interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDeviceA +DECLARE_INTERFACE_(IDirectInputDeviceA,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; +}; + +/***************************************************************************** + * IDirectInputDeviceW interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDeviceW +DECLARE_INTERFACE_(IDirectInputDeviceW,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice_AddRef(p) (p)->AddRef() +#define IDirectInputDevice_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice_Acquire(p) (p)->Acquire() +#define IDirectInputDevice_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +#endif + + +#if (DIRECTINPUT_VERSION >= 0x0500) +/***************************************************************************** + * IDirectInputDevice2A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice2A +DECLARE_INTERFACE_(IDirectInputDevice2A,IDirectInputDeviceA) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2A methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; +}; + +/***************************************************************************** + * IDirectInputDevice2W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice2W +DECLARE_INTERFACE_(IDirectInputDevice2W,IDirectInputDeviceW) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2W methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice2_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice2_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice2_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice2_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice2_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice2_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice2_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice2_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice2_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice2_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice2_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice2_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice2_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice2_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice2_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice2_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice2_CreateEffect(p,a,b,c,d) (p)->lpVtbl->CreateEffect(p,a,b,c,d) +#define IDirectInputDevice2_EnumEffects(p,a,b,c) (p)->lpVtbl->EnumEffects(p,a,b,c) +#define IDirectInputDevice2_GetEffectInfo(p,a,b) (p)->lpVtbl->GetEffectInfo(p,a,b) +#define IDirectInputDevice2_GetForceFeedbackState(p,a) (p)->lpVtbl->GetForceFeedbackState(p,a) +#define IDirectInputDevice2_SendForceFeedbackCommand(p,a) (p)->lpVtbl->SendForceFeedbackCommand(p,a) +#define IDirectInputDevice2_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c) +#define IDirectInputDevice2_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#define IDirectInputDevice2_Poll(p) (p)->lpVtbl->Poll(p) +#define IDirectInputDevice2_SendDeviceData(p,a,b,c,d) (p)->lpVtbl->SendDeviceData(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice2_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice2_AddRef(p) (p)->AddRef() +#define IDirectInputDevice2_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice2_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice2_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice2_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice2_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice2_Acquire(p) (p)->Acquire() +#define IDirectInputDevice2_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice2_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice2_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice2_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice2_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice2_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice2_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice2_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice2_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice2_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice2_CreateEffect(p,a,b,c,d) (p)->CreateEffect(a,b,c,d) +#define IDirectInputDevice2_EnumEffects(p,a,b,c) (p)->EnumEffects(a,b,c) +#define IDirectInputDevice2_GetEffectInfo(p,a,b) (p)->GetEffectInfo(a,b) +#define IDirectInputDevice2_GetForceFeedbackState(p,a) (p)->GetForceFeedbackState(a) +#define IDirectInputDevice2_SendForceFeedbackCommand(p,a) (p)->SendForceFeedbackCommand(a) +#define IDirectInputDevice2_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c) +#define IDirectInputDevice2_Escape(p,a) (p)->Escape(a) +#define IDirectInputDevice2_Poll(p) (p)->Poll() +#define IDirectInputDevice2_SendDeviceData(p,a,b,c,d) (p)->SendDeviceData(a,b,c,d) +#endif +#endif /* DI5 */ + +#if DIRECTINPUT_VERSION >= 0x0700 +/***************************************************************************** + * IDirectInputDevice7A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice7A +DECLARE_INTERFACE_(IDirectInputDevice7A,IDirectInputDevice2A) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2A methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7A methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; +}; + +/***************************************************************************** + * IDirectInputDevice7W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice7W +DECLARE_INTERFACE_(IDirectInputDevice7W,IDirectInputDevice2W) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2W methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7W methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCWSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCWSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice7_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice7_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice7_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice7_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice7_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice7_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice7_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice7_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice7_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice7_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice7_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice7_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice7_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice7_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice7_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice7_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice7_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice7_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice7_CreateEffect(p,a,b,c,d) (p)->lpVtbl->CreateEffect(p,a,b,c,d) +#define IDirectInputDevice7_EnumEffects(p,a,b,c) (p)->lpVtbl->EnumEffects(p,a,b,c) +#define IDirectInputDevice7_GetEffectInfo(p,a,b) (p)->lpVtbl->GetEffectInfo(p,a,b) +#define IDirectInputDevice7_GetForceFeedbackState(p,a) (p)->lpVtbl->GetForceFeedbackState(p,a) +#define IDirectInputDevice7_SendForceFeedbackCommand(p,a) (p)->lpVtbl->SendForceFeedbackCommand(p,a) +#define IDirectInputDevice7_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c) +#define IDirectInputDevice7_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#define IDirectInputDevice7_Poll(p) (p)->lpVtbl->Poll(p) +#define IDirectInputDevice7_SendDeviceData(p,a,b,c,d) (p)->lpVtbl->SendDeviceData(p,a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice7_EnumEffectsInFile(p,a,b,c,d) (p)->lpVtbl->EnumEffectsInFile(p,a,b,c,d) +#define IDirectInputDevice7_WriteEffectToFile(p,a,b,c,d) (p)->lpVtbl->WriteEffectToFile(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice7_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice7_AddRef(p) (p)->AddRef() +#define IDirectInputDevice7_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice7_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice7_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice7_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice7_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice7_Acquire(p) (p)->Acquire() +#define IDirectInputDevice7_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice7_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice7_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice7_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice7_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice7_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice7_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice7_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice7_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice7_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice7_CreateEffect(p,a,b,c,d) (p)->CreateEffect(a,b,c,d) +#define IDirectInputDevice7_EnumEffects(p,a,b,c) (p)->EnumEffects(a,b,c) +#define IDirectInputDevice7_GetEffectInfo(p,a,b) (p)->GetEffectInfo(a,b) +#define IDirectInputDevice7_GetForceFeedbackState(p,a) (p)->GetForceFeedbackState(a) +#define IDirectInputDevice7_SendForceFeedbackCommand(p,a) (p)->SendForceFeedbackCommand(a) +#define IDirectInputDevice7_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c) +#define IDirectInputDevice7_Escape(p,a) (p)->Escape(a) +#define IDirectInputDevice7_Poll(p) (p)->Poll() +#define IDirectInputDevice7_SendDeviceData(p,a,b,c,d) (p)->SendDeviceData(a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice7_EnumEffectsInFile(p,a,b,c,d) (p)->EnumEffectsInFile(a,b,c,d) +#define IDirectInputDevice7_WriteEffectToFile(p,a,b,c,d) (p)->WriteEffectToFile(a,b,c,d) +#endif + +#endif /* DI7 */ + +#if DIRECTINPUT_VERSION >= 0x0800 +/***************************************************************************** + * IDirectInputDevice8A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice8A +DECLARE_INTERFACE_(IDirectInputDevice8A,IDirectInputDevice7A) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2A methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7A methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; + /*** IDirectInputDevice8A methods ***/ + STDMETHOD(BuildActionMap)(THIS_ LPDIACTIONFORMATA lpdiaf, LPCSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(SetActionMap)(THIS_ LPDIACTIONFORMATA lpdiaf, LPCSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(GetImageInfo)(THIS_ LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader) PURE; +}; + +/***************************************************************************** + * IDirectInputDevice8W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputDevice8W +DECLARE_INTERFACE_(IDirectInputDevice8W,IDirectInputDevice7W) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE; + /*** IDirectInputDevice2W methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE; + /*** IDirectInputDevice7W methods ***/ + STDMETHOD(EnumEffectsInFile)(THIS_ LPCWSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE; + STDMETHOD(WriteEffectToFile)(THIS_ LPCWSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE; + /*** IDirectInputDevice8W methods ***/ + STDMETHOD(BuildActionMap)(THIS_ LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(SetActionMap)(THIS_ LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) PURE; + STDMETHOD(GetImageInfo)(THIS_ LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInputDevice8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice8_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice8_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice8_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice8_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice8_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice8_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice8_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice8_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice8_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice8_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice8_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice8_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice8_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice8_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice8_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice8_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice8_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice8_CreateEffect(p,a,b,c,d) (p)->lpVtbl->CreateEffect(p,a,b,c,d) +#define IDirectInputDevice8_EnumEffects(p,a,b,c) (p)->lpVtbl->EnumEffects(p,a,b,c) +#define IDirectInputDevice8_GetEffectInfo(p,a,b) (p)->lpVtbl->GetEffectInfo(p,a,b) +#define IDirectInputDevice8_GetForceFeedbackState(p,a) (p)->lpVtbl->GetForceFeedbackState(p,a) +#define IDirectInputDevice8_SendForceFeedbackCommand(p,a) (p)->lpVtbl->SendForceFeedbackCommand(p,a) +#define IDirectInputDevice8_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c) +#define IDirectInputDevice8_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#define IDirectInputDevice8_Poll(p) (p)->lpVtbl->Poll(p) +#define IDirectInputDevice8_SendDeviceData(p,a,b,c,d) (p)->lpVtbl->SendDeviceData(p,a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice8_EnumEffectsInFile(p,a,b,c,d) (p)->lpVtbl->EnumEffectsInFile(p,a,b,c,d) +#define IDirectInputDevice8_WriteEffectToFile(p,a,b,c,d) (p)->lpVtbl->WriteEffectToFile(p,a,b,c,d) +/*** IDirectInputDevice8 methods ***/ +#define IDirectInputDevice8_BuildActionMap(p,a,b,c) (p)->lpVtbl->BuildActionMap(p,a,b,c) +#define IDirectInputDevice8_SetActionMap(p,a,b,c) (p)->lpVtbl->SetActionMap(p,a,b,c) +#define IDirectInputDevice8_GetImageInfo(p,a) (p)->lpVtbl->GetImageInfo(p,a) +#else +/*** IUnknown methods ***/ +#define IDirectInputDevice8_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice8_AddRef(p) (p)->AddRef() +#define IDirectInputDevice8_Release(p) (p)->Release() +/*** IDirectInputDevice methods ***/ +#define IDirectInputDevice8_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice8_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice8_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice8_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice8_Acquire(p) (p)->Acquire() +#define IDirectInputDevice8_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice8_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice8_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice8_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice8_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice8_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice8_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice8_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice8_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice8_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +/*** IDirectInputDevice2 methods ***/ +#define IDirectInputDevice8_CreateEffect(p,a,b,c,d) (p)->CreateEffect(a,b,c,d) +#define IDirectInputDevice8_EnumEffects(p,a,b,c) (p)->EnumEffects(a,b,c) +#define IDirectInputDevice8_GetEffectInfo(p,a,b) (p)->GetEffectInfo(a,b) +#define IDirectInputDevice8_GetForceFeedbackState(p,a) (p)->GetForceFeedbackState(a) +#define IDirectInputDevice8_SendForceFeedbackCommand(p,a) (p)->SendForceFeedbackCommand(a) +#define IDirectInputDevice8_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c) +#define IDirectInputDevice8_Escape(p,a) (p)->Escape(a) +#define IDirectInputDevice8_Poll(p) (p)->Poll() +#define IDirectInputDevice8_SendDeviceData(p,a,b,c,d) (p)->SendDeviceData(a,b,c,d) +/*** IDirectInputDevice7 methods ***/ +#define IDirectInputDevice8_EnumEffectsInFile(p,a,b,c,d) (p)->EnumEffectsInFile(a,b,c,d) +#define IDirectInputDevice8_WriteEffectToFile(p,a,b,c,d) (p)->WriteEffectToFile(a,b,c,d) +/*** IDirectInputDevice8 methods ***/ +#define IDirectInputDevice8_BuildActionMap(p,a,b,c) (p)->BuildActionMap(a,b,c) +#define IDirectInputDevice8_SetActionMap(p,a,b,c) (p)->SetActionMap(a,b,c) +#define IDirectInputDevice8_GetImageInfo(p,a) (p)->GetImageInfo(a) +#endif + +#endif /* DI8 */ + +/* "Standard" Mouse report... */ +typedef struct DIMOUSESTATE { + LONG lX; + LONG lY; + LONG lZ; + BYTE rgbButtons[4]; +} DIMOUSESTATE; + +#if DIRECTINPUT_VERSION >= 0x0700 +/* "Standard" Mouse report for DInput 7... */ +typedef struct DIMOUSESTATE2 { + LONG lX; + LONG lY; + LONG lZ; + BYTE rgbButtons[8]; +} DIMOUSESTATE2; +#endif /* DI7 */ + +#define DIMOFS_X FIELD_OFFSET(DIMOUSESTATE, lX) +#define DIMOFS_Y FIELD_OFFSET(DIMOUSESTATE, lY) +#define DIMOFS_Z FIELD_OFFSET(DIMOUSESTATE, lZ) +#define DIMOFS_BUTTON0 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 0) +#define DIMOFS_BUTTON1 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 1) +#define DIMOFS_BUTTON2 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 2) +#define DIMOFS_BUTTON3 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 3) +#if DIRECTINPUT_VERSION >= 0x0700 +#define DIMOFS_BUTTON4 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 4) +#define DIMOFS_BUTTON5 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 5) +#define DIMOFS_BUTTON6 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 6) +#define DIMOFS_BUTTON7 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 7) +#endif /* DI7 */ + +#ifdef __cplusplus +extern "C" { +#endif +extern const DIDATAFORMAT c_dfDIMouse; +#if DIRECTINPUT_VERSION >= 0x0700 +extern const DIDATAFORMAT c_dfDIMouse2; /* DX 7 */ +#endif /* DI7 */ +extern const DIDATAFORMAT c_dfDIKeyboard; +#if DIRECTINPUT_VERSION >= 0x0500 +extern const DIDATAFORMAT c_dfDIJoystick; +extern const DIDATAFORMAT c_dfDIJoystick2; +#endif /* DI5 */ +#ifdef __cplusplus +}; +#endif + +/***************************************************************************** + * IDirectInputA interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputA +DECLARE_INTERFACE_(IDirectInputA,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputA methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; +}; + +/***************************************************************************** + * IDirectInputW interface + */ +#undef INTERFACE +#define INTERFACE IDirectInputW +DECLARE_INTERFACE_(IDirectInputW,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputW methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput methods ***/ +#define IDirectInput_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#else +/*** IUnknown methods ***/ +#define IDirectInput_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput_AddRef(p) (p)->AddRef() +#define IDirectInput_Release(p) (p)->Release() +/*** IDirectInput methods ***/ +#define IDirectInput_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput_Initialize(p,a,b) (p)->Initialize(a,b) +#endif + +/***************************************************************************** + * IDirectInput2A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput2A +DECLARE_INTERFACE_(IDirectInput2A,IDirectInputA) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputA methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2A methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE; +}; + +/***************************************************************************** + * IDirectInput2W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput2W +DECLARE_INTERFACE_(IDirectInput2W,IDirectInputW) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputW methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2W methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput2_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput methods ***/ +#define IDirectInput2_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput2_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput2_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput2_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput2_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput2_FindDevice(p,a,b,c) (p)->lpVtbl->FindDevice(p,a,b,c) +#else +/*** IUnknown methods ***/ +#define IDirectInput2_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput2_AddRef(p) (p)->AddRef() +#define IDirectInput2_Release(p) (p)->Release() +/*** IDirectInput methods ***/ +#define IDirectInput2_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput2_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput2_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput2_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput2_Initialize(p,a,b) (p)->Initialize(a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput2_FindDevice(p,a,b,c) (p)->FindDevice(a,b,c) +#endif + +/***************************************************************************** + * IDirectInput7A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput7A +DECLARE_INTERFACE_(IDirectInput7A,IDirectInput2A) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputA methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2A methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE; + /*** IDirectInput7A methods ***/ + STDMETHOD(CreateDeviceEx)(THIS_ REFGUID rguid, REFIID riid, LPVOID *pvOut, LPUNKNOWN lpUnknownOuter) PURE; +}; + +/***************************************************************************** + * IDirectInput7W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput7W +DECLARE_INTERFACE_(IDirectInput7W,IDirectInput2W) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInputW methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + /*** IDirectInput2W methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE; + /*** IDirectInput7W methods ***/ + STDMETHOD(CreateDeviceEx)(THIS_ REFGUID rguid, REFIID riid, LPVOID *pvOut, LPUNKNOWN lpUnknownOuter) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput7_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput7_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput7_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput methods ***/ +#define IDirectInput7_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput7_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput7_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput7_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput7_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput7_FindDevice(p,a,b,c) (p)->lpVtbl->FindDevice(p,a,b,c) +/*** IDirectInput7 methods ***/ +#define IDirectInput7_CreateDeviceEx(p,a,b,c,d) (p)->lpVtbl->CreateDeviceEx(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInput7_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput7_AddRef(p) (p)->AddRef() +#define IDirectInput7_Release(p) (p)->Release() +/*** IDirectInput methods ***/ +#define IDirectInput7_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput7_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput7_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput7_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput7_Initialize(p,a,b) (p)->Initialize(a,b) +/*** IDirectInput2 methods ***/ +#define IDirectInput7_FindDevice(p,a,b,c) (p)->FindDevice(a,b,c) +/*** IDirectInput7 methods ***/ +#define IDirectInput7_CreateDeviceEx(p,a,b,c,d) (p)->CreateDeviceEx(a,b,c,d) +#endif + + +#if DIRECTINPUT_VERSION >= 0x0800 +/***************************************************************************** + * IDirectInput8A interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput8A +DECLARE_INTERFACE_(IDirectInput8A,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInput8A methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICE8A *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE; + STDMETHOD(EnumDevicesBySemantics)(THIS_ LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat, LPDIENUMDEVICESBYSEMANTICSCBA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(ConfigureDevices)(THIS_ LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) PURE; +}; + +/***************************************************************************** + * IDirectInput8W interface + */ +#undef INTERFACE +#define INTERFACE IDirectInput8W +DECLARE_INTERFACE_(IDirectInput8W,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectInput8W methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE; + STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE; + STDMETHOD(EnumDevicesBySemantics)(THIS_ LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat, LPDIENUMDEVICESBYSEMANTICSCBW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE; + STDMETHOD(ConfigureDevices)(THIS_ LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) PURE; +}; +#undef INTERFACE + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectInput8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput8_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput8_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectInput8 methods ***/ +#define IDirectInput8_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput8_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput8_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput8_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput8_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectInput8_FindDevice(p,a,b,c) (p)->lpVtbl->FindDevice(p,a,b,c) +#define IDirectInput8_EnumDevicesBySemantics(p,a,b,c,d,e) (p)->lpVtbl->EnumDevicesBySemantics(p,a,b,c,d,e) +#define IDirectInput8_ConfigureDevices(p,a,b,c,d) (p)->lpVtbl->ConfigureDevices(p,a,b,c,d) +#else +/*** IUnknown methods ***/ +#define IDirectInput8_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput8_AddRef(p) (p)->AddRef() +#define IDirectInput8_Release(p) (p)->Release() +/*** IDirectInput8 methods ***/ +#define IDirectInput8_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput8_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput8_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput8_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput8_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectInput8_FindDevice(p,a,b,c) (p)->FindDevice(a,b,c) +#define IDirectInput8_EnumDevicesBySemantics(p,a,b,c,d,e) (p)->EnumDevicesBySemantics(a,b,c,d,e) +#define IDirectInput8_ConfigureDevices(p,a,b,c,d) (p)->ConfigureDevices(a,b,c,d) +#endif + +#endif /* DI8 */ + +/* Export functions */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if DIRECTINPUT_VERSION >= 0x0800 +HRESULT WINAPI DirectInput8Create(HINSTANCE,DWORD,REFIID,LPVOID *,LPUNKNOWN); +#else /* DI < 8 */ +HRESULT WINAPI DirectInputCreateA(HINSTANCE,DWORD,LPDIRECTINPUTA *,LPUNKNOWN); +HRESULT WINAPI DirectInputCreateW(HINSTANCE,DWORD,LPDIRECTINPUTW *,LPUNKNOWN); +#define DirectInputCreate WINELIB_NAME_AW(DirectInputCreate) + +HRESULT WINAPI DirectInputCreateEx(HINSTANCE,DWORD,REFIID,LPVOID *,LPUNKNOWN); +#endif /* DI8 */ + +#ifdef __cplusplus +}; +#endif + +#endif /* __DINPUT_INCLUDED__ */ diff --git a/src/external/glfw/deps/mingw/xinput.h b/src/external/glfw/deps/mingw/xinput.h new file mode 100644 index 00000000..d3ca726c --- /dev/null +++ b/src/external/glfw/deps/mingw/xinput.h @@ -0,0 +1,239 @@ +/* + * The Wine project - Xinput Joystick Library + * Copyright 2008 Andrew Fenn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_XINPUT_H +#define __WINE_XINPUT_H + +#include + +/* + * Bitmasks for the joysticks buttons, determines what has + * been pressed on the joystick, these need to be mapped + * to whatever device you're using instead of an xbox 360 + * joystick + */ + +#define XINPUT_GAMEPAD_DPAD_UP 0x0001 +#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002 +#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004 +#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 +#define XINPUT_GAMEPAD_START 0x0010 +#define XINPUT_GAMEPAD_BACK 0x0020 +#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 +#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 +#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 +#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 +#define XINPUT_GAMEPAD_A 0x1000 +#define XINPUT_GAMEPAD_B 0x2000 +#define XINPUT_GAMEPAD_X 0x4000 +#define XINPUT_GAMEPAD_Y 0x8000 + +/* + * Defines the flags used to determine if the user is pushing + * down on a button, not holding a button, etc + */ + +#define XINPUT_KEYSTROKE_KEYDOWN 0x0001 +#define XINPUT_KEYSTROKE_KEYUP 0x0002 +#define XINPUT_KEYSTROKE_REPEAT 0x0004 + +/* + * Defines the codes which are returned by XInputGetKeystroke + */ + +#define VK_PAD_A 0x5800 +#define VK_PAD_B 0x5801 +#define VK_PAD_X 0x5802 +#define VK_PAD_Y 0x5803 +#define VK_PAD_RSHOULDER 0x5804 +#define VK_PAD_LSHOULDER 0x5805 +#define VK_PAD_LTRIGGER 0x5806 +#define VK_PAD_RTRIGGER 0x5807 +#define VK_PAD_DPAD_UP 0x5810 +#define VK_PAD_DPAD_DOWN 0x5811 +#define VK_PAD_DPAD_LEFT 0x5812 +#define VK_PAD_DPAD_RIGHT 0x5813 +#define VK_PAD_START 0x5814 +#define VK_PAD_BACK 0x5815 +#define VK_PAD_LTHUMB_PRESS 0x5816 +#define VK_PAD_RTHUMB_PRESS 0x5817 +#define VK_PAD_LTHUMB_UP 0x5820 +#define VK_PAD_LTHUMB_DOWN 0x5821 +#define VK_PAD_LTHUMB_RIGHT 0x5822 +#define VK_PAD_LTHUMB_LEFT 0x5823 +#define VK_PAD_LTHUMB_UPLEFT 0x5824 +#define VK_PAD_LTHUMB_UPRIGHT 0x5825 +#define VK_PAD_LTHUMB_DOWNRIGHT 0x5826 +#define VK_PAD_LTHUMB_DOWNLEFT 0x5827 +#define VK_PAD_RTHUMB_UP 0x5830 +#define VK_PAD_RTHUMB_DOWN 0x5831 +#define VK_PAD_RTHUMB_RIGHT 0x5832 +#define VK_PAD_RTHUMB_LEFT 0x5833 +#define VK_PAD_RTHUMB_UPLEFT 0x5834 +#define VK_PAD_RTHUMB_UPRIGHT 0x5835 +#define VK_PAD_RTHUMB_DOWNRIGHT 0x5836 +#define VK_PAD_RTHUMB_DOWNLEFT 0x5837 + +/* + * Deadzones are for analogue joystick controls on the joypad + * which determine when input should be assumed to be in the + * middle of the pad. This is a threshold to stop a joypad + * controlling the game when the player isn't touching the + * controls. + */ + +#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 +#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 +#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30 + + +/* + * Defines what type of abilities the type of joystick has + * DEVTYPE_GAMEPAD is available for all joysticks, however + * there may be more specific identifiers for other joysticks + * which are being used. + */ + +#define XINPUT_DEVTYPE_GAMEPAD 0x01 +#define XINPUT_DEVSUBTYPE_GAMEPAD 0x01 +#define XINPUT_DEVSUBTYPE_WHEEL 0x02 +#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03 +#define XINPUT_DEVSUBTYPE_FLIGHT_SICK 0x04 +#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05 +#define XINPUT_DEVSUBTYPE_GUITAR 0x06 +#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08 + +/* + * These are used with the XInputGetCapabilities function to + * determine the abilities to the joystick which has been + * plugged in. + */ + +#define XINPUT_CAPS_VOICE_SUPPORTED 0x0004 +#define XINPUT_FLAG_GAMEPAD 0x00000001 + +/* + * Defines the status of the battery if one is used in the + * attached joystick. The first two define if the joystick + * supports a battery. Disconnected means that the joystick + * isn't connected. Wired shows that the joystick is a wired + * joystick. + */ + +#define BATTERY_DEVTYPE_GAMEPAD 0x00 +#define BATTERY_DEVTYPE_HEADSET 0x01 +#define BATTERY_TYPE_DISCONNECTED 0x00 +#define BATTERY_TYPE_WIRED 0x01 +#define BATTERY_TYPE_ALKALINE 0x02 +#define BATTERY_TYPE_NIMH 0x03 +#define BATTERY_TYPE_UNKNOWN 0xFF +#define BATTERY_LEVEL_EMPTY 0x00 +#define BATTERY_LEVEL_LOW 0x01 +#define BATTERY_LEVEL_MEDIUM 0x02 +#define BATTERY_LEVEL_FULL 0x03 + +/* + * How many joysticks can be used with this library. Games that + * use the xinput library will not go over this number. + */ + +#define XUSER_MAX_COUNT 4 +#define XUSER_INDEX_ANY 0x000000FF + +/* + * Defines the structure of an xbox 360 joystick. + */ + +typedef struct _XINPUT_GAMEPAD { + WORD wButtons; + BYTE bLeftTrigger; + BYTE bRightTrigger; + SHORT sThumbLX; + SHORT sThumbLY; + SHORT sThumbRX; + SHORT sThumbRY; +} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD; + +typedef struct _XINPUT_STATE { + DWORD dwPacketNumber; + XINPUT_GAMEPAD Gamepad; +} XINPUT_STATE, *PXINPUT_STATE; + +/* + * Defines the structure of how much vibration is set on both the + * right and left motors in a joystick. If you're not using a 360 + * joystick you will have to map these to your device. + */ + +typedef struct _XINPUT_VIBRATION { + WORD wLeftMotorSpeed; + WORD wRightMotorSpeed; +} XINPUT_VIBRATION, *PXINPUT_VIBRATION; + +/* + * Defines the structure for what kind of abilities the joystick has + * such abilities are things such as if the joystick has the ability + * to send and receive audio, if the joystick is in fact a driving + * wheel or perhaps if the joystick is some kind of dance pad or + * guitar. + */ + +typedef struct _XINPUT_CAPABILITIES { + BYTE Type; + BYTE SubType; + WORD Flags; + XINPUT_GAMEPAD Gamepad; + XINPUT_VIBRATION Vibration; +} XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES; + +/* + * Defines the structure for a joystick input event which is + * retrieved using the function XInputGetKeystroke + */ +typedef struct _XINPUT_KEYSTROKE { + WORD VirtualKey; + WCHAR Unicode; + WORD Flags; + BYTE UserIndex; + BYTE HidCode; +} XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE; + +typedef struct _XINPUT_BATTERY_INFORMATION +{ + BYTE BatteryType; + BYTE BatteryLevel; +} XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION; + +#ifdef __cplusplus +extern "C" { +#endif + +void WINAPI XInputEnable(WINBOOL); +DWORD WINAPI XInputSetState(DWORD, XINPUT_VIBRATION*); +DWORD WINAPI XInputGetState(DWORD, XINPUT_STATE*); +DWORD WINAPI XInputGetKeystroke(DWORD, DWORD, PXINPUT_KEYSTROKE); +DWORD WINAPI XInputGetCapabilities(DWORD, DWORD, XINPUT_CAPABILITIES*); +DWORD WINAPI XInputGetDSoundAudioDeviceGuids(DWORD, GUID*, GUID*); +DWORD WINAPI XInputGetBatteryInformation(DWORD, BYTE, XINPUT_BATTERY_INFORMATION*); + +#ifdef __cplusplus +} +#endif + +#endif /* __WINE_XINPUT_H */ diff --git a/src/external/glfw/deps/nuklear.h b/src/external/glfw/deps/nuklear.h new file mode 100644 index 00000000..333acee7 --- /dev/null +++ b/src/external/glfw/deps/nuklear.h @@ -0,0 +1,23590 @@ +/* + Nuklear - 1.40.0 - public domain + no warrenty implied; use at your own risk. + authored from 2015-2017 by Micha Mettke + +ABOUT: + This is a minimal state graphical user interface single header toolkit + written in ANSI C and licensed under public domain. + It was designed as a simple embeddable user interface for application and does + not have any dependencies, a default renderbackend or OS window and input handling + but instead provides a very modular library approach by using simple input state + for input and draw commands describing primitive shapes as output. + So instead of providing a layered library that tries to abstract over a number + of platform and render backends it only focuses on the actual UI. + +VALUES: + - Graphical user interface toolkit + - Single header library + - Written in C89 (a.k.a. ANSI C or ISO C90) + - Small codebase (~17kLOC) + - Focus on portability, efficiency and simplicity + - No dependencies (not even the standard library if not wanted) + - Fully skinnable and customizable + - Low memory footprint with total memory control if needed or wanted + - UTF-8 support + - No global or hidden state + - Customizable library modules (you can compile and use only what you need) + - Optional font baker and vertex buffer output + +USAGE: + This library is self contained in one single header file and can be used either + in header only mode or in implementation mode. The header only mode is used + by default when included and allows including this header in other headers + and does not contain the actual implementation. + + The implementation mode requires to define the preprocessor macro + NK_IMPLEMENTATION in *one* .c/.cpp file before #includeing this file, e.g.: + + #define NK_IMPLEMENTATION + #include "nuklear.h" + + Also optionally define the symbols listed in the section "OPTIONAL DEFINES" + below in header and implementation mode if you want to use additional functionality + or need more control over the library. + IMPORTANT: Every time you include "nuklear.h" you have to define the same flags. + This is very important not doing it either leads to compiler errors + or even worse stack corruptions. + +FEATURES: + - Absolutely no platform dependend code + - Memory management control ranging from/to + - Ease of use by allocating everything from standard library + - Control every byte of memory inside the library + - Font handling control ranging from/to + - Use your own font implementation for everything + - Use this libraries internal font baking and handling API + - Drawing output control ranging from/to + - Simple shapes for more high level APIs which already have drawing capabilities + - Hardware accessible anti-aliased vertex buffer output + - Customizable colors and properties ranging from/to + - Simple changes to color by filling a simple color table + - Complete control with ability to use skinning to decorate widgets + - Bendable UI library with widget ranging from/to + - Basic widgets like buttons, checkboxes, slider, ... + - Advanced widget like abstract comboboxes, contextual menus,... + - Compile time configuration to only compile what you need + - Subset which can be used if you do not want to link or use the standard library + - Can be easily modified to only update on user input instead of frame updates + +OPTIONAL DEFINES: + NK_PRIVATE + If defined declares all functions as static, so they can only be accessed + inside the file that contains the implementation + + NK_INCLUDE_FIXED_TYPES + If defined it will include header for fixed sized types + otherwise nuklear tries to select the correct type. If that fails it will + throw a compiler error and you have to select the correct types yourself. + If used needs to be defined for implementation and header + + NK_INCLUDE_DEFAULT_ALLOCATOR + if defined it will include header and provide additional functions + to use this library without caring for memory allocation control and therefore + ease memory management. + Adds the standard library with malloc and free so don't define if you + don't want to link to the standard library + If used needs to be defined for implementation and header + + NK_INCLUDE_STANDARD_IO + if defined it will include header and provide + additional functions depending on file loading. + Adds the standard library with fopen, fclose,... so don't define this + if you don't want to link to the standard library + If used needs to be defined for implementation and header + + NK_INCLUDE_STANDARD_VARARGS + if defined it will include header and provide + additional functions depending on variable arguments + Adds the standard library with va_list and so don't define this if + you don't want to link to the standard library + If used needs to be defined for implementation and header + + NK_INCLUDE_VERTEX_BUFFER_OUTPUT + Defining this adds a vertex draw command list backend to this + library, which allows you to convert queue commands into vertex draw commands. + This is mainly if you need a hardware accessible format for OpenGL, DirectX, + Vulkan, Metal,... + If used needs to be defined for implementation and header + + NK_INCLUDE_FONT_BAKING + Defining this adds `stb_truetype` and `stb_rect_pack` implementation + to this library and provides font baking and rendering. + If you already have font handling or do not want to use this font handler + you don't have to define it. + If used needs to be defined for implementation and header + + NK_INCLUDE_DEFAULT_FONT + Defining this adds the default font: ProggyClean.ttf into this library + which can be loaded into a font atlas and allows using this library without + having a truetype font + Enabling this adds ~12kb to global stack memory + If used needs to be defined for implementation and header + + NK_INCLUDE_COMMAND_USERDATA + Defining this adds a userdata pointer into each command. Can be useful for + example if you want to provide custom shaders depending on the used widget. + Can be combined with the style structures. + If used needs to be defined for implementation and header + + NK_BUTTON_TRIGGER_ON_RELEASE + Different platforms require button clicks occuring either on buttons being + pressed (up to down) or released (down to up). + By default this library will react on buttons being pressed, but if you + define this it will only trigger if a button is released. + If used it is only required to be defined for the implementation part + + NK_ZERO_COMMAND_MEMORY + Defining this will zero out memory for each drawing command added to a + drawing queue (inside nk_command_buffer_push). Zeroing command memory + is very useful for fast checking (using memcmp) if command buffers are + equal and avoid drawing frames when nothing on screen has changed since + previous frame. + + NK_ASSERT + If you don't define this, nuklear will use with assert(). + Adds the standard library so define to nothing of not wanted + If used needs to be defined for implementation and header + + NK_BUFFER_DEFAULT_INITIAL_SIZE + Initial buffer size allocated by all buffers while using the default allocator + functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't + want to allocate the default 4k memory then redefine it. + If used needs to be defined for implementation and header + + NK_MAX_NUMBER_BUFFER + Maximum buffer size for the conversion buffer between float and string + Under normal circumstances this should be more than sufficient. + If used needs to be defined for implementation and header + + NK_INPUT_MAX + Defines the max number of bytes which can be added as text input in one frame. + Under normal circumstances this should be more than sufficient. + If used it is only required to be defined for the implementation part + + NK_MEMSET + You can define this to 'memset' or your own memset implementation + replacement. If not nuklear will use its own version. + If used it is only required to be defined for the implementation part + + NK_MEMCPY + You can define this to 'memcpy' or your own memcpy implementation + replacement. If not nuklear will use its own version. + If used it is only required to be defined for the implementation part + + NK_SQRT + You can define this to 'sqrt' or your own sqrt implementation + replacement. If not nuklear will use its own slow and not highly + accurate version. + If used it is only required to be defined for the implementation part + + NK_SIN + You can define this to 'sinf' or your own sine implementation + replacement. If not nuklear will use its own approximation implementation. + If used it is only required to be defined for the implementation part + + NK_COS + You can define this to 'cosf' or your own cosine implementation + replacement. If not nuklear will use its own approximation implementation. + If used it is only required to be defined for the implementation part + + NK_STRTOD + You can define this to `strtod` or your own string to double conversion + implementation replacement. If not defined nuklear will use its own + imprecise and possibly unsafe version (does not handle nan or infinity!). + If used it is only required to be defined for the implementation part + + NK_DTOA + You can define this to `dtoa` or your own double to string conversion + implementation replacement. If not defined nuklear will use its own + imprecise and possibly unsafe version (does not handle nan or infinity!). + If used it is only required to be defined for the implementation part + + NK_VSNPRINTF + If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` + and want to be safe define this to `vsnprintf` on compilers supporting + later versions of C or C++. By default nuklear will check for your stdlib version + in C as well as compiler version in C++. if `vsnprintf` is available + it will define it to `vsnprintf` directly. If not defined and if you have + older versions of C or C++ it will be defined to `vsprintf` which is unsafe. + If used it is only required to be defined for the implementation part + + NK_BYTE + NK_INT16 + NK_UINT16 + NK_INT32 + NK_UINT32 + NK_SIZE_TYPE + NK_POINTER_TYPE + If you compile without NK_USE_FIXED_TYPE then a number of standard types + will be selected and compile time validated. If they are incorrect you can + define the correct types by overloading these type defines. + +CREDITS: + Developed by Micha Mettke and every direct or indirect contributor. + + Embeds stb_texedit, stb_truetype and stb_rectpack by Sean Barret (public domain) + Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license). + + Big thank you to Omar Cornut (ocornut@github) for his imgui library and + giving me the inspiration for this library, Casey Muratori for handmade hero + and his original immediate mode graphical user interface idea and Sean + Barret for his amazing single header libraries which restored my faith + in libraries and brought me to create some of my own. + +LICENSE: + This software is dual-licensed to the public domain and under the following + license: you are granted a perpetual, irrevocable license to copy, modify, + publish and distribute this file as you see fit. +*/ +#ifndef NK_NUKLEAR_H_ +#define NK_NUKLEAR_H_ + +#ifdef __cplusplus +extern "C" { +#endif +/* + * ============================================================== + * + * CONSTANTS + * + * =============================================================== + */ +#define NK_UNDEFINED (-1.0f) +#define NK_UTF_INVALID 0xFFFD /* internal invalid utf8 rune */ +#define NK_UTF_SIZE 4 /* describes the number of bytes a glyph consists of*/ +#ifndef NK_INPUT_MAX +#define NK_INPUT_MAX 16 +#endif +#ifndef NK_MAX_NUMBER_BUFFER +#define NK_MAX_NUMBER_BUFFER 64 +#endif +#ifndef NK_SCROLLBAR_HIDING_TIMEOUT +#define NK_SCROLLBAR_HIDING_TIMEOUT 4.0f +#endif +/* + * ============================================================== + * + * HELPER + * + * =============================================================== + */ +#ifndef NK_API + #ifdef NK_PRIVATE + #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199409L)) + #define NK_API static inline + #elif defined(__cplusplus) + #define NK_API static inline + #else + #define NK_API static + #endif + #else + #define NK_API extern + #endif +#endif + +#define NK_INTERN static +#define NK_STORAGE static +#define NK_GLOBAL static + +#define NK_FLAG(x) (1 << (x)) +#define NK_STRINGIFY(x) #x +#define NK_MACRO_STRINGIFY(x) NK_STRINGIFY(x) +#define NK_STRING_JOIN_IMMEDIATE(arg1, arg2) arg1 ## arg2 +#define NK_STRING_JOIN_DELAY(arg1, arg2) NK_STRING_JOIN_IMMEDIATE(arg1, arg2) +#define NK_STRING_JOIN(arg1, arg2) NK_STRING_JOIN_DELAY(arg1, arg2) + +#ifdef _MSC_VER +#define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__COUNTER__) +#else +#define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__LINE__) +#endif + +#ifndef NK_STATIC_ASSERT +#define NK_STATIC_ASSERT(exp) typedef char NK_UNIQUE_NAME(_dummy_array)[(exp)?1:-1] +#endif + +#ifndef NK_FILE_LINE +#ifdef _MSC_VER +#define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__COUNTER__) +#else +#define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__LINE__) +#endif +#endif + +#define NK_MIN(a,b) ((a) < (b) ? (a) : (b)) +#define NK_MAX(a,b) ((a) < (b) ? (b) : (a)) +#define NK_CLAMP(i,v,x) (NK_MAX(NK_MIN(v,x), i)) +/* + * =============================================================== + * + * BASIC + * + * =============================================================== + */ +#ifdef NK_INCLUDE_FIXED_TYPES + #include + #define NK_INT8 int8_t + #define NK_UINT8 uint8_t + #define NK_INT16 int16_t + #define NK_UINT16 uint16_t + #define NK_INT32 int32_t + #define NK_UINT32 uint32_t + #define NK_SIZE_TYPE uintptr_t + #define NK_POINTER_TYPE uintptr_t +#else + #ifndef NK_INT8 + #define NK_INT8 char + #endif + #ifndef NK_UINT8 + #define NK_UINT8 unsigned char + #endif + #ifndef NK_INT16 + #define NK_INT16 signed short + #endif + #ifndef NK_UINT16 + #define NK_UINT16 unsigned short + #endif + #ifndef NK_INT32 + #if defined(_MSC_VER) + #define NK_INT32 __int32 + #else + #define NK_INT32 signed int + #endif + #endif + #ifndef NK_UINT32 + #if defined(_MSC_VER) + #define NK_UINT32 unsigned __int32 + #else + #define NK_UINT32 unsigned int + #endif + #endif + #ifndef NK_SIZE_TYPE + #if defined(_WIN64) && defined(_MSC_VER) + #define NK_SIZE_TYPE unsigned __int64 + #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) + #define NK_SIZE_TYPE unsigned __int32 + #elif defined(__GNUC__) || defined(__clang__) + #if defined(__x86_64__) || defined(__ppc64__) + #define NK_SIZE_TYPE unsigned long + #else + #define NK_SIZE_TYPE unsigned int + #endif + #else + #define NK_SIZE_TYPE unsigned long + #endif + #endif + #ifndef NK_POINTER_TYPE + #if defined(_WIN64) && defined(_MSC_VER) + #define NK_POINTER_TYPE unsigned __int64 + #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) + #define NK_POINTER_TYPE unsigned __int32 + #elif defined(__GNUC__) || defined(__clang__) + #if defined(__x86_64__) || defined(__ppc64__) + #define NK_POINTER_TYPE unsigned long + #else + #define NK_POINTER_TYPE unsigned int + #endif + #else + #define NK_POINTER_TYPE unsigned long + #endif + #endif +#endif + +typedef NK_INT8 nk_char; +typedef NK_UINT8 nk_uchar; +typedef NK_UINT8 nk_byte; +typedef NK_INT16 nk_short; +typedef NK_UINT16 nk_ushort; +typedef NK_INT32 nk_int; +typedef NK_UINT32 nk_uint; +typedef NK_SIZE_TYPE nk_size; +typedef NK_POINTER_TYPE nk_ptr; + +typedef nk_uint nk_hash; +typedef nk_uint nk_flags; +typedef nk_uint nk_rune; + +/* Make sure correct type size: + * This will fire with a negative subscript error if the type sizes + * are set incorrectly by the compiler, and compile out if not */ +NK_STATIC_ASSERT(sizeof(nk_short) == 2); +NK_STATIC_ASSERT(sizeof(nk_ushort) == 2); +NK_STATIC_ASSERT(sizeof(nk_uint) == 4); +NK_STATIC_ASSERT(sizeof(nk_int) == 4); +NK_STATIC_ASSERT(sizeof(nk_byte) == 1); +NK_STATIC_ASSERT(sizeof(nk_flags) >= 4); +NK_STATIC_ASSERT(sizeof(nk_rune) >= 4); +NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*)); +NK_STATIC_ASSERT(sizeof(nk_ptr) >= sizeof(void*)); + +/* ============================================================================ + * + * API + * + * =========================================================================== */ +struct nk_buffer; +struct nk_allocator; +struct nk_command_buffer; +struct nk_draw_command; +struct nk_convert_config; +struct nk_style_item; +struct nk_text_edit; +struct nk_draw_list; +struct nk_user_font; +struct nk_panel; +struct nk_context; +struct nk_draw_vertex_layout_element; +struct nk_style_button; +struct nk_style_toggle; +struct nk_style_selectable; +struct nk_style_slide; +struct nk_style_progress; +struct nk_style_scrollbar; +struct nk_style_edit; +struct nk_style_property; +struct nk_style_chart; +struct nk_style_combo; +struct nk_style_tab; +struct nk_style_window_header; +struct nk_style_window; + +enum {nk_false, nk_true}; +struct nk_color {nk_byte r,g,b,a;}; +struct nk_colorf {float r,g,b,a;}; +struct nk_vec2 {float x,y;}; +struct nk_vec2i {short x, y;}; +struct nk_rect {float x,y,w,h;}; +struct nk_recti {short x,y,w,h;}; +typedef char nk_glyph[NK_UTF_SIZE]; +typedef union {void *ptr; int id;} nk_handle; +struct nk_image {nk_handle handle;unsigned short w,h;unsigned short region[4];}; +struct nk_cursor {struct nk_image img; struct nk_vec2 size, offset;}; +struct nk_scroll {nk_uint x, y;}; + +enum nk_heading {NK_UP, NK_RIGHT, NK_DOWN, NK_LEFT}; +enum nk_button_behavior {NK_BUTTON_DEFAULT, NK_BUTTON_REPEATER}; +enum nk_modify {NK_FIXED = nk_false, NK_MODIFIABLE = nk_true}; +enum nk_orientation {NK_VERTICAL, NK_HORIZONTAL}; +enum nk_collapse_states {NK_MINIMIZED = nk_false, NK_MAXIMIZED = nk_true}; +enum nk_show_states {NK_HIDDEN = nk_false, NK_SHOWN = nk_true}; +enum nk_chart_type {NK_CHART_LINES, NK_CHART_COLUMN, NK_CHART_MAX}; +enum nk_chart_event {NK_CHART_HOVERING = 0x01, NK_CHART_CLICKED = 0x02}; +enum nk_color_format {NK_RGB, NK_RGBA}; +enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC}; +enum nk_layout_format {NK_DYNAMIC, NK_STATIC}; +enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB}; + +typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size); +typedef void (*nk_plugin_free)(nk_handle, void *old); +typedef int(*nk_plugin_filter)(const struct nk_text_edit*, nk_rune unicode); +typedef void(*nk_plugin_paste)(nk_handle, struct nk_text_edit*); +typedef void(*nk_plugin_copy)(nk_handle, const char*, int len); + +struct nk_allocator { + nk_handle userdata; + nk_plugin_alloc alloc; + nk_plugin_free free; +}; +enum nk_symbol_type { + NK_SYMBOL_NONE, + NK_SYMBOL_X, + NK_SYMBOL_UNDERSCORE, + NK_SYMBOL_CIRCLE_SOLID, + NK_SYMBOL_CIRCLE_OUTLINE, + NK_SYMBOL_RECT_SOLID, + NK_SYMBOL_RECT_OUTLINE, + NK_SYMBOL_TRIANGLE_UP, + NK_SYMBOL_TRIANGLE_DOWN, + NK_SYMBOL_TRIANGLE_LEFT, + NK_SYMBOL_TRIANGLE_RIGHT, + NK_SYMBOL_PLUS, + NK_SYMBOL_MINUS, + NK_SYMBOL_MAX +}; +/* ============================================================================= + * + * CONTEXT + * + * =============================================================================*/ +/* Contexts are the main entry point and the majestro of nuklear and contain all required state. + * They are used for window, memory, input, style, stack, commands and time management and need + * to be passed into all nuklear GUI specific functions. + * + * Usage + * ------------------- + * To use a context it first has to be initialized which can be achieved by calling + * one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`. + * Each takes in a font handle and a specific way of handling memory. Memory control + * hereby ranges from standard library to just specifing a fixed sized block of memory + * which nuklear has to manage itself from. + * + * struct nk_context ctx; + * nk_init_xxx(&ctx, ...); + * while (1) { + * [...] + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * Reference + * ------------------- + * nk_init_default - Initializes context with standard library memory alloction (malloc,free) + * nk_init_fixed - Initializes context from single fixed size memory block + * nk_init - Initializes context with memory allocator callbacks for alloc and free + * nk_init_custom - Initializes context from two buffers. One for draw commands the other for window/panel/table allocations + * nk_clear - Called at the end of the frame to reset and prepare the context for the next frame + * nk_free - Shutdown and free all memory allocated inside the context + * nk_set_user_data - Utility function to pass user data to draw command + */ +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +/* nk_init_default - Initializes a `nk_context` struct with a default standard library allocator. + * Should be used if you don't want to be bothered with memory management in nuklear. + * Parameters: + * @ctx must point to an either stack or heap allocated `nk_context` struct + * @font must point to a previously initialized font handle for more info look at font documentation + * Return values: + * true(1) on success + * false(0) on failure */ +NK_API int nk_init_default(struct nk_context*, const struct nk_user_font*); +#endif +/* nk_init_fixed - Initializes a `nk_context` struct from a single fixed size memory block + * Should be used if you want complete control over nuklears memory management. + * Especially recommended for system with little memory or systems with virtual memory. + * For the later case you can just allocate for example 16MB of virtual memory + * and only the required amount of memory will actually be commited. + * IMPORTANT: make sure the passed memory block is aligned correctly for `nk_draw_commands` + * Parameters: + * @ctx must point to an either stack or heap allocated `nk_context` struct + * @memory must point to a previously allocated memory block + * @size must contain the total size of @memory + * @font must point to a previously initialized font handle for more info look at font documentation + * Return values: + * true(1) on success + * false(0) on failure */ +NK_API int nk_init_fixed(struct nk_context*, void *memory, nk_size size, const struct nk_user_font*); +/* nk_init - Initializes a `nk_context` struct with memory allocation callbacks for nuklear to allocate + * memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation + * interface to nuklear. Can be useful for cases like monitoring memory consumption. + * Parameters: + * @ctx must point to an either stack or heap allocated `nk_context` struct + * @alloc must point to a previously allocated memory allocator + * @font must point to a previously initialized font handle for more info look at font documentation + * Return values: + * true(1) on success + * false(0) on failure */ +NK_API int nk_init(struct nk_context*, struct nk_allocator*, const struct nk_user_font*); +/* nk_init_custom - Initializes a `nk_context` struct from two different either fixed or growing + * buffers. The first buffer is for allocating draw commands while the second buffer is + * used for allocating windows, panels and state tables. + * Parameters: + * @ctx must point to an either stack or heap allocated `nk_context` struct + * @cmds must point to a previously initialized memory buffer either fixed or dynamic to store draw commands into + * @pool must point to a previously initialized memory buffer either fixed or dynamic to store windows, panels and tables + * @font must point to a previously initialized font handle for more info look at font documentation + * Return values: + * true(1) on success + * false(0) on failure */ +NK_API int nk_init_custom(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font*); +/* nk_clear - Resets the context state at the end of the frame. This includes mostly + * garbage collector tasks like removing windows or table not called and therefore + * used anymore. + * Parameters: + * @ctx must point to a previously initialized `nk_context` struct */ +NK_API void nk_clear(struct nk_context*); +/* nk_free - Frees all memory allocated by nuklear. Not needed if context was + * initialized with `nk_init_fixed`. + * Parameters: + * @ctx must point to a previously initialized `nk_context` struct */ +NK_API void nk_free(struct nk_context*); +#ifdef NK_INCLUDE_COMMAND_USERDATA +/* nk_set_user_data - Sets the currently passed userdata passed down into each draw command. + * Parameters: + * @ctx must point to a previously initialized `nk_context` struct + * @data handle with either pointer or index to be passed into every draw commands */ +NK_API void nk_set_user_data(struct nk_context*, nk_handle handle); +#endif +/* ============================================================================= + * + * INPUT + * + * =============================================================================*/ +/* The input API is responsible for holding the current input state composed of + * mouse, key and text input states. + * It is worth noting that no direct os or window handling is done in nuklear. + * Instead all input state has to be provided by platform specific code. This in one hand + * expects more work from the user and complicates usage but on the other hand + * provides simple abstraction over a big number of platforms, libraries and other + * already provided functionality. + * + * Usage + * ------------------- + * Input state needs to be provided to nuklear by first calling `nk_input_begin` + * which resets internal state like delta mouse position and button transistions. + * After `nk_input_begin` all current input state needs to be provided. This includes + * mouse motion, button and key pressed and released, text input and scrolling. + * Both event- or state-based input handling are supported by this API + * and should work without problems. Finally after all input state has been + * mirrored `nk_input_end` needs to be called to finish input process. + * + * struct nk_context ctx; + * nk_init_xxx(&ctx, ...); + * while (1) { + * Event evt; + * nk_input_begin(&ctx); + * while (GetEvent(&evt)) { + * if (evt.type == MOUSE_MOVE) + * nk_input_motion(&ctx, evt.motion.x, evt.motion.y); + * else if (evt.type == ...) { + * ... + * } + * } + * nk_input_end(&ctx); + * [...] + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * Reference + * ------------------- + * nk_input_begin - Begins the input mirroring process. Needs to be called before all other `nk_input_xxx` calls + * nk_input_motion - Mirrors mouse cursor position + * nk_input_key - Mirrors key state with either pressed or released + * nk_input_button - Mirrors mouse button state with either pressed or released + * nk_input_scroll - Mirrors mouse scroll values + * nk_input_char - Adds a single ASCII text character into an internal text buffer + * nk_input_glyph - Adds a single multi-byte UTF-8 character into an internal text buffer + * nk_input_unicode - Adds a single unicode rune into an internal text buffer + * nk_input_end - Ends the input mirroring process by calculating state changes. Don't call any `nk_input_xxx` function referenced above after this call + */ +enum nk_keys { + NK_KEY_NONE, + NK_KEY_SHIFT, + NK_KEY_CTRL, + NK_KEY_DEL, + NK_KEY_ENTER, + NK_KEY_TAB, + NK_KEY_BACKSPACE, + NK_KEY_COPY, + NK_KEY_CUT, + NK_KEY_PASTE, + NK_KEY_UP, + NK_KEY_DOWN, + NK_KEY_LEFT, + NK_KEY_RIGHT, + /* Shortcuts: text field */ + NK_KEY_TEXT_INSERT_MODE, + NK_KEY_TEXT_REPLACE_MODE, + NK_KEY_TEXT_RESET_MODE, + NK_KEY_TEXT_LINE_START, + NK_KEY_TEXT_LINE_END, + NK_KEY_TEXT_START, + NK_KEY_TEXT_END, + NK_KEY_TEXT_UNDO, + NK_KEY_TEXT_REDO, + NK_KEY_TEXT_SELECT_ALL, + NK_KEY_TEXT_WORD_LEFT, + NK_KEY_TEXT_WORD_RIGHT, + /* Shortcuts: scrollbar */ + NK_KEY_SCROLL_START, + NK_KEY_SCROLL_END, + NK_KEY_SCROLL_DOWN, + NK_KEY_SCROLL_UP, + NK_KEY_MAX +}; +enum nk_buttons { + NK_BUTTON_LEFT, + NK_BUTTON_MIDDLE, + NK_BUTTON_RIGHT, + NK_BUTTON_DOUBLE, + NK_BUTTON_MAX +}; +/* nk_input_begin - Begins the input mirroring process by resetting text, scroll + * mouse previous mouse position and movement as well as key state transistions, + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct */ +NK_API void nk_input_begin(struct nk_context*); +/* nk_input_motion - Mirros current mouse position to nuklear + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @x must constain an integer describing the current mouse cursor x-position + * @y must constain an integer describing the current mouse cursor y-position */ +NK_API void nk_input_motion(struct nk_context*, int x, int y); +/* nk_input_key - Mirros state of a specific key to nuklear + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @key must be any value specified in enum `nk_keys` that needs to be mirrored + * @down must be 0 for key is up and 1 for key is down */ +NK_API void nk_input_key(struct nk_context*, enum nk_keys, int down); +/* nk_input_button - Mirros the state of a specific mouse button to nuklear + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @nk_buttons must be any value specified in enum `nk_buttons` that needs to be mirrored + * @x must constain an integer describing mouse cursor x-position on click up/down + * @y must constain an integer describing mouse cursor y-position on click up/down + * @down must be 0 for key is up and 1 for key is down */ +NK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, int down); +/* nk_input_char - Copies a single ASCII character into an internal text buffer + * This is basically a helper function to quickly push ASCII characters into + * nuklear. Note that you can only push up to NK_INPUT_MAX bytes into + * struct `nk_input` between `nk_input_begin` and `nk_input_end`. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @c must be a single ASCII character preferable one that can be printed */ +NK_API void nk_input_scroll(struct nk_context*, struct nk_vec2 val); +/* nk_input_char - Copies a single ASCII character into an internal text buffer + * This is basically a helper function to quickly push ASCII characters into + * nuklear. Note that you can only push up to NK_INPUT_MAX bytes into + * struct `nk_input` between `nk_input_begin` and `nk_input_end`. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @c must be a single ASCII character preferable one that can be printed */ +NK_API void nk_input_char(struct nk_context*, char); +/* nk_input_unicode - Converts a encoded unicode rune into UTF-8 and copies the result + * into an internal text buffer. + * Note that you can only push up to NK_INPUT_MAX bytes into + * struct `nk_input` between `nk_input_begin` and `nk_input_end`. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @glyph UTF-32 uncode codepoint */ +NK_API void nk_input_glyph(struct nk_context*, const nk_glyph); +/* nk_input_unicode - Converts a unicode rune into UTF-8 and copies the result + * into an internal text buffer. + * Note that you can only push up to NK_INPUT_MAX bytes into + * struct `nk_input` between `nk_input_begin` and `nk_input_end`. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @glyph UTF-32 uncode codepoint */ +NK_API void nk_input_unicode(struct nk_context*, nk_rune); +/* nk_input_end - End the input mirroring process by resetting mouse grabbing + * state to ensure the mouse cursor is not grabbed indefinitely. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct */ +NK_API void nk_input_end(struct nk_context*); +/* ============================================================================= + * + * DRAWING + * + * =============================================================================*/ +/* This library was designed to be render backend agnostic so it does + * not draw anything to screen directly. Instead all drawn shapes, widgets + * are made of, are buffered into memory and make up a command queue. + * Each frame therefore fills the command buffer with draw commands + * that then need to be executed by the user and his own render backend. + * After that the command buffer needs to be cleared and a new frame can be + * started. It is probably important to note that the command buffer is the main + * drawing API and the optional vertex buffer API only takes this format and + * converts it into a hardware accessible format. + * + * Usage + * ------------------- + * To draw all draw commands accumulated over a frame you need your own render + * backend able to draw a number of 2D primitives. This includes at least + * filled and stroked rectangles, circles, text, lines, triangles and scissors. + * As soon as this criterion is met you can iterate over each draw command + * and execute each draw command in a interpreter like fashion: + * + * const struct nk_command *cmd = 0; + * nk_foreach(cmd, &ctx) { + * switch (cmd->type) { + * case NK_COMMAND_LINE: + * your_draw_line_function(...) + * break; + * case NK_COMMAND_RECT + * your_draw_rect_function(...) + * break; + * case ...: + * [...] + * } + * + * In program flow context draw commands need to be executed after input has been + * gathered and the complete UI with windows and their contained widgets have + * been executed and before calling `nk_clear` which frees all previously + * allocated draw commands. + * + * struct nk_context ctx; + * nk_init_xxx(&ctx, ...); + * while (1) { + * Event evt; + * nk_input_begin(&ctx); + * while (GetEvent(&evt)) { + * if (evt.type == MOUSE_MOVE) + * nk_input_motion(&ctx, evt.motion.x, evt.motion.y); + * else if (evt.type == [...]) { + * [...] + * } + * } + * nk_input_end(&ctx); + * + * [...] + * + * const struct nk_command *cmd = 0; + * nk_foreach(cmd, &ctx) { + * switch (cmd->type) { + * case NK_COMMAND_LINE: + * your_draw_line_function(...) + * break; + * case NK_COMMAND_RECT + * your_draw_rect_function(...) + * break; + * case ...: + * [...] + * } + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * You probably noticed that you have to draw all of the UI each frame which is + * quite wasteful. While the actual UI updating loop is quite fast rendering + * without actually needing it is not. So there are multiple things you could do. + * + * First is only update on input. This of course is only an option if your + * application only depends on the UI and does not require any outside calculations. + * If you actually only update on input make sure to update the UI two times each + * frame and call `nk_clear` directly after the first pass and only draw in + * the second pass. In addition it is recommended to also add additional timers + * to make sure the UI is not drawn more than a fixed number of frames per second. + * + * struct nk_context ctx; + * nk_init_xxx(&ctx, ...); + * while (1) { + * [...wait for input ] + * + * [...do two UI passes ...] + * do_ui(...) + * nk_clear(&ctx); + * do_ui(...) + * + * const struct nk_command *cmd = 0; + * nk_foreach(cmd, &ctx) { + * switch (cmd->type) { + * case NK_COMMAND_LINE: + * your_draw_line_function(...) + * break; + * case NK_COMMAND_RECT + * your_draw_rect_function(...) + * break; + * case ...: + * [...] + * } + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * The second probably more applicable trick is to only draw if anything changed. + * It is not really useful for applications with continous draw loop but + * quite useful for desktop applications. To actually get nuklear to only + * draw on changes you first have to define `NK_ZERO_COMMAND_MEMORY` and + * allocate a memory buffer that will store each unique drawing output. + * After each frame you compare the draw command memory inside the library + * with your allocated buffer by memcmp. If memcmp detects differences + * you have to copy the command buffer into the allocated buffer + * and then draw like usual (this example uses fixed memory but you could + * use dynamically allocated memory). + * + * [... other defines ...] + * #define NK_ZERO_COMMAND_MEMORY + * #include "nuklear.h" + * + * struct nk_context ctx; + * void *last = calloc(1,64*1024); + * void *buf = calloc(1,64*1024); + * nk_init_fixed(&ctx, buf, 64*1024); + * while (1) { + * [...input...] + * [...ui...] + * + * void *cmds = nk_buffer_memory(&ctx.memory); + * if (memcmp(cmds, last, ctx.memory.allocated)) { + * memcpy(last,cmds,ctx.memory.allocated); + * const struct nk_command *cmd = 0; + * nk_foreach(cmd, &ctx) { + * switch (cmd->type) { + * case NK_COMMAND_LINE: + * your_draw_line_function(...) + * break; + * case NK_COMMAND_RECT + * your_draw_rect_function(...) + * break; + * case ...: + * [...] + * } + * } + * } + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * Finally while using draw commands makes sense for higher abstracted platforms like + * X11 and Win32 or drawing libraries it is often desirable to use graphics + * hardware directly. Therefore it is possible to just define + * `NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output. + * To access the vertex output you first have to convert all draw commands into + * vertexes by calling `nk_convert` which takes in your prefered vertex format. + * After successfully converting all draw commands just iterate over and execute all + * vertex draw commands: + * + * struct nk_convert_config cfg = {}; + * static const struct nk_draw_vertex_layout_element vertex_layout[] = { + * {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, pos)}, + * {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, uv)}, + * {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct your_vertex, col)}, + * {NK_VERTEX_LAYOUT_END} + * }; + * cfg.shape_AA = NK_ANTI_ALIASING_ON; + * cfg.line_AA = NK_ANTI_ALIASING_ON; + * cfg.vertex_layout = vertex_layout; + * cfg.vertex_size = sizeof(struct your_vertex); + * cfg.vertex_alignment = NK_ALIGNOF(struct your_vertex); + * cfg.circle_segment_count = 22; + * cfg.curve_segment_count = 22; + * cfg.arc_segment_count = 22; + * cfg.global_alpha = 1.0f; + * cfg.null = dev->null; + * + * struct nk_buffer cmds, verts, idx; + * nk_buffer_init_default(&cmds); + * nk_buffer_init_default(&verts); + * nk_buffer_init_default(&idx); + * nk_convert(&ctx, &cmds, &verts, &idx, &cfg); + * nk_draw_foreach(cmd, &ctx, &cmds) { + * if (!cmd->elem_count) continue; + * [...] + * } + * nk_buffer_free(&cms); + * nk_buffer_free(&verts); + * nk_buffer_free(&idx); + * + * Reference + * ------------------- + * nk__begin - Returns the first draw command in the context draw command list to be drawn + * nk__next - Increments the draw command iterator to the next command inside the context draw command list + * nk_foreach - Iteratates over each draw command inside the context draw command list + * + * nk_convert - Converts from the abstract draw commands list into a hardware accessable vertex format + * nk__draw_begin - Returns the first vertex command in the context vertex draw list to be executed + * nk__draw_next - Increments the vertex command iterator to the next command inside the context vertex command list + * nk__draw_end - Returns the end of the vertex draw list + * nk_draw_foreach - Iterates over each vertex draw command inside the vertex draw list + */ +enum nk_anti_aliasing {NK_ANTI_ALIASING_OFF, NK_ANTI_ALIASING_ON}; +enum nk_convert_result { + NK_CONVERT_SUCCESS = 0, + NK_CONVERT_INVALID_PARAM = 1, + NK_CONVERT_COMMAND_BUFFER_FULL = NK_FLAG(1), + NK_CONVERT_VERTEX_BUFFER_FULL = NK_FLAG(2), + NK_CONVERT_ELEMENT_BUFFER_FULL = NK_FLAG(3) +}; +struct nk_draw_null_texture { + nk_handle texture; /* texture handle to a texture with a white pixel */ + struct nk_vec2 uv; /* coordinates to a white pixel in the texture */ +}; +struct nk_convert_config { + float global_alpha; /* global alpha value */ + enum nk_anti_aliasing line_AA; /* line anti-aliasing flag can be turned off if you are tight on memory */ + enum nk_anti_aliasing shape_AA; /* shape anti-aliasing flag can be turned off if you are tight on memory */ + unsigned circle_segment_count; /* number of segments used for circles: default to 22 */ + unsigned arc_segment_count; /* number of segments used for arcs: default to 22 */ + unsigned curve_segment_count; /* number of segments used for curves: default to 22 */ + struct nk_draw_null_texture null; /* handle to texture with a white pixel for shape drawing */ + const struct nk_draw_vertex_layout_element *vertex_layout; /* describes the vertex output format and packing */ + nk_size vertex_size; /* sizeof one vertex for vertex packing */ + nk_size vertex_alignment; /* vertex alignment: Can be optained by NK_ALIGNOF */ +}; +/* nk__begin - Returns a draw command list iterator to iterate all draw + * commands accumulated over one frame. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * Return values: + * draw command pointer pointing to the first command inside the draw command list */ +NK_API const struct nk_command* nk__begin(struct nk_context*); +/* nk__next - Returns a draw command list iterator to iterate all draw + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * @cmd must point to an previously a draw command either returned by `nk__begin` or `nk__next` + * Return values: + * draw command pointer pointing to the next command inside the draw command list */ +NK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_command*); +/* nk_foreach - Iterates over each draw command inside the context draw command list + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * @cmd pointer initialized to NULL */ +#define nk_foreach(c, ctx) for((c) = nk__begin(ctx); (c) != 0; (c) = nk__next(ctx,c)) +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT +/* nk_convert - converts all internal draw command into vertex draw commands and fills + * three buffers with vertexes, vertex draw commands and vertex indicies. The vertex format + * as well as some other configuration values have to be configurated by filling out a + * `nk_convert_config` struct. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * @cmds must point to a previously initialized buffer to hold converted vertex draw commands + * @vertices must point to a previously initialized buffer to hold all produced verticies + * @elements must point to a previously initialized buffer to hold all procudes vertex indicies + * @config must point to a filled out `nk_config` struct to configure the conversion process + * Returns: + * returns NK_CONVERT_SUCCESS on success and a enum nk_convert_result error values if not */ +NK_API nk_flags nk_convert(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*); +/* nk__draw_begin - Returns a draw vertex command buffer iterator to iterate each the vertex draw command buffer + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer + * Return values: + * vertex draw command pointer pointing to the first command inside the vertex draw command buffer */ +NK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*); +/* nk__draw_end - Returns the vertex draw command at the end of the vertex draw command buffer + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer + * Return values: + * vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer */ +NK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*); +/* nk__draw_next - Increments the the vertex draw command buffer iterator + * Parameters: + * @cmd must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command + * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame + * Return values: + * vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer */ +NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*); +/* nk_draw_foreach - Iterates over each vertex draw command inside a vertex draw command buffer + * Parameters: + * @cmd nk_draw_command pointer set to NULL + * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer + * @ctx must point to an previously initialized `nk_context` struct at the end of a frame */ +#define nk_draw_foreach(cmd,ctx, b) for((cmd)=nk__draw_begin(ctx, b); (cmd)!=0; (cmd)=nk__draw_next(cmd, b, ctx)) +#endif +/* ============================================================================= + * + * WINDOW + * + * ============================================================================= + * Windows are the main persistent state used inside nuklear and are life time + * controlled by simply "retouching" (i.e. calling) each window each frame. + * All widgets inside nuklear can only be added inside function pair `nk_begin_xxx` + * and `nk_end`. Calling any widgets outside these two functions will result in an + * assert in debug or no state change in release mode. + * + * Each window holds frame persistent state like position, size, flags, state tables, + * and some garbage collected internal persistent widget state. Each window + * is linked into a window stack list which determines the drawing and overlapping + * order. The topmost window thereby is the currently active window. + * + * To change window position inside the stack occurs either automatically by + * user input by being clicked on or programatically by calling `nk_window_focus`. + * Windows by default are visible unless explicitly being defined with flag + * `NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag + * `NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling + * `nk_window_show`. To explicitly close and destroy a window call `nk_window_close`. + * + * Usage + * ------------------- + * To create and keep a window you have to call one of the two `nk_begin_xxx` + * functions to start window declarations and `nk_end` at the end. Furthermore it + * is recommended to check the return value of `nk_begin_xxx` and only process + * widgets inside the window if the value is not 0. Either way you have to call + * `nk_end` at the end of window declarations. Furthmore do not attempt to + * nest `nk_begin_xxx` calls which will hopefully result in an assert or if not + * in a segmation fault. + * + * if (nk_begin_xxx(...) { + * [... widgets ...] + * } + * nk_end(ctx); + * + * In the grand concept window and widget declarations need to occur after input + * handling and before drawing to screen. Not doing so can result in higher + * latency or at worst invalid behavior. Furthermore make sure that `nk_clear` + * is called at the end of the frame. While nuklears default platform backends + * already call `nk_clear` for you if you write your own backend not calling + * `nk_clear` can cause asserts or even worse undefined behavior. + * + * struct nk_context ctx; + * nk_init_xxx(&ctx, ...); + * while (1) { + * Event evt; + * nk_input_begin(&ctx); + * while (GetEvent(&evt)) { + * if (evt.type == MOUSE_MOVE) + * nk_input_motion(&ctx, evt.motion.x, evt.motion.y); + * else if (evt.type == [...]) { + * nk_input_xxx(...); + * } + * } + * nk_input_end(&ctx); + * + * if (nk_begin_xxx(...) { + * [...] + * } + * nk_end(ctx); + * + * const struct nk_command *cmd = 0; + * nk_foreach(cmd, &ctx) { + * case NK_COMMAND_LINE: + * your_draw_line_function(...) + * break; + * case NK_COMMAND_RECT + * your_draw_rect_function(...) + * break; + * case ...: + * [...] + * } + * nk_clear(&ctx); + * } + * nk_free(&ctx); + * + * Reference + * ------------------- + * nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed + * nk_begin_titled - extended window start with seperated title and identifier to allow multiple windows with same name but not title + * nk_end - needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup + * + * nk_window_find - finds and returns the window with give name + * nk_window_get_bounds - returns a rectangle with screen position and size of the currently processed window. + * nk_window_get_position - returns the position of the currently processed window + * nk_window_get_size - returns the size with width and height of the currently processed window + * nk_window_get_width - returns the width of the currently processed window + * nk_window_get_height - returns the height of the currently processed window + * nk_window_get_panel - returns the underlying panel which contains all processing state of the currnet window + * nk_window_get_content_region - returns the position and size of the currently visible and non-clipped space inside the currently processed window + * nk_window_get_content_region_min - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window + * nk_window_get_content_region_max - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window + * nk_window_get_content_region_size - returns the size of the currently visible and non-clipped space inside the currently processed window + * nk_window_get_canvas - returns the draw command buffer. Can be used to draw custom widgets + * + * nk_window_has_focus - returns if the currently processed window is currently active + * nk_window_is_collapsed - returns if the window with given name is currently minimized/collapsed + * nk_window_is_closed - returns if the currently processed window was closed + * nk_window_is_hidden - returns if the currently processed window was hidden + * nk_window_is_active - same as nk_window_has_focus for some reason + * nk_window_is_hovered - returns if the currently processed window is currently being hovered by mouse + * nk_window_is_any_hovered - return if any wndow currently hovered + * nk_item_is_any_active - returns if any window or widgets is currently hovered or active + * + * nk_window_set_bounds - updates position and size of the currently processed window + * nk_window_set_position - updates position of the currently process window + * nk_window_set_size - updates the size of the currently processed window + * nk_window_set_focus - set the currently processed window as active window + * + * nk_window_close - closes the window with given window name which deletes the window at the end of the frame + * nk_window_collapse - collapses the window with given window name + * nk_window_collapse_if - collapses the window with given window name if the given condition was met + * nk_window_show - hides a visible or reshows a hidden window + * nk_window_show_if - hides/shows a window depending on condition + */ +enum nk_panel_flags { + NK_WINDOW_BORDER = NK_FLAG(0), /* Draws a border around the window to visually separate window from the background */ + NK_WINDOW_MOVABLE = NK_FLAG(1), /* The movable flag indicates that a window can be moved by user input or by dragging the window header */ + NK_WINDOW_SCALABLE = NK_FLAG(2), /* The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window */ + NK_WINDOW_CLOSABLE = NK_FLAG(3), /* adds a closable icon into the header */ + NK_WINDOW_MINIMIZABLE = NK_FLAG(4), /* adds a minimize icon into the header */ + NK_WINDOW_NO_SCROLLBAR = NK_FLAG(5), /* Removes the scrollbar from the window */ + NK_WINDOW_TITLE = NK_FLAG(6), /* Forces a header at the top at the window showing the title */ + NK_WINDOW_SCROLL_AUTO_HIDE = NK_FLAG(7), /* Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame */ + NK_WINDOW_BACKGROUND = NK_FLAG(8), /* Always keep window in the background */ + NK_WINDOW_SCALE_LEFT = NK_FLAG(9), /* Puts window scaler in the left-ottom corner instead right-bottom*/ + NK_WINDOW_NO_INPUT = NK_FLAG(10) /* Prevents window of scaling, moving or getting focus */ +}; +/* nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @title window title and identifier. Needs to be persitent over frames to identify the window + * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame + * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors + * Return values: + * returns 1 if the window can be filled up with widgets from this point until `nk_end or 0 otherwise for example if minimized `*/ +NK_API int nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags); +/* nk_begin_titled - extended window start with seperated title and identifier to allow multiple windows with same name but not title + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name window identifier. Needs to be persitent over frames to identify the window + * @title window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set + * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame + * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors + * Return values: + * returns 1 if the window can be filled up with widgets from this point until `nk_end or 0 otherwise `*/ +NK_API int nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags); +/* nk_end - needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup. + * All widget calls after this functions will result in asserts or no state changes + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct */ +NK_API void nk_end(struct nk_context *ctx); +/* nk_window_find - finds and returns the window with give name + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name window identifier + * Return values: + * returns a `nk_window` struct pointing to the idified window or 0 if no window with given name was found */ +NK_API struct nk_window *nk_window_find(struct nk_context *ctx, const char *name); +/* nk_window_get_bounds - returns a rectangle with screen position and size of the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns a `nk_rect` struct with window upper left position and size */ +NK_API struct nk_rect nk_window_get_bounds(const struct nk_context *ctx); +/* nk_window_get_position - returns the position of the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns a `nk_vec2` struct with window upper left position */ +NK_API struct nk_vec2 nk_window_get_position(const struct nk_context *ctx); +/* nk_window_get_size - returns the size with width and height of the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns a `nk_vec2` struct with window size */ +NK_API struct nk_vec2 nk_window_get_size(const struct nk_context*); +/* nk_window_get_width - returns the width of the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns the window width */ +NK_API float nk_window_get_width(const struct nk_context*); +/* nk_window_get_height - returns the height of the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns the window height */ +NK_API float nk_window_get_height(const struct nk_context*); +/* nk_window_get_panel - returns the underlying panel which contains all processing state of the currnet window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns a pointer to window internal `nk_panel` state. DO NOT keep this pointer around it is only valid until `nk_end` */ +NK_API struct nk_panel* nk_window_get_panel(struct nk_context*); +/* nk_window_get_content_region - returns the position and size of the currently visible and non-clipped space inside the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns `nk_rect` struct with screen position and size (no scrollbar offset) of the visible space inside the current window */ +NK_API struct nk_rect nk_window_get_content_region(struct nk_context*); +/* nk_window_get_content_region_min - returns the upper left position of the currently visible and non-clipped space inside the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns `nk_vec2` struct with upper left screen position (no scrollbar offset) of the visible space inside the current window */ +NK_API struct nk_vec2 nk_window_get_content_region_min(struct nk_context*); +/* nk_window_get_content_region_max - returns the lower right screen position of the currently visible and non-clipped space inside the currently processed window. + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns `nk_vec2` struct with lower right screen position (no scrollbar offset) of the visible space inside the current window */ +NK_API struct nk_vec2 nk_window_get_content_region_max(struct nk_context*); +/* nk_window_get_content_region_size - returns the size of the currently visible and non-clipped space inside the currently processed window + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns `nk_vec2` struct with size the visible space inside the current window */ +NK_API struct nk_vec2 nk_window_get_content_region_size(struct nk_context*); +/* nk_window_get_canvas - returns the draw command buffer. Can be used to draw custom widgets + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns a pointer to window internal `nk_command_buffer` struct used as drawing canvas. Can be used to do custom drawing */ +NK_API struct nk_command_buffer* nk_window_get_canvas(struct nk_context*); +/* nk_window_has_focus - returns if the currently processed window is currently active + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns 0 if current window is not active or 1 if it is */ +NK_API int nk_window_has_focus(const struct nk_context*); +/* nk_window_is_collapsed - returns if the window with given name is currently minimized/collapsed + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of window you want to check is collapsed + * Return values: + * returns 1 if current window is minimized and 0 if window not found or is not minimized */ +NK_API int nk_window_is_collapsed(struct nk_context *ctx, const char *name); +/* nk_window_is_closed - returns if the window with given name was closed by calling `nk_close` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of window you want to check is closed + * Return values: + * returns 1 if current window was closed or 0 window not found or not closed */ +NK_API int nk_window_is_closed(struct nk_context*, const char*); +/* nk_window_is_hidden - returns if the window with given name is hidden + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of window you want to check is hidden + * Return values: + * returns 1 if current window is hidden or 0 window not found or visible */ +NK_API int nk_window_is_hidden(struct nk_context*, const char*); +/* nk_window_is_active - same as nk_window_has_focus for some reason + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of window you want to check is hidden + * Return values: + * returns 1 if current window is active or 0 window not found or not active */ +NK_API int nk_window_is_active(struct nk_context*, const char*); +/* nk_window_is_hovered - return if the current window is being hovered + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns 1 if current window is hovered or 0 otherwise */ +NK_API int nk_window_is_hovered(struct nk_context*); +/* nk_window_is_any_hovered - returns if the any window is being hovered + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns 1 if any window is hovered or 0 otherwise */ +NK_API int nk_window_is_any_hovered(struct nk_context*); +/* nk_item_is_any_active - returns if the any window is being hovered or any widget is currently active. + * Can be used to decide if input should be processed by UI or your specific input handling. + * Example could be UI and 3D camera to move inside a 3D space. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * Return values: + * returns 1 if any window is hovered or any item is active or 0 otherwise */ +NK_API int nk_item_is_any_active(struct nk_context*); +/* nk_window_set_bounds - updates position and size of the currently processed window + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @bounds points to a `nk_rect` struct with the new position and size of currently active window */ +NK_API void nk_window_set_bounds(struct nk_context*, struct nk_rect bounds); +/* nk_window_set_position - updates position of the currently processed window + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @pos points to a `nk_vec2` struct with the new position of currently active window */ +NK_API void nk_window_set_position(struct nk_context*, struct nk_vec2 pos); +/* nk_window_set_size - updates size of the currently processed window + * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @bounds points to a `nk_vec2` struct with the new size of currently active window */ +NK_API void nk_window_set_size(struct nk_context*, struct nk_vec2); +/* nk_window_set_focus - sets the window with given name as active + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be set active */ +NK_API void nk_window_set_focus(struct nk_context*, const char *name); +/* nk_window_close - closed a window and marks it for being freed at the end of the frame + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be closed */ +NK_API void nk_window_close(struct nk_context *ctx, const char *name); +/* nk_window_collapse - updates collapse state of a window with given name + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be either collapse or maximize */ +NK_API void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state); +/* nk_window_collapse - updates collapse state of a window with given name if given condition is met + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be either collapse or maximize + * @state the window should be put into + * @condition that has to be true to actually commit the collsage state change */ +NK_API void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond); +/* nk_window_show - updates visibility state of a window with given name + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be either collapse or maximize + * @state with either visible or hidden to modify the window with */ +NK_API void nk_window_show(struct nk_context*, const char *name, enum nk_show_states); +/* nk_window_show_if - updates visibility state of a window with given name if a given condition is met + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to be either collapse or maximize + * @state with either visible or hidden to modify the window with + * @condition that has to be true to actually commit the visible state change */ +NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond); +/* ============================================================================= + * + * LAYOUT + * + * ============================================================================= */ +/* Layouting in general describes placing widget inside a window with position and size. + * While in this particular implementation there are five different APIs for layouting + * each with different trade offs between control and ease of use. + * + * All layouting methodes in this library are based around the concept of a row. + * A row has a height the window content grows by and a number of columns and each + * layouting method specifies how each widget is placed inside the row. + * After a row has been allocated by calling a layouting functions and then + * filled with widgets will advance an internal pointer over the allocated row. + * + * To acually define a layout you just call the appropriate layouting function + * and each subsequnetial widget call will place the widget as specified. Important + * here is that if you define more widgets then columns defined inside the layout + * functions it will allocate the next row without you having to make another layouting + * call. + * + * Biggest limitation with using all these APIs outside the `nk_layout_space_xxx` API + * is that you have to define the row height for each. However the row height + * often depends on the height of the font. + * + * To fix that internally nuklear uses a minimum row height that is set to the + * height plus padding of currently active font and overwrites the row height + * value if zero. + * + * If you manually want to change the minimum row height then + * use nk_layout_set_min_row_height, and use nk_layout_reset_min_row_height to + * reset it back to be derived from font height. + * + * Also if you change the font in nuklear it will automatically change the minimum + * row height for you and. This means if you change the font but still want + * a minimum row height smaller than the font you have to repush your value. + * + * For actually more advanced UI I would even recommend using the `nk_layout_space_xxx` + * layouting method in combination with a cassowary constraint solver (there are + * some versions on github with permissive license model) to take over all control over widget + * layouting yourself. However for quick and dirty layouting using all the other layouting + * functions should be fine. + * + * Usage + * ------------------- + * 1.) nk_layout_row_dynamic + * The easiest layouting function is `nk_layout_row_dynamic`. It provides each + * widgets with same horizontal space inside the row and dynamically grows + * if the owning window grows in width. So the number of columns dictates + * the size of each widget dynamically by formula: + * + * widget_width = (window_width - padding - spacing) * (1/colum_count) + * + * Just like all other layouting APIs if you define more widget than columns this + * library will allocate a new row and keep all layouting parameters previously + * defined. + * + * if (nk_begin_xxx(...) { + * // first row with height: 30 composed of two widgets + * nk_layout_row_dynamic(&ctx, 30, 2); + * nk_widget(...); + * nk_widget(...); + * + * // second row with same parameter as defined above + * nk_widget(...); + * nk_widget(...); + * + * // third row uses 0 for height which will use auto layouting + * nk_layout_row_dynamic(&ctx, 0, 2); + * nk_widget(...); + * nk_widget(...); + * } + * nk_end(...); + * + * 2.) nk_layout_row_static + * Another easy layouting function is `nk_layout_row_static`. It provides each + * widget with same horizontal pixel width inside the row and does not grow + * if the owning window scales smaller or bigger. + * + * if (nk_begin_xxx(...) { + * // first row with height: 30 composed of two widgets with width: 80 + * nk_layout_row_static(&ctx, 30, 80, 2); + * nk_widget(...); + * nk_widget(...); + * + * // second row with same parameter as defined above + * nk_widget(...); + * nk_widget(...); + * + * // third row uses 0 for height which will use auto layouting + * nk_layout_row_static(&ctx, 0, 80, 2); + * nk_widget(...); + * nk_widget(...); + * } + * nk_end(...); + * + * 3.) nk_layout_row_xxx + * A little bit more advanced layouting API are functions `nk_layout_row_begin`, + * `nk_layout_row_push` and `nk_layout_row_end`. They allow to directly + * specify each column pixel or window ratio in a row. It supports either + * directly setting per column pixel width or widget window ratio but not + * both. Furthermore it is a immediate mode API so each value is directly + * pushed before calling a widget. Therefore the layout is not automatically + * repeating like the last two layouting functions. + * + * if (nk_begin_xxx(...) { + * // first row with height: 25 composed of two widgets with width 60 and 40 + * nk_layout_row_begin(ctx, NK_STATIC, 25, 2); + * nk_layout_row_push(ctx, 60); + * nk_widget(...); + * nk_layout_row_push(ctx, 40); + * nk_widget(...); + * nk_layout_row_end(ctx); + * + * // second row with height: 25 composed of two widgets with window ratio 0.25 and 0.75 + * nk_layout_row_begin(ctx, NK_DYNAMIC, 25, 2); + * nk_layout_row_push(ctx, 0.25f); + * nk_widget(...); + * nk_layout_row_push(ctx, 0.75f); + * nk_widget(...); + * nk_layout_row_end(ctx); + * + * // third row with auto generated height: composed of two widgets with window ratio 0.25 and 0.75 + * nk_layout_row_begin(ctx, NK_DYNAMIC, 0, 2); + * nk_layout_row_push(ctx, 0.25f); + * nk_widget(...); + * nk_layout_row_push(ctx, 0.75f); + * nk_widget(...); + * nk_layout_row_end(ctx); + * } + * nk_end(...); + * + * 4.) nk_layout_row + * The array counterpart to API nk_layout_row_xxx is the single nk_layout_row + * functions. Instead of pushing either pixel or window ratio for every widget + * it allows to define it by array. The trade of for less control is that + * `nk_layout_row` is automatically repeating. Otherwise the behavior is the + * same. + * + * if (nk_begin_xxx(...) { + * // two rows with height: 30 composed of two widgets with width 60 and 40 + * const float size[] = {60,40}; + * nk_layout_row(ctx, NK_STATIC, 30, 2, ratio); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * + * // two rows with height: 30 composed of two widgets with window ratio 0.25 and 0.75 + * const float ratio[] = {0.25, 0.75}; + * nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * + * // two rows with auto generated height composed of two widgets with window ratio 0.25 and 0.75 + * const float ratio[] = {0.25, 0.75}; + * nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * } + * nk_end(...); + * + * 5.) nk_layout_row_template_xxx + * The most complex and second most flexible API is a simplified flexbox version without + * line wrapping and weights for dynamic widgets. It is an immediate mode API but + * unlike `nk_layout_row_xxx` it has auto repeat behavior and needs to be called + * before calling the templated widgets. + * The row template layout has three different per widget size specifier. The first + * one is the static widget size specifier with fixed widget pixel width. They do + * not grow if the row grows and will always stay the same. The second size + * specifier is nk_layout_row_template_push_variable which defines a + * minumum widget size but it also can grow if more space is available not taken + * by other widgets. Finally there are dynamic widgets which are completly flexible + * and unlike variable widgets can even shrink to zero if not enough space + * is provided. + * + * if (nk_begin_xxx(...) { + * // two rows with height: 30 composed of three widgets + * nk_layout_row_template_begin(ctx, 30); + * nk_layout_row_template_push_dynamic(ctx); + * nk_layout_row_template_push_variable(ctx, 80); + * nk_layout_row_template_push_static(ctx, 80); + * nk_layout_row_template_end(ctx); + * + * nk_widget(...); // dynamic widget can go to zero if not enough space + * nk_widget(...); // variable widget with min 80 pixel but can grow bigger if enough space + * nk_widget(...); // static widget with fixed 80 pixel width + * + * // second row same layout + * nk_widget(...); + * nk_widget(...); + * nk_widget(...); + * } + * nk_end(...); + * + * 6.) nk_layout_space_xxx + * Finally the most flexible API directly allows you to place widgets inside the + * window. The space layout API is an immediate mode API which does not support + * row auto repeat and directly sets position and size of a widget. Position + * and size hereby can be either specified as ratio of alloated space or + * allocated space local position and pixel size. Since this API is quite + * powerfull there are a number of utility functions to get the available space + * and convert between local allocated space and screen space. + * + * if (nk_begin_xxx(...) { + * // static row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) + * nk_layout_space_begin(ctx, NK_STATIC, 500, INT_MAX); + * nk_layout_space_push(ctx, nk_rect(0,0,150,200)); + * nk_widget(...); + * nk_layout_space_push(ctx, nk_rect(200,200,100,200)); + * nk_widget(...); + * nk_layout_space_end(ctx); + * + * // dynamic row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) + * nk_layout_space_begin(ctx, NK_DYNAMIC, 500, INT_MAX); + * nk_layout_space_push(ctx, nk_rect(0.5,0.5,0.1,0.1)); + * nk_widget(...); + * nk_layout_space_push(ctx, nk_rect(0.7,0.6,0.1,0.1)); + * nk_widget(...); + * } + * nk_end(...); + * + * Reference + * ------------------- + * nk_layout_set_min_row_height - set the currently used minimum row height to a specified value + * nk_layout_reset_min_row_height - resets the currently used minimum row height to font height + * + * nk_layout_widget_bounds - calculates current width a static layout row can fit inside a window + * nk_layout_ratio_from_pixel - utility functions to calculate window ratio from pixel size + * + * nk_layout_row_dynamic - current layout is divided into n same sized gowing columns + * nk_layout_row_static - current layout is divided into n same fixed sized columns + * nk_layout_row_begin - starts a new row with given height and number of columns + * nk_layout_row_push - pushes another column with given size or window ratio + * nk_layout_row_end - finished previously started row + * nk_layout_row - specifies row columns in array as either window ratio or size + * + * nk_layout_row_template_begin - begins the row template declaration + * nk_layout_row_template_push_dynamic - adds a dynamic column that dynamically grows and can go to zero if not enough space + * nk_layout_row_template_push_variable - adds a variable column that dynamically grows but does not shrink below specified pixel width + * nk_layout_row_template_push_static - adds a static column that does not grow and will always have the same size + * nk_layout_row_template_end - marks the end of the row template + * + * nk_layout_space_begin - begins a new layouting space that allows to specify each widgets position and size + * nk_layout_space_push - pushes position and size of the next widget in own coordiante space either as pixel or ratio + * nk_layout_space_end - marks the end of the layouting space + * + * nk_layout_space_bounds - callable after nk_layout_space_begin and returns total space allocated + * nk_layout_space_to_screen - convertes vector from nk_layout_space coordiant space into screen space + * nk_layout_space_to_local - convertes vector from screem space into nk_layout_space coordinates + * nk_layout_space_rect_to_screen - convertes rectangle from nk_layout_space coordiant space into screen space + * nk_layout_space_rect_to_local - convertes rectangle from screem space into nk_layout_space coordinates + */ +/* nk_layout_set_min_row_height - sets the currently used minimum row height. + * IMPORTANT: The passed height needs to include both your prefered row height + * as well as padding. No internal padding is added. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` + * @height new minimum row height to be used for auto generating the row height */ +NK_API void nk_layout_set_min_row_height(struct nk_context*, float height); +/* nk_layout_reset_min_row_height - Reset the currently used minimum row height + * back to font height + text padding + additional padding (style_window.min_row_height_padding) + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` */ +NK_API void nk_layout_reset_min_row_height(struct nk_context*); +/* nk_layout_widget_bounds - returns the width of the next row allocate by one of the layouting functions + * Parameters: + * @ctx must point to an previously initialized `nk_context` */ +NK_API struct nk_rect nk_layout_widget_bounds(struct nk_context*); +/* nk_layout_ratio_from_pixel - utility functions to calculate window ratio from pixel size + * Parameters: + * @ctx must point to an previously initialized `nk_context` + * @pixel_width to convert to window ratio */ +NK_API float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width); +/* nk_layout_row_dynamic - Sets current row layout to share horizontal space + * between @cols number of widgets evenly. Once called all subsequent widget + * calls greater than @cols will allocate a new row with same layout. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` + * @row_height holds height of each widget in row or zero for auto layouting + * @cols number of widget inside row */ +NK_API void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols); +/* nk_layout_row_static - Sets current row layout to fill @cols number of widgets + * in row with same @item_width horizontal size. Once called all subsequent widget + * calls greater than @cols will allocate a new row with same layout. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` + * @height holds row height to allocate from panel for widget height + * @item_width holds width of each widget in row + * @cols number of widget inside row */ +NK_API void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols); +/* nk_layout_row_begin - Starts a new dynamic or fixed row with given height and columns. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` + * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns + * @row_height holds height of each widget in row or zero for auto layouting + * @cols number of widget inside row */ +NK_API void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols); +/* nk_layout_row_push - Specifies either window ratio or width of a single column + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_begin` + * @value either a window ratio or fixed width depending on @fmt in previous `nk_layout_row_begin` call */ +NK_API void nk_layout_row_push(struct nk_context*, float value); +/* nk_layout_row_end - finished previously started row + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_begin` */ +NK_API void nk_layout_row_end(struct nk_context*); +/* nk_layout_row - specifies row columns in array as either window ratio or size + * Parameters: + * @ctx must point to an previously initialized `nk_context` + * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns + * @row_height holds height of each widget in row or zero for auto layouting + * @cols number of widget inside row */ +NK_API void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio); +/* nk_layout_row_template_begin - Begins the row template declaration + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @row_height holds height of each widget in row or zero for auto layouting */ +NK_API void nk_layout_row_template_begin(struct nk_context*, float row_height); +/* nk_layout_row_template_push_dynamic - adds a dynamic column that dynamically grows and can go to zero if not enough space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` */ +NK_API void nk_layout_row_template_push_dynamic(struct nk_context*); +/* nk_layout_row_template_push_variable - adds a variable column that dynamically grows but does not shrink below specified pixel width + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` + * @min_width holds the minimum pixel width the next column must be */ +NK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_width); +/* nk_layout_row_template_push_static - adds a static column that does not grow and will always have the same size + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` + * @width holds the absolulte pixel width value the next column must be */ +NK_API void nk_layout_row_template_push_static(struct nk_context*, float width); +/* nk_layout_row_template_end - marks the end of the row template + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` */ +NK_API void nk_layout_row_template_end(struct nk_context*); +/* nk_layout_space_begin - begins a new layouting space that allows to specify each widgets position and size. + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct + * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns + * @row_height holds height of each widget in row or zero for auto layouting + * @widget_count number of widgets inside row */ +NK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count); +/* nk_layout_space_push - pushes position and size of the next widget in own coordiante space either as pixel or ratio + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` + * @bounds position and size in laoyut space local coordinates */ +NK_API void nk_layout_space_push(struct nk_context*, struct nk_rect); +/* nk_layout_space_end - marks the end of the layout space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` */ +NK_API void nk_layout_space_end(struct nk_context*); +/* nk_layout_space_bounds - returns total space allocated for `nk_layout_space` + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` */ +NK_API struct nk_rect nk_layout_space_bounds(struct nk_context*); +/* nk_layout_space_to_screen - convertes vector from nk_layout_space coordiant space into screen space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` + * @vec position to convert from layout space into screen coordinate space */ +NK_API struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2); +/* nk_layout_space_to_screen - convertes vector from layout space into screen space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` + * @vec position to convert from screen space into layout coordinate space */ +NK_API struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2); +/* nk_layout_space_rect_to_screen - convertes rectangle from screen space into layout space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` + * @bounds rectangle to convert from layout space into screen space */ +NK_API struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect); +/* nk_layout_space_rect_to_local - convertes rectangle from layout space into screen space + * Parameters: + * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` + * @bounds rectangle to convert from screen space into layout space */ +NK_API struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect); +/* ============================================================================= + * + * GROUP + * + * ============================================================================= */ +NK_API int nk_group_begin(struct nk_context*, const char *title, nk_flags); +NK_API int nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char*, nk_flags); +NK_API int nk_group_scrolled_begin(struct nk_context*, struct nk_scroll*, const char *title, nk_flags); +NK_API void nk_group_scrolled_end(struct nk_context*); +NK_API void nk_group_end(struct nk_context*); +/* ============================================================================= + * + * LIST VIEW + * + * ============================================================================= */ +struct nk_list_view { +/* public: */ + int begin, end, count; +/* private: */ + int total_height; + struct nk_context *ctx; + nk_uint *scroll_pointer; + nk_uint scroll_value; +}; +NK_API int nk_list_view_begin(struct nk_context*, struct nk_list_view *out, const char *id, nk_flags, int row_height, int row_count); +NK_API void nk_list_view_end(struct nk_list_view*); +/* ============================================================================= + * + * TREE + * + * ============================================================================= */ +#define nk_tree_push(ctx, type, title, state) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) +#define nk_tree_push_id(ctx, type, title, state, id) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) +NK_API int nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); +#define nk_tree_image_push(ctx, type, img, title, state) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) +#define nk_tree_image_push_id(ctx, type, img, title, state, id) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) +NK_API int nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); +NK_API void nk_tree_pop(struct nk_context*); +NK_API int nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state); +NK_API int nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state); +NK_API void nk_tree_state_pop(struct nk_context*); +/* ============================================================================= + * + * WIDGET + * + * ============================================================================= */ +enum nk_widget_layout_states { + NK_WIDGET_INVALID, /* The widget cannot be seen and is completely out of view */ + NK_WIDGET_VALID, /* The widget is completely inside the window and can be updated and drawn */ + NK_WIDGET_ROM /* The widget is partially visible and cannot be updated */ +}; +enum nk_widget_states { + NK_WIDGET_STATE_MODIFIED = NK_FLAG(1), + NK_WIDGET_STATE_INACTIVE = NK_FLAG(2), /* widget is neither active nor hovered */ + NK_WIDGET_STATE_ENTERED = NK_FLAG(3), /* widget has been hovered on the current frame */ + NK_WIDGET_STATE_HOVER = NK_FLAG(4), /* widget is being hovered */ + NK_WIDGET_STATE_ACTIVED = NK_FLAG(5),/* widget is currently activated */ + NK_WIDGET_STATE_LEFT = NK_FLAG(6), /* widget is from this frame on not hovered anymore */ + NK_WIDGET_STATE_HOVERED = NK_WIDGET_STATE_HOVER|NK_WIDGET_STATE_MODIFIED, /* widget is being hovered */ + NK_WIDGET_STATE_ACTIVE = NK_WIDGET_STATE_ACTIVED|NK_WIDGET_STATE_MODIFIED /* widget is currently activated */ +}; +NK_API enum nk_widget_layout_states nk_widget(struct nk_rect*, const struct nk_context*); +NK_API enum nk_widget_layout_states nk_widget_fitting(struct nk_rect*, struct nk_context*, struct nk_vec2); +NK_API struct nk_rect nk_widget_bounds(struct nk_context*); +NK_API struct nk_vec2 nk_widget_position(struct nk_context*); +NK_API struct nk_vec2 nk_widget_size(struct nk_context*); +NK_API float nk_widget_width(struct nk_context*); +NK_API float nk_widget_height(struct nk_context*); +NK_API int nk_widget_is_hovered(struct nk_context*); +NK_API int nk_widget_is_mouse_clicked(struct nk_context*, enum nk_buttons); +NK_API int nk_widget_has_mouse_click_down(struct nk_context*, enum nk_buttons, int down); +NK_API void nk_spacing(struct nk_context*, int cols); +/* ============================================================================= + * + * TEXT + * + * ============================================================================= */ +enum nk_text_align { + NK_TEXT_ALIGN_LEFT = 0x01, + NK_TEXT_ALIGN_CENTERED = 0x02, + NK_TEXT_ALIGN_RIGHT = 0x04, + NK_TEXT_ALIGN_TOP = 0x08, + NK_TEXT_ALIGN_MIDDLE = 0x10, + NK_TEXT_ALIGN_BOTTOM = 0x20 +}; +enum nk_text_alignment { + NK_TEXT_LEFT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_LEFT, + NK_TEXT_CENTERED = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_CENTERED, + NK_TEXT_RIGHT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_RIGHT +}; +NK_API void nk_text(struct nk_context*, const char*, int, nk_flags); +NK_API void nk_text_colored(struct nk_context*, const char*, int, nk_flags, struct nk_color); +NK_API void nk_text_wrap(struct nk_context*, const char*, int); +NK_API void nk_text_wrap_colored(struct nk_context*, const char*, int, struct nk_color); +NK_API void nk_label(struct nk_context*, const char*, nk_flags align); +NK_API void nk_label_colored(struct nk_context*, const char*, nk_flags align, struct nk_color); +NK_API void nk_label_wrap(struct nk_context*, const char*); +NK_API void nk_label_colored_wrap(struct nk_context*, const char*, struct nk_color); +NK_API void nk_image(struct nk_context*, struct nk_image); +#ifdef NK_INCLUDE_STANDARD_VARARGS +NK_API void nk_labelf(struct nk_context*, nk_flags, const char*, ...); +NK_API void nk_labelf_colored(struct nk_context*, nk_flags align, struct nk_color, const char*,...); +NK_API void nk_labelf_wrap(struct nk_context*, const char*,...); +NK_API void nk_labelf_colored_wrap(struct nk_context*, struct nk_color, const char*,...); +NK_API void nk_value_bool(struct nk_context*, const char *prefix, int); +NK_API void nk_value_int(struct nk_context*, const char *prefix, int); +NK_API void nk_value_uint(struct nk_context*, const char *prefix, unsigned int); +NK_API void nk_value_float(struct nk_context*, const char *prefix, float); +NK_API void nk_value_color_byte(struct nk_context*, const char *prefix, struct nk_color); +NK_API void nk_value_color_float(struct nk_context*, const char *prefix, struct nk_color); +NK_API void nk_value_color_hex(struct nk_context*, const char *prefix, struct nk_color); +#endif +/* ============================================================================= + * + * BUTTON + * + * ============================================================================= */ +NK_API int nk_button_text(struct nk_context*, const char *title, int len); +NK_API int nk_button_label(struct nk_context*, const char *title); +NK_API int nk_button_color(struct nk_context*, struct nk_color); +NK_API int nk_button_symbol(struct nk_context*, enum nk_symbol_type); +NK_API int nk_button_image(struct nk_context*, struct nk_image img); +NK_API int nk_button_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags text_alignment); +NK_API int nk_button_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); +NK_API int nk_button_image_label(struct nk_context*, struct nk_image img, const char*, nk_flags text_alignment); +NK_API int nk_button_image_text(struct nk_context*, struct nk_image img, const char*, int, nk_flags alignment); +NK_API int nk_button_text_styled(struct nk_context*, const struct nk_style_button*, const char *title, int len); +NK_API int nk_button_label_styled(struct nk_context*, const struct nk_style_button*, const char *title); +NK_API int nk_button_symbol_styled(struct nk_context*, const struct nk_style_button*, enum nk_symbol_type); +NK_API int nk_button_image_styled(struct nk_context*, const struct nk_style_button*, struct nk_image img); +NK_API int nk_button_symbol_text_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, int, nk_flags alignment); +NK_API int nk_button_symbol_label_styled(struct nk_context *ctx, const struct nk_style_button *style, enum nk_symbol_type symbol, const char *title, nk_flags align); +NK_API int nk_button_image_label_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, nk_flags text_alignment); +NK_API int nk_button_image_text_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, int, nk_flags alignment); +NK_API void nk_button_set_behavior(struct nk_context*, enum nk_button_behavior); +NK_API int nk_button_push_behavior(struct nk_context*, enum nk_button_behavior); +NK_API int nk_button_pop_behavior(struct nk_context*); +/* ============================================================================= + * + * CHECKBOX + * + * ============================================================================= */ +NK_API int nk_check_label(struct nk_context*, const char*, int active); +NK_API int nk_check_text(struct nk_context*, const char*, int,int active); +NK_API unsigned nk_check_flags_label(struct nk_context*, const char*, unsigned int flags, unsigned int value); +NK_API unsigned nk_check_flags_text(struct nk_context*, const char*, int, unsigned int flags, unsigned int value); +NK_API int nk_checkbox_label(struct nk_context*, const char*, int *active); +NK_API int nk_checkbox_text(struct nk_context*, const char*, int, int *active); +NK_API int nk_checkbox_flags_label(struct nk_context*, const char*, unsigned int *flags, unsigned int value); +NK_API int nk_checkbox_flags_text(struct nk_context*, const char*, int, unsigned int *flags, unsigned int value); +/* ============================================================================= + * + * RADIO BUTTON + * + * ============================================================================= */ +NK_API int nk_radio_label(struct nk_context*, const char*, int *active); +NK_API int nk_radio_text(struct nk_context*, const char*, int, int *active); +NK_API int nk_option_label(struct nk_context*, const char*, int active); +NK_API int nk_option_text(struct nk_context*, const char*, int, int active); +/* ============================================================================= + * + * SELECTABLE + * + * ============================================================================= */ +NK_API int nk_selectable_label(struct nk_context*, const char*, nk_flags align, int *value); +NK_API int nk_selectable_text(struct nk_context*, const char*, int, nk_flags align, int *value); +NK_API int nk_selectable_image_label(struct nk_context*,struct nk_image, const char*, nk_flags align, int *value); +NK_API int nk_selectable_image_text(struct nk_context*,struct nk_image, const char*, int, nk_flags align, int *value); +NK_API int nk_select_label(struct nk_context*, const char*, nk_flags align, int value); +NK_API int nk_select_text(struct nk_context*, const char*, int, nk_flags align, int value); +NK_API int nk_select_image_label(struct nk_context*, struct nk_image,const char*, nk_flags align, int value); +NK_API int nk_select_image_text(struct nk_context*, struct nk_image,const char*, int, nk_flags align, int value); +/* ============================================================================= + * + * SLIDER + * + * ============================================================================= */ +NK_API float nk_slide_float(struct nk_context*, float min, float val, float max, float step); +NK_API int nk_slide_int(struct nk_context*, int min, int val, int max, int step); +NK_API int nk_slider_float(struct nk_context*, float min, float *val, float max, float step); +NK_API int nk_slider_int(struct nk_context*, int min, int *val, int max, int step); +/* ============================================================================= + * + * PROGRESSBAR + * + * ============================================================================= */ +NK_API int nk_progress(struct nk_context*, nk_size *cur, nk_size max, int modifyable); +NK_API nk_size nk_prog(struct nk_context*, nk_size cur, nk_size max, int modifyable); + +/* ============================================================================= + * + * COLOR PICKER + * + * ============================================================================= */ +NK_API struct nk_color nk_color_picker(struct nk_context*, struct nk_color, enum nk_color_format); +NK_API int nk_color_pick(struct nk_context*, struct nk_color*, enum nk_color_format); +/* ============================================================================= + * + * PROPERTIES + * + * ============================================================================= */ +NK_API void nk_property_int(struct nk_context*, const char *name, int min, int *val, int max, int step, float inc_per_pixel); +NK_API void nk_property_float(struct nk_context*, const char *name, float min, float *val, float max, float step, float inc_per_pixel); +NK_API void nk_property_double(struct nk_context*, const char *name, double min, double *val, double max, double step, float inc_per_pixel); +NK_API int nk_propertyi(struct nk_context*, const char *name, int min, int val, int max, int step, float inc_per_pixel); +NK_API float nk_propertyf(struct nk_context*, const char *name, float min, float val, float max, float step, float inc_per_pixel); +NK_API double nk_propertyd(struct nk_context*, const char *name, double min, double val, double max, double step, float inc_per_pixel); +/* ============================================================================= + * + * TEXT EDIT + * + * ============================================================================= */ +enum nk_edit_flags { + NK_EDIT_DEFAULT = 0, + NK_EDIT_READ_ONLY = NK_FLAG(0), + NK_EDIT_AUTO_SELECT = NK_FLAG(1), + NK_EDIT_SIG_ENTER = NK_FLAG(2), + NK_EDIT_ALLOW_TAB = NK_FLAG(3), + NK_EDIT_NO_CURSOR = NK_FLAG(4), + NK_EDIT_SELECTABLE = NK_FLAG(5), + NK_EDIT_CLIPBOARD = NK_FLAG(6), + NK_EDIT_CTRL_ENTER_NEWLINE = NK_FLAG(7), + NK_EDIT_NO_HORIZONTAL_SCROLL = NK_FLAG(8), + NK_EDIT_ALWAYS_INSERT_MODE = NK_FLAG(9), + NK_EDIT_MULTILINE = NK_FLAG(10), + NK_EDIT_GOTO_END_ON_ACTIVATE = NK_FLAG(11) +}; +enum nk_edit_types { + NK_EDIT_SIMPLE = NK_EDIT_ALWAYS_INSERT_MODE, + NK_EDIT_FIELD = NK_EDIT_SIMPLE|NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD, + NK_EDIT_BOX = NK_EDIT_ALWAYS_INSERT_MODE| NK_EDIT_SELECTABLE| NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB|NK_EDIT_CLIPBOARD, + NK_EDIT_EDITOR = NK_EDIT_SELECTABLE|NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB| NK_EDIT_CLIPBOARD +}; +enum nk_edit_events { + NK_EDIT_ACTIVE = NK_FLAG(0), /* edit widget is currently being modified */ + NK_EDIT_INACTIVE = NK_FLAG(1), /* edit widget is not active and is not being modified */ + NK_EDIT_ACTIVATED = NK_FLAG(2), /* edit widget went from state inactive to state active */ + NK_EDIT_DEACTIVATED = NK_FLAG(3), /* edit widget went from state active to state inactive */ + NK_EDIT_COMMITED = NK_FLAG(4) /* edit widget has received an enter and lost focus */ +}; +NK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter); +NK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter); +NK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter); +NK_API void nk_edit_focus(struct nk_context*, nk_flags flags); +NK_API void nk_edit_unfocus(struct nk_context*); +/* ============================================================================= + * + * CHART + * + * ============================================================================= */ +NK_API int nk_chart_begin(struct nk_context*, enum nk_chart_type, int num, float min, float max); +NK_API int nk_chart_begin_colored(struct nk_context*, enum nk_chart_type, struct nk_color, struct nk_color active, int num, float min, float max); +NK_API void nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type, int count, float min_value, float max_value); +NK_API void nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type, struct nk_color, struct nk_color active, int count, float min_value, float max_value); +NK_API nk_flags nk_chart_push(struct nk_context*, float); +NK_API nk_flags nk_chart_push_slot(struct nk_context*, float, int); +NK_API void nk_chart_end(struct nk_context*); +NK_API void nk_plot(struct nk_context*, enum nk_chart_type, const float *values, int count, int offset); +NK_API void nk_plot_function(struct nk_context*, enum nk_chart_type, void *userdata, float(*value_getter)(void* user, int index), int count, int offset); +/* ============================================================================= + * + * POPUP + * + * ============================================================================= */ +NK_API int nk_popup_begin(struct nk_context*, enum nk_popup_type, const char*, nk_flags, struct nk_rect bounds); +NK_API void nk_popup_close(struct nk_context*); +NK_API void nk_popup_end(struct nk_context*); +/* ============================================================================= + * + * COMBOBOX + * + * ============================================================================= */ +NK_API int nk_combo(struct nk_context*, const char **items, int count, int selected, int item_height, struct nk_vec2 size); +NK_API int nk_combo_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int selected, int count, int item_height, struct nk_vec2 size); +NK_API int nk_combo_string(struct nk_context*, const char *items_separated_by_zeros, int selected, int count, int item_height, struct nk_vec2 size); +NK_API int nk_combo_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void *userdata, int selected, int count, int item_height, struct nk_vec2 size); +NK_API void nk_combobox(struct nk_context*, const char **items, int count, int *selected, int item_height, struct nk_vec2 size); +NK_API void nk_combobox_string(struct nk_context*, const char *items_separated_by_zeros, int *selected, int count, int item_height, struct nk_vec2 size); +NK_API void nk_combobox_separator(struct nk_context*, const char *items_separated_by_separator, int separator,int *selected, int count, int item_height, struct nk_vec2 size); +NK_API void nk_combobox_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void*, int *selected, int count, int item_height, struct nk_vec2 size); +/* ============================================================================= + * + * ABSTRACT COMBOBOX + * + * ============================================================================= */ +NK_API int nk_combo_begin_text(struct nk_context*, const char *selected, int, struct nk_vec2 size); +NK_API int nk_combo_begin_label(struct nk_context*, const char *selected, struct nk_vec2 size); +NK_API int nk_combo_begin_color(struct nk_context*, struct nk_color color, struct nk_vec2 size); +NK_API int nk_combo_begin_symbol(struct nk_context*, enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_combo_begin_symbol_label(struct nk_context*, const char *selected, enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_combo_begin_symbol_text(struct nk_context*, const char *selected, int, enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_combo_begin_image(struct nk_context*, struct nk_image img, struct nk_vec2 size); +NK_API int nk_combo_begin_image_label(struct nk_context*, const char *selected, struct nk_image, struct nk_vec2 size); +NK_API int nk_combo_begin_image_text(struct nk_context*, const char *selected, int, struct nk_image, struct nk_vec2 size); +NK_API int nk_combo_item_label(struct nk_context*, const char*, nk_flags alignment); +NK_API int nk_combo_item_text(struct nk_context*, const char*,int, nk_flags alignment); +NK_API int nk_combo_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); +NK_API int nk_combo_item_image_text(struct nk_context*, struct nk_image, const char*, int,nk_flags alignment); +NK_API int nk_combo_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); +NK_API int nk_combo_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); +NK_API void nk_combo_close(struct nk_context*); +NK_API void nk_combo_end(struct nk_context*); +/* ============================================================================= + * + * CONTEXTUAL + * + * ============================================================================= */ +NK_API int nk_contextual_begin(struct nk_context*, nk_flags, struct nk_vec2, struct nk_rect trigger_bounds); +NK_API int nk_contextual_item_text(struct nk_context*, const char*, int,nk_flags align); +NK_API int nk_contextual_item_label(struct nk_context*, const char*, nk_flags align); +NK_API int nk_contextual_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); +NK_API int nk_contextual_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); +NK_API int nk_contextual_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); +NK_API int nk_contextual_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); +NK_API void nk_contextual_close(struct nk_context*); +NK_API void nk_contextual_end(struct nk_context*); +/* ============================================================================= + * + * TOOLTIP + * + * ============================================================================= */ +NK_API void nk_tooltip(struct nk_context*, const char*); +NK_API int nk_tooltip_begin(struct nk_context*, float width); +NK_API void nk_tooltip_end(struct nk_context*); +/* ============================================================================= + * + * MENU + * + * ============================================================================= */ +NK_API void nk_menubar_begin(struct nk_context*); +NK_API void nk_menubar_end(struct nk_context*); +NK_API int nk_menu_begin_text(struct nk_context*, const char* title, int title_len, nk_flags align, struct nk_vec2 size); +NK_API int nk_menu_begin_label(struct nk_context*, const char*, nk_flags align, struct nk_vec2 size); +NK_API int nk_menu_begin_image(struct nk_context*, const char*, struct nk_image, struct nk_vec2 size); +NK_API int nk_menu_begin_image_text(struct nk_context*, const char*, int,nk_flags align,struct nk_image, struct nk_vec2 size); +NK_API int nk_menu_begin_image_label(struct nk_context*, const char*, nk_flags align,struct nk_image, struct nk_vec2 size); +NK_API int nk_menu_begin_symbol(struct nk_context*, const char*, enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_menu_begin_symbol_text(struct nk_context*, const char*, int,nk_flags align,enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_menu_begin_symbol_label(struct nk_context*, const char*, nk_flags align,enum nk_symbol_type, struct nk_vec2 size); +NK_API int nk_menu_item_text(struct nk_context*, const char*, int,nk_flags align); +NK_API int nk_menu_item_label(struct nk_context*, const char*, nk_flags alignment); +NK_API int nk_menu_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); +NK_API int nk_menu_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); +NK_API int nk_menu_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); +NK_API int nk_menu_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); +NK_API void nk_menu_close(struct nk_context*); +NK_API void nk_menu_end(struct nk_context*); +/* ============================================================================= + * + * STYLE + * + * ============================================================================= */ +enum nk_style_colors { + NK_COLOR_TEXT, + NK_COLOR_WINDOW, + NK_COLOR_HEADER, + NK_COLOR_BORDER, + NK_COLOR_BUTTON, + NK_COLOR_BUTTON_HOVER, + NK_COLOR_BUTTON_ACTIVE, + NK_COLOR_TOGGLE, + NK_COLOR_TOGGLE_HOVER, + NK_COLOR_TOGGLE_CURSOR, + NK_COLOR_SELECT, + NK_COLOR_SELECT_ACTIVE, + NK_COLOR_SLIDER, + NK_COLOR_SLIDER_CURSOR, + NK_COLOR_SLIDER_CURSOR_HOVER, + NK_COLOR_SLIDER_CURSOR_ACTIVE, + NK_COLOR_PROPERTY, + NK_COLOR_EDIT, + NK_COLOR_EDIT_CURSOR, + NK_COLOR_COMBO, + NK_COLOR_CHART, + NK_COLOR_CHART_COLOR, + NK_COLOR_CHART_COLOR_HIGHLIGHT, + NK_COLOR_SCROLLBAR, + NK_COLOR_SCROLLBAR_CURSOR, + NK_COLOR_SCROLLBAR_CURSOR_HOVER, + NK_COLOR_SCROLLBAR_CURSOR_ACTIVE, + NK_COLOR_TAB_HEADER, + NK_COLOR_COUNT +}; +enum nk_style_cursor { + NK_CURSOR_ARROW, + NK_CURSOR_TEXT, + NK_CURSOR_MOVE, + NK_CURSOR_RESIZE_VERTICAL, + NK_CURSOR_RESIZE_HORIZONTAL, + NK_CURSOR_RESIZE_TOP_LEFT_DOWN_RIGHT, + NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT, + NK_CURSOR_COUNT +}; +NK_API void nk_style_default(struct nk_context*); +NK_API void nk_style_from_table(struct nk_context*, const struct nk_color*); +NK_API void nk_style_load_cursor(struct nk_context*, enum nk_style_cursor, const struct nk_cursor*); +NK_API void nk_style_load_all_cursors(struct nk_context*, struct nk_cursor*); +NK_API const char* nk_style_get_color_by_name(enum nk_style_colors); +NK_API void nk_style_set_font(struct nk_context*, const struct nk_user_font*); +NK_API int nk_style_set_cursor(struct nk_context*, enum nk_style_cursor); +NK_API void nk_style_show_cursor(struct nk_context*); +NK_API void nk_style_hide_cursor(struct nk_context*); + +NK_API int nk_style_push_font(struct nk_context*, const struct nk_user_font*); +NK_API int nk_style_push_float(struct nk_context*, float*, float); +NK_API int nk_style_push_vec2(struct nk_context*, struct nk_vec2*, struct nk_vec2); +NK_API int nk_style_push_style_item(struct nk_context*, struct nk_style_item*, struct nk_style_item); +NK_API int nk_style_push_flags(struct nk_context*, nk_flags*, nk_flags); +NK_API int nk_style_push_color(struct nk_context*, struct nk_color*, struct nk_color); + +NK_API int nk_style_pop_font(struct nk_context*); +NK_API int nk_style_pop_float(struct nk_context*); +NK_API int nk_style_pop_vec2(struct nk_context*); +NK_API int nk_style_pop_style_item(struct nk_context*); +NK_API int nk_style_pop_flags(struct nk_context*); +NK_API int nk_style_pop_color(struct nk_context*); +/* ============================================================================= + * + * COLOR + * + * ============================================================================= */ +NK_API struct nk_color nk_rgb(int r, int g, int b); +NK_API struct nk_color nk_rgb_iv(const int *rgb); +NK_API struct nk_color nk_rgb_bv(const nk_byte* rgb); +NK_API struct nk_color nk_rgb_f(float r, float g, float b); +NK_API struct nk_color nk_rgb_fv(const float *rgb); +NK_API struct nk_color nk_rgb_hex(const char *rgb); + +NK_API struct nk_color nk_rgba(int r, int g, int b, int a); +NK_API struct nk_color nk_rgba_u32(nk_uint); +NK_API struct nk_color nk_rgba_iv(const int *rgba); +NK_API struct nk_color nk_rgba_bv(const nk_byte *rgba); +NK_API struct nk_color nk_rgba_f(float r, float g, float b, float a); +NK_API struct nk_color nk_rgba_fv(const float *rgba); +NK_API struct nk_color nk_rgba_hex(const char *rgb); + +NK_API struct nk_color nk_hsv(int h, int s, int v); +NK_API struct nk_color nk_hsv_iv(const int *hsv); +NK_API struct nk_color nk_hsv_bv(const nk_byte *hsv); +NK_API struct nk_color nk_hsv_f(float h, float s, float v); +NK_API struct nk_color nk_hsv_fv(const float *hsv); + +NK_API struct nk_color nk_hsva(int h, int s, int v, int a); +NK_API struct nk_color nk_hsva_iv(const int *hsva); +NK_API struct nk_color nk_hsva_bv(const nk_byte *hsva); +NK_API struct nk_color nk_hsva_f(float h, float s, float v, float a); +NK_API struct nk_color nk_hsva_fv(const float *hsva); + +/* color (conversion nuklear --> user) */ +NK_API void nk_color_f(float *r, float *g, float *b, float *a, struct nk_color); +NK_API void nk_color_fv(float *rgba_out, struct nk_color); +NK_API void nk_color_d(double *r, double *g, double *b, double *a, struct nk_color); +NK_API void nk_color_dv(double *rgba_out, struct nk_color); + +NK_API nk_uint nk_color_u32(struct nk_color); +NK_API void nk_color_hex_rgba(char *output, struct nk_color); +NK_API void nk_color_hex_rgb(char *output, struct nk_color); + +NK_API void nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color); +NK_API void nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color); +NK_API void nk_color_hsv_iv(int *hsv_out, struct nk_color); +NK_API void nk_color_hsv_bv(nk_byte *hsv_out, struct nk_color); +NK_API void nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color); +NK_API void nk_color_hsv_fv(float *hsv_out, struct nk_color); + +NK_API void nk_color_hsva_i(int *h, int *s, int *v, int *a, struct nk_color); +NK_API void nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color); +NK_API void nk_color_hsva_iv(int *hsva_out, struct nk_color); +NK_API void nk_color_hsva_bv(nk_byte *hsva_out, struct nk_color); +NK_API void nk_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_color); +NK_API void nk_color_hsva_fv(float *hsva_out, struct nk_color); +/* ============================================================================= + * + * IMAGE + * + * ============================================================================= */ +NK_API nk_handle nk_handle_ptr(void*); +NK_API nk_handle nk_handle_id(int); +NK_API struct nk_image nk_image_handle(nk_handle); +NK_API struct nk_image nk_image_ptr(void*); +NK_API struct nk_image nk_image_id(int); +NK_API int nk_image_is_subimage(const struct nk_image* img); +NK_API struct nk_image nk_subimage_ptr(void*, unsigned short w, unsigned short h, struct nk_rect sub_region); +NK_API struct nk_image nk_subimage_id(int, unsigned short w, unsigned short h, struct nk_rect sub_region); +NK_API struct nk_image nk_subimage_handle(nk_handle, unsigned short w, unsigned short h, struct nk_rect sub_region); +/* ============================================================================= + * + * MATH + * + * ============================================================================= */ +NK_API nk_hash nk_murmur_hash(const void *key, int len, nk_hash seed); +NK_API void nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, float pad_x, float pad_y, enum nk_heading); + +NK_API struct nk_vec2 nk_vec2(float x, float y); +NK_API struct nk_vec2 nk_vec2i(int x, int y); +NK_API struct nk_vec2 nk_vec2v(const float *xy); +NK_API struct nk_vec2 nk_vec2iv(const int *xy); + +NK_API struct nk_rect nk_get_null_rect(void); +NK_API struct nk_rect nk_rect(float x, float y, float w, float h); +NK_API struct nk_rect nk_recti(int x, int y, int w, int h); +NK_API struct nk_rect nk_recta(struct nk_vec2 pos, struct nk_vec2 size); +NK_API struct nk_rect nk_rectv(const float *xywh); +NK_API struct nk_rect nk_rectiv(const int *xywh); +NK_API struct nk_vec2 nk_rect_pos(struct nk_rect); +NK_API struct nk_vec2 nk_rect_size(struct nk_rect); +/* ============================================================================= + * + * STRING + * + * ============================================================================= */ +NK_API int nk_strlen(const char *str); +NK_API int nk_stricmp(const char *s1, const char *s2); +NK_API int nk_stricmpn(const char *s1, const char *s2, int n); +NK_API int nk_strtoi(const char *str, const char **endptr); +NK_API float nk_strtof(const char *str, const char **endptr); +NK_API double nk_strtod(const char *str, const char **endptr); +NK_API int nk_strfilter(const char *text, const char *regexp); +NK_API int nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score); +NK_API int nk_strmatch_fuzzy_text(const char *txt, int txt_len, const char *pattern, int *out_score); +/* ============================================================================= + * + * UTF-8 + * + * ============================================================================= */ +NK_API int nk_utf_decode(const char*, nk_rune*, int); +NK_API int nk_utf_encode(nk_rune, char*, int); +NK_API int nk_utf_len(const char*, int byte_len); +NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune *unicode, int *len); +/* =============================================================== + * + * FONT + * + * ===============================================================*/ +/* Font handling in this library was designed to be quite customizable and lets + you decide what you want to use and what you want to provide. There are three + different ways to use the font atlas. The first two will use your font + handling scheme and only requires essential data to run nuklear. The next + slightly more advanced features is font handling with vertex buffer output. + Finally the most complex API wise is using nuklears font baking API. + + 1.) Using your own implementation without vertex buffer output + -------------------------------------------------------------- + So first up the easiest way to do font handling is by just providing a + `nk_user_font` struct which only requires the height in pixel of the used + font and a callback to calculate the width of a string. This way of handling + fonts is best fitted for using the normal draw shape command API where you + do all the text drawing yourself and the library does not require any kind + of deeper knowledge about which font handling mechanism you use. + IMPORTANT: the `nk_user_font` pointer provided to nuklear has to persist + over the complete life time! I know this sucks but it is currently the only + way to switch between fonts. + + float your_text_width_calculation(nk_handle handle, float height, const char *text, int len) + { + your_font_type *type = handle.ptr; + float text_width = ...; + return text_width; + } + + struct nk_user_font font; + font.userdata.ptr = &your_font_class_or_struct; + font.height = your_font_height; + font.width = your_text_width_calculation; + + struct nk_context ctx; + nk_init_default(&ctx, &font); + + 2.) Using your own implementation with vertex buffer output + -------------------------------------------------------------- + While the first approach works fine if you don't want to use the optional + vertex buffer output it is not enough if you do. To get font handling working + for these cases you have to provide two additional parameters inside the + `nk_user_font`. First a texture atlas handle used to draw text as subimages + of a bigger font atlas texture and a callback to query a character's glyph + information (offset, size, ...). So it is still possible to provide your own + font and use the vertex buffer output. + + float your_text_width_calculation(nk_handle handle, float height, const char *text, int len) + { + your_font_type *type = handle.ptr; + float text_width = ...; + return text_width; + } + void query_your_font_glyph(nk_handle handle, float font_height, struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint) + { + your_font_type *type = handle.ptr; + glyph.width = ...; + glyph.height = ...; + glyph.xadvance = ...; + glyph.uv[0].x = ...; + glyph.uv[0].y = ...; + glyph.uv[1].x = ...; + glyph.uv[1].y = ...; + glyph.offset.x = ...; + glyph.offset.y = ...; + } + + struct nk_user_font font; + font.userdata.ptr = &your_font_class_or_struct; + font.height = your_font_height; + font.width = your_text_width_calculation; + font.query = query_your_font_glyph; + font.texture.id = your_font_texture; + + struct nk_context ctx; + nk_init_default(&ctx, &font); + + 3.) Nuklear font baker + ------------------------------------ + The final approach if you do not have a font handling functionality or don't + want to use it in this library is by using the optional font baker. + The font baker API's can be used to create a font plus font atlas texture + and can be used with or without the vertex buffer output. + + It still uses the `nk_user_font` struct and the two different approaches + previously stated still work. The font baker is not located inside + `nk_context` like all other systems since it can be understood as more of + an extension to nuklear and does not really depend on any `nk_context` state. + + Font baker need to be initialized first by one of the nk_font_atlas_init_xxx + functions. If you don't care about memory just call the default version + `nk_font_atlas_init_default` which will allocate all memory from the standard library. + If you want to control memory allocation but you don't care if the allocated + memory is temporary and therefore can be freed directly after the baking process + is over or permanent you can call `nk_font_atlas_init`. + + After successfull intializing the font baker you can add Truetype(.ttf) fonts from + different sources like memory or from file by calling one of the `nk_font_atlas_add_xxx`. + functions. Adding font will permanently store each font, font config and ttf memory block(!) + inside the font atlas and allows to reuse the font atlas. If you don't want to reuse + the font baker by for example adding additional fonts you can call + `nk_font_atlas_cleanup` after the baking process is over (after calling nk_font_atlas_end). + + As soon as you added all fonts you wanted you can now start the baking process + for every selected glyphes to image by calling `nk_font_atlas_bake`. + The baking process returns image memory, width and height which can be used to + either create your own image object or upload it to any graphics library. + No matter which case you finally have to call `nk_font_atlas_end` which + will free all temporary memory including the font atlas image so make sure + you created our texture beforehand. `nk_font_atlas_end` requires a handle + to your font texture or object and optionally fills a `struct nk_draw_null_texture` + which can be used for the optional vertex output. If you don't want it just + set the argument to `NULL`. + + At this point you are done and if you don't want to reuse the font atlas you + can call `nk_font_atlas_cleanup` to free all truetype blobs and configuration + memory. Finally if you don't use the font atlas and any of it's fonts anymore + you need to call `nk_font_atlas_clear` to free all memory still being used. + + struct nk_font_atlas atlas; + nk_font_atlas_init_default(&atlas); + nk_font_atlas_begin(&atlas); + nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, 0); + nk_font *font2 = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font2.ttf", 16, 0); + const void* img = nk_font_atlas_bake(&atlas, &img_width, &img_height, NK_FONT_ATLAS_RGBA32); + nk_font_atlas_end(&atlas, nk_handle_id(texture), 0); + + struct nk_context ctx; + nk_init_default(&ctx, &font->handle); + while (1) { + + } + nk_font_atlas_clear(&atlas); + + The font baker API is probably the most complex API inside this library and + I would suggest reading some of my examples `example/` to get a grip on how + to use the font atlas. There are a number of details I left out. For example + how to merge fonts, configure a font with `nk_font_config` to use other languages, + use another texture coodinate format and a lot more: + + struct nk_font_config cfg = nk_font_config(font_pixel_height); + cfg.merge_mode = nk_false or nk_true; + cfg.range = nk_font_korean_glyph_ranges(); + cfg.coord_type = NK_COORD_PIXEL; + nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, &cfg); + +*/ +struct nk_user_font_glyph; +typedef float(*nk_text_width_f)(nk_handle, float h, const char*, int len); +typedef void(*nk_query_font_glyph_f)(nk_handle handle, float font_height, + struct nk_user_font_glyph *glyph, + nk_rune codepoint, nk_rune next_codepoint); + +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT +struct nk_user_font_glyph { + struct nk_vec2 uv[2]; + /* texture coordinates */ + struct nk_vec2 offset; + /* offset between top left and glyph */ + float width, height; + /* size of the glyph */ + float xadvance; + /* offset to the next glyph */ +}; +#endif + +struct nk_user_font { + nk_handle userdata; + /* user provided font handle */ + float height; + /* max height of the font */ + nk_text_width_f width; + /* font string width in pixel callback */ +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT + nk_query_font_glyph_f query; + /* font glyph callback to query drawing info */ + nk_handle texture; + /* texture handle to the used font atlas or texture */ +#endif +}; + +#ifdef NK_INCLUDE_FONT_BAKING +enum nk_font_coord_type { + NK_COORD_UV, /* texture coordinates inside font glyphs are clamped between 0-1 */ + NK_COORD_PIXEL /* texture coordinates inside font glyphs are in absolute pixel */ +}; + +struct nk_baked_font { + float height; + /* height of the font */ + float ascent, descent; + /* font glyphs ascent and descent */ + nk_rune glyph_offset; + /* glyph array offset inside the font glyph baking output array */ + nk_rune glyph_count; + /* number of glyphs of this font inside the glyph baking array output */ + const nk_rune *ranges; + /* font codepoint ranges as pairs of (from/to) and 0 as last element */ +}; + +struct nk_font_config { + struct nk_font_config *next; + /* NOTE: only used internally */ + void *ttf_blob; + /* pointer to loaded TTF file memory block. + * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */ + nk_size ttf_size; + /* size of the loaded TTF file memory block + * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */ + + unsigned char ttf_data_owned_by_atlas; + /* used inside font atlas: default to: 0*/ + unsigned char merge_mode; + /* merges this font into the last font */ + unsigned char pixel_snap; + /* align every character to pixel boundary (if true set oversample (1,1)) */ + unsigned char oversample_v, oversample_h; + /* rasterize at hight quality for sub-pixel position */ + unsigned char padding[3]; + + float size; + /* baked pixel height of the font */ + enum nk_font_coord_type coord_type; + /* texture coordinate format with either pixel or UV coordinates */ + struct nk_vec2 spacing; + /* extra pixel spacing between glyphs */ + const nk_rune *range; + /* list of unicode ranges (2 values per range, zero terminated) */ + struct nk_baked_font *font; + /* font to setup in the baking process: NOTE: not needed for font atlas */ + nk_rune fallback_glyph; + /* fallback glyph to use if a given rune is not found */ +}; + +struct nk_font_glyph { + nk_rune codepoint; + float xadvance; + float x0, y0, x1, y1, w, h; + float u0, v0, u1, v1; +}; + +struct nk_font { + struct nk_font *next; + struct nk_user_font handle; + struct nk_baked_font info; + float scale; + struct nk_font_glyph *glyphs; + const struct nk_font_glyph *fallback; + nk_rune fallback_codepoint; + nk_handle texture; + struct nk_font_config *config; +}; + +enum nk_font_atlas_format { + NK_FONT_ATLAS_ALPHA8, + NK_FONT_ATLAS_RGBA32 +}; + +struct nk_font_atlas { + void *pixel; + int tex_width; + int tex_height; + + struct nk_allocator permanent; + struct nk_allocator temporary; + + struct nk_recti custom; + struct nk_cursor cursors[NK_CURSOR_COUNT]; + + int glyph_count; + struct nk_font_glyph *glyphs; + struct nk_font *default_font; + struct nk_font *fonts; + struct nk_font_config *config; + int font_num; +}; + +/* some language glyph codepoint ranges */ +NK_API const nk_rune *nk_font_default_glyph_ranges(void); +NK_API const nk_rune *nk_font_chinese_glyph_ranges(void); +NK_API const nk_rune *nk_font_cyrillic_glyph_ranges(void); +NK_API const nk_rune *nk_font_korean_glyph_ranges(void); + +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +NK_API void nk_font_atlas_init_default(struct nk_font_atlas*); +#endif +NK_API void nk_font_atlas_init(struct nk_font_atlas*, struct nk_allocator*); +NK_API void nk_font_atlas_init_custom(struct nk_font_atlas*, struct nk_allocator *persistent, struct nk_allocator *transient); +NK_API void nk_font_atlas_begin(struct nk_font_atlas*); +NK_API struct nk_font_config nk_font_config(float pixel_height); +NK_API struct nk_font *nk_font_atlas_add(struct nk_font_atlas*, const struct nk_font_config*); +#ifdef NK_INCLUDE_DEFAULT_FONT +NK_API struct nk_font* nk_font_atlas_add_default(struct nk_font_atlas*, float height, const struct nk_font_config*); +#endif +NK_API struct nk_font* nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, nk_size size, float height, const struct nk_font_config *config); +#ifdef NK_INCLUDE_STANDARD_IO +NK_API struct nk_font* nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, float height, const struct nk_font_config*); +#endif +NK_API struct nk_font *nk_font_atlas_add_compressed(struct nk_font_atlas*, void *memory, nk_size size, float height, const struct nk_font_config*); +NK_API struct nk_font* nk_font_atlas_add_compressed_base85(struct nk_font_atlas*, const char *data, float height, const struct nk_font_config *config); +NK_API const void* nk_font_atlas_bake(struct nk_font_atlas*, int *width, int *height, enum nk_font_atlas_format); +NK_API void nk_font_atlas_end(struct nk_font_atlas*, nk_handle tex, struct nk_draw_null_texture*); +NK_API const struct nk_font_glyph* nk_font_find_glyph(struct nk_font*, nk_rune unicode); +NK_API void nk_font_atlas_cleanup(struct nk_font_atlas *atlas); +NK_API void nk_font_atlas_clear(struct nk_font_atlas*); + +#endif + +/* ============================================================== + * + * MEMORY BUFFER + * + * ===============================================================*/ +/* A basic (double)-buffer with linear allocation and resetting as only + freeing policy. The buffer's main purpose is to control all memory management + inside the GUI toolkit and still leave memory control as much as possible in + the hand of the user while also making sure the library is easy to use if + not as much control is needed. + In general all memory inside this library can be provided from the user in + three different ways. + + The first way and the one providing most control is by just passing a fixed + size memory block. In this case all control lies in the hand of the user + since he can exactly control where the memory comes from and how much memory + the library should consume. Of course using the fixed size API removes the + ability to automatically resize a buffer if not enough memory is provided so + you have to take over the resizing. While being a fixed sized buffer sounds + quite limiting, it is very effective in this library since the actual memory + consumption is quite stable and has a fixed upper bound for a lot of cases. + + If you don't want to think about how much memory the library should allocate + at all time or have a very dynamic UI with unpredictable memory consumption + habits but still want control over memory allocation you can use the dynamic + allocator based API. The allocator consists of two callbacks for allocating + and freeing memory and optional userdata so you can plugin your own allocator. + + The final and easiest way can be used by defining + NK_INCLUDE_DEFAULT_ALLOCATOR which uses the standard library memory + allocation functions malloc and free and takes over complete control over + memory in this library. +*/ +struct nk_memory_status { + void *memory; + unsigned int type; + nk_size size; + nk_size allocated; + nk_size needed; + nk_size calls; +}; + +enum nk_allocation_type { + NK_BUFFER_FIXED, + NK_BUFFER_DYNAMIC +}; + +enum nk_buffer_allocation_type { + NK_BUFFER_FRONT, + NK_BUFFER_BACK, + NK_BUFFER_MAX +}; + +struct nk_buffer_marker { + int active; + nk_size offset; +}; + +struct nk_memory {void *ptr;nk_size size;}; +struct nk_buffer { + struct nk_buffer_marker marker[NK_BUFFER_MAX]; + /* buffer marker to free a buffer to a certain offset */ + struct nk_allocator pool; + /* allocator callback for dynamic buffers */ + enum nk_allocation_type type; + /* memory management type */ + struct nk_memory memory; + /* memory and size of the current memory block */ + float grow_factor; + /* growing factor for dynamic memory management */ + nk_size allocated; + /* total amount of memory allocated */ + nk_size needed; + /* totally consumed memory given that enough memory is present */ + nk_size calls; + /* number of allocation calls */ + nk_size size; + /* current size of the buffer */ +}; + +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +NK_API void nk_buffer_init_default(struct nk_buffer*); +#endif +NK_API void nk_buffer_init(struct nk_buffer*, const struct nk_allocator*, nk_size size); +NK_API void nk_buffer_init_fixed(struct nk_buffer*, void *memory, nk_size size); +NK_API void nk_buffer_info(struct nk_memory_status*, struct nk_buffer*); +NK_API void nk_buffer_push(struct nk_buffer*, enum nk_buffer_allocation_type type, const void *memory, nk_size size, nk_size align); +NK_API void nk_buffer_mark(struct nk_buffer*, enum nk_buffer_allocation_type type); +NK_API void nk_buffer_reset(struct nk_buffer*, enum nk_buffer_allocation_type type); +NK_API void nk_buffer_clear(struct nk_buffer*); +NK_API void nk_buffer_free(struct nk_buffer*); +NK_API void *nk_buffer_memory(struct nk_buffer*); +NK_API const void *nk_buffer_memory_const(const struct nk_buffer*); +NK_API nk_size nk_buffer_total(struct nk_buffer*); + +/* ============================================================== + * + * STRING + * + * ===============================================================*/ +/* Basic string buffer which is only used in context with the text editor + * to manage and manipulate dynamic or fixed size string content. This is _NOT_ + * the default string handling method. The only instance you should have any contact + * with this API is if you interact with an `nk_text_edit` object inside one of the + * copy and paste functions and even there only for more advanced cases. */ +struct nk_str { + struct nk_buffer buffer; + int len; /* in codepoints/runes/glyphs */ +}; + +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +NK_API void nk_str_init_default(struct nk_str*); +#endif +NK_API void nk_str_init(struct nk_str*, const struct nk_allocator*, nk_size size); +NK_API void nk_str_init_fixed(struct nk_str*, void *memory, nk_size size); +NK_API void nk_str_clear(struct nk_str*); +NK_API void nk_str_free(struct nk_str*); + +NK_API int nk_str_append_text_char(struct nk_str*, const char*, int); +NK_API int nk_str_append_str_char(struct nk_str*, const char*); +NK_API int nk_str_append_text_utf8(struct nk_str*, const char*, int); +NK_API int nk_str_append_str_utf8(struct nk_str*, const char*); +NK_API int nk_str_append_text_runes(struct nk_str*, const nk_rune*, int); +NK_API int nk_str_append_str_runes(struct nk_str*, const nk_rune*); + +NK_API int nk_str_insert_at_char(struct nk_str*, int pos, const char*, int); +NK_API int nk_str_insert_at_rune(struct nk_str*, int pos, const char*, int); + +NK_API int nk_str_insert_text_char(struct nk_str*, int pos, const char*, int); +NK_API int nk_str_insert_str_char(struct nk_str*, int pos, const char*); +NK_API int nk_str_insert_text_utf8(struct nk_str*, int pos, const char*, int); +NK_API int nk_str_insert_str_utf8(struct nk_str*, int pos, const char*); +NK_API int nk_str_insert_text_runes(struct nk_str*, int pos, const nk_rune*, int); +NK_API int nk_str_insert_str_runes(struct nk_str*, int pos, const nk_rune*); + +NK_API void nk_str_remove_chars(struct nk_str*, int len); +NK_API void nk_str_remove_runes(struct nk_str *str, int len); +NK_API void nk_str_delete_chars(struct nk_str*, int pos, int len); +NK_API void nk_str_delete_runes(struct nk_str*, int pos, int len); + +NK_API char *nk_str_at_char(struct nk_str*, int pos); +NK_API char *nk_str_at_rune(struct nk_str*, int pos, nk_rune *unicode, int *len); +NK_API nk_rune nk_str_rune_at(const struct nk_str*, int pos); +NK_API const char *nk_str_at_char_const(const struct nk_str*, int pos); +NK_API const char *nk_str_at_const(const struct nk_str*, int pos, nk_rune *unicode, int *len); + +NK_API char *nk_str_get(struct nk_str*); +NK_API const char *nk_str_get_const(const struct nk_str*); +NK_API int nk_str_len(struct nk_str*); +NK_API int nk_str_len_char(struct nk_str*); + +/*=============================================================== + * + * TEXT EDITOR + * + * ===============================================================*/ +/* Editing text in this library is handled by either `nk_edit_string` or + * `nk_edit_buffer`. But like almost everything in this library there are multiple + * ways of doing it and a balance between control and ease of use with memory + * as well as functionality controlled by flags. + * + * This library generally allows three different levels of memory control: + * First of is the most basic way of just providing a simple char array with + * string length. This method is probably the easiest way of handling simple + * user text input. Main upside is complete control over memory while the biggest + * downside in comparsion with the other two approaches is missing undo/redo. + * + * For UIs that require undo/redo the second way was created. It is based on + * a fixed size nk_text_edit struct, which has an internal undo/redo stack. + * This is mainly useful if you want something more like a text editor but don't want + * to have a dynamically growing buffer. + * + * The final way is using a dynamically growing nk_text_edit struct, which + * has both a default version if you don't care where memory comes from and an + * allocator version if you do. While the text editor is quite powerful for its + * complexity I would not recommend editing gigabytes of data with it. + * It is rather designed for uses cases which make sense for a GUI library not for + * an full blown text editor. + */ +#ifndef NK_TEXTEDIT_UNDOSTATECOUNT +#define NK_TEXTEDIT_UNDOSTATECOUNT 99 +#endif + +#ifndef NK_TEXTEDIT_UNDOCHARCOUNT +#define NK_TEXTEDIT_UNDOCHARCOUNT 999 +#endif + +struct nk_text_edit; +struct nk_clipboard { + nk_handle userdata; + nk_plugin_paste paste; + nk_plugin_copy copy; +}; + +struct nk_text_undo_record { + int where; + short insert_length; + short delete_length; + short char_storage; +}; + +struct nk_text_undo_state { + struct nk_text_undo_record undo_rec[NK_TEXTEDIT_UNDOSTATECOUNT]; + nk_rune undo_char[NK_TEXTEDIT_UNDOCHARCOUNT]; + short undo_point; + short redo_point; + short undo_char_point; + short redo_char_point; +}; + +enum nk_text_edit_type { + NK_TEXT_EDIT_SINGLE_LINE, + NK_TEXT_EDIT_MULTI_LINE +}; + +enum nk_text_edit_mode { + NK_TEXT_EDIT_MODE_VIEW, + NK_TEXT_EDIT_MODE_INSERT, + NK_TEXT_EDIT_MODE_REPLACE +}; + +struct nk_text_edit { + struct nk_clipboard clip; + struct nk_str string; + nk_plugin_filter filter; + struct nk_vec2 scrollbar; + + int cursor; + int select_start; + int select_end; + unsigned char mode; + unsigned char cursor_at_end_of_line; + unsigned char initialized; + unsigned char has_preferred_x; + unsigned char single_line; + unsigned char active; + unsigned char padding1; + float preferred_x; + struct nk_text_undo_state undo; +}; + +/* filter function */ +NK_API int nk_filter_default(const struct nk_text_edit*, nk_rune unicode); +NK_API int nk_filter_ascii(const struct nk_text_edit*, nk_rune unicode); +NK_API int nk_filter_float(const struct nk_text_edit*, nk_rune unicode); +NK_API int nk_filter_decimal(const struct nk_text_edit*, nk_rune unicode); +NK_API int nk_filter_hex(const struct nk_text_edit*, nk_rune unicode); +NK_API int nk_filter_oct(const struct nk_text_edit*, nk_rune unicode); +NK_API int nk_filter_binary(const struct nk_text_edit*, nk_rune unicode); + +/* text editor */ +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +NK_API void nk_textedit_init_default(struct nk_text_edit*); +#endif +NK_API void nk_textedit_init(struct nk_text_edit*, struct nk_allocator*, nk_size size); +NK_API void nk_textedit_init_fixed(struct nk_text_edit*, void *memory, nk_size size); +NK_API void nk_textedit_free(struct nk_text_edit*); +NK_API void nk_textedit_text(struct nk_text_edit*, const char*, int total_len); +NK_API void nk_textedit_delete(struct nk_text_edit*, int where, int len); +NK_API void nk_textedit_delete_selection(struct nk_text_edit*); +NK_API void nk_textedit_select_all(struct nk_text_edit*); +NK_API int nk_textedit_cut(struct nk_text_edit*); +NK_API int nk_textedit_paste(struct nk_text_edit*, char const*, int len); +NK_API void nk_textedit_undo(struct nk_text_edit*); +NK_API void nk_textedit_redo(struct nk_text_edit*); + +/* =============================================================== + * + * DRAWING + * + * ===============================================================*/ +/* This library was designed to be render backend agnostic so it does + not draw anything to screen. Instead all drawn shapes, widgets + are made of, are buffered into memory and make up a command queue. + Each frame therefore fills the command buffer with draw commands + that then need to be executed by the user and his own render backend. + After that the command buffer needs to be cleared and a new frame can be + started. It is probably important to note that the command buffer is the main + drawing API and the optional vertex buffer API only takes this format and + converts it into a hardware accessible format. + + To use the command queue to draw your own widgets you can access the + command buffer of each window by calling `nk_window_get_canvas` after + previously having called `nk_begin`: + + void draw_red_rectangle_widget(struct nk_context *ctx) + { + struct nk_command_buffer *canvas; + struct nk_input *input = &ctx->input; + canvas = nk_window_get_canvas(ctx); + + struct nk_rect space; + enum nk_widget_layout_states state; + state = nk_widget(&space, ctx); + if (!state) return; + + if (state != NK_WIDGET_ROM) + update_your_widget_by_user_input(...); + nk_fill_rect(canvas, space, 0, nk_rgb(255,0,0)); + } + + if (nk_begin(...)) { + nk_layout_row_dynamic(ctx, 25, 1); + draw_red_rectangle_widget(ctx); + } + nk_end(..) + + Important to know if you want to create your own widgets is the `nk_widget` + call. It allocates space on the panel reserved for this widget to be used, + but also returns the state of the widget space. If your widget is not seen and does + not have to be updated it is '0' and you can just return. If it only has + to be drawn the state will be `NK_WIDGET_ROM` otherwise you can do both + update and draw your widget. The reason for seperating is to only draw and + update what is actually neccessary which is crucial for performance. +*/ +enum nk_command_type { + NK_COMMAND_NOP, + NK_COMMAND_SCISSOR, + NK_COMMAND_LINE, + NK_COMMAND_CURVE, + NK_COMMAND_RECT, + NK_COMMAND_RECT_FILLED, + NK_COMMAND_RECT_MULTI_COLOR, + NK_COMMAND_CIRCLE, + NK_COMMAND_CIRCLE_FILLED, + NK_COMMAND_ARC, + NK_COMMAND_ARC_FILLED, + NK_COMMAND_TRIANGLE, + NK_COMMAND_TRIANGLE_FILLED, + NK_COMMAND_POLYGON, + NK_COMMAND_POLYGON_FILLED, + NK_COMMAND_POLYLINE, + NK_COMMAND_TEXT, + NK_COMMAND_IMAGE, + NK_COMMAND_CUSTOM +}; + +/* command base and header of every command inside the buffer */ +struct nk_command { + enum nk_command_type type; + nk_size next; +#ifdef NK_INCLUDE_COMMAND_USERDATA + nk_handle userdata; +#endif +}; + +struct nk_command_scissor { + struct nk_command header; + short x, y; + unsigned short w, h; +}; + +struct nk_command_line { + struct nk_command header; + unsigned short line_thickness; + struct nk_vec2i begin; + struct nk_vec2i end; + struct nk_color color; +}; + +struct nk_command_curve { + struct nk_command header; + unsigned short line_thickness; + struct nk_vec2i begin; + struct nk_vec2i end; + struct nk_vec2i ctrl[2]; + struct nk_color color; +}; + +struct nk_command_rect { + struct nk_command header; + unsigned short rounding; + unsigned short line_thickness; + short x, y; + unsigned short w, h; + struct nk_color color; +}; + +struct nk_command_rect_filled { + struct nk_command header; + unsigned short rounding; + short x, y; + unsigned short w, h; + struct nk_color color; +}; + +struct nk_command_rect_multi_color { + struct nk_command header; + short x, y; + unsigned short w, h; + struct nk_color left; + struct nk_color top; + struct nk_color bottom; + struct nk_color right; +}; + +struct nk_command_triangle { + struct nk_command header; + unsigned short line_thickness; + struct nk_vec2i a; + struct nk_vec2i b; + struct nk_vec2i c; + struct nk_color color; +}; + +struct nk_command_triangle_filled { + struct nk_command header; + struct nk_vec2i a; + struct nk_vec2i b; + struct nk_vec2i c; + struct nk_color color; +}; + +struct nk_command_circle { + struct nk_command header; + short x, y; + unsigned short line_thickness; + unsigned short w, h; + struct nk_color color; +}; + +struct nk_command_circle_filled { + struct nk_command header; + short x, y; + unsigned short w, h; + struct nk_color color; +}; + +struct nk_command_arc { + struct nk_command header; + short cx, cy; + unsigned short r; + unsigned short line_thickness; + float a[2]; + struct nk_color color; +}; + +struct nk_command_arc_filled { + struct nk_command header; + short cx, cy; + unsigned short r; + float a[2]; + struct nk_color color; +}; + +struct nk_command_polygon { + struct nk_command header; + struct nk_color color; + unsigned short line_thickness; + unsigned short point_count; + struct nk_vec2i points[1]; +}; + +struct nk_command_polygon_filled { + struct nk_command header; + struct nk_color color; + unsigned short point_count; + struct nk_vec2i points[1]; +}; + +struct nk_command_polyline { + struct nk_command header; + struct nk_color color; + unsigned short line_thickness; + unsigned short point_count; + struct nk_vec2i points[1]; +}; + +struct nk_command_image { + struct nk_command header; + short x, y; + unsigned short w, h; + struct nk_image img; + struct nk_color col; +}; + +typedef void (*nk_command_custom_callback)(void *canvas, short x,short y, + unsigned short w, unsigned short h, nk_handle callback_data); +struct nk_command_custom { + struct nk_command header; + short x, y; + unsigned short w, h; + nk_handle callback_data; + nk_command_custom_callback callback; +}; + +struct nk_command_text { + struct nk_command header; + const struct nk_user_font *font; + struct nk_color background; + struct nk_color foreground; + short x, y; + unsigned short w, h; + float height; + int length; + char string[1]; +}; + +enum nk_command_clipping { + NK_CLIPPING_OFF = nk_false, + NK_CLIPPING_ON = nk_true +}; + +struct nk_command_buffer { + struct nk_buffer *base; + struct nk_rect clip; + int use_clipping; + nk_handle userdata; + nk_size begin, end, last; +}; + +/* shape outlines */ +NK_API void nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, float x1, float y1, float line_thickness, struct nk_color); +NK_API void nk_stroke_curve(struct nk_command_buffer*, float, float, float, float, float, float, float, float, float line_thickness, struct nk_color); +NK_API void nk_stroke_rect(struct nk_command_buffer*, struct nk_rect, float rounding, float line_thickness, struct nk_color); +NK_API void nk_stroke_circle(struct nk_command_buffer*, struct nk_rect, float line_thickness, struct nk_color); +NK_API void nk_stroke_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, float line_thickness, struct nk_color); +NK_API void nk_stroke_triangle(struct nk_command_buffer*, float, float, float, float, float, float, float line_thichness, struct nk_color); +NK_API void nk_stroke_polyline(struct nk_command_buffer*, float *points, int point_count, float line_thickness, struct nk_color col); +NK_API void nk_stroke_polygon(struct nk_command_buffer*, float*, int point_count, float line_thickness, struct nk_color); + +/* filled shades */ +NK_API void nk_fill_rect(struct nk_command_buffer*, struct nk_rect, float rounding, struct nk_color); +NK_API void nk_fill_rect_multi_color(struct nk_command_buffer*, struct nk_rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom); +NK_API void nk_fill_circle(struct nk_command_buffer*, struct nk_rect, struct nk_color); +NK_API void nk_fill_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, struct nk_color); +NK_API void nk_fill_triangle(struct nk_command_buffer*, float x0, float y0, float x1, float y1, float x2, float y2, struct nk_color); +NK_API void nk_fill_polygon(struct nk_command_buffer*, float*, int point_count, struct nk_color); + +/* misc */ +NK_API void nk_draw_image(struct nk_command_buffer*, struct nk_rect, const struct nk_image*, struct nk_color); +NK_API void nk_draw_text(struct nk_command_buffer*, struct nk_rect, const char *text, int len, const struct nk_user_font*, struct nk_color, struct nk_color); +NK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect); +NK_API void nk_push_custom(struct nk_command_buffer*, struct nk_rect, nk_command_custom_callback, nk_handle usr); + +/* =============================================================== + * + * INPUT + * + * ===============================================================*/ +struct nk_mouse_button { + int down; + unsigned int clicked; + struct nk_vec2 clicked_pos; +}; +struct nk_mouse { + struct nk_mouse_button buttons[NK_BUTTON_MAX]; + struct nk_vec2 pos; + struct nk_vec2 prev; + struct nk_vec2 delta; + struct nk_vec2 scroll_delta; + unsigned char grab; + unsigned char grabbed; + unsigned char ungrab; +}; + +struct nk_key { + int down; + unsigned int clicked; +}; +struct nk_keyboard { + struct nk_key keys[NK_KEY_MAX]; + char text[NK_INPUT_MAX]; + int text_len; +}; + +struct nk_input { + struct nk_keyboard keyboard; + struct nk_mouse mouse; +}; + +NK_API int nk_input_has_mouse_click(const struct nk_input*, enum nk_buttons); +NK_API int nk_input_has_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect); +NK_API int nk_input_has_mouse_click_down_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect, int down); +NK_API int nk_input_is_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect); +NK_API int nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, struct nk_rect b, int down); +NK_API int nk_input_any_mouse_click_in_rect(const struct nk_input*, struct nk_rect); +NK_API int nk_input_is_mouse_prev_hovering_rect(const struct nk_input*, struct nk_rect); +NK_API int nk_input_is_mouse_hovering_rect(const struct nk_input*, struct nk_rect); +NK_API int nk_input_mouse_clicked(const struct nk_input*, enum nk_buttons, struct nk_rect); +NK_API int nk_input_is_mouse_down(const struct nk_input*, enum nk_buttons); +NK_API int nk_input_is_mouse_pressed(const struct nk_input*, enum nk_buttons); +NK_API int nk_input_is_mouse_released(const struct nk_input*, enum nk_buttons); +NK_API int nk_input_is_key_pressed(const struct nk_input*, enum nk_keys); +NK_API int nk_input_is_key_released(const struct nk_input*, enum nk_keys); +NK_API int nk_input_is_key_down(const struct nk_input*, enum nk_keys); + +/* =============================================================== + * + * DRAW LIST + * + * ===============================================================*/ +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT +/* The optional vertex buffer draw list provides a 2D drawing context + with antialiasing functionality which takes basic filled or outlined shapes + or a path and outputs vertexes, elements and draw commands. + The actual draw list API is not required to be used directly while using this + library since converting the default library draw command output is done by + just calling `nk_convert` but I decided to still make this library accessible + since it can be useful. + + The draw list is based on a path buffering and polygon and polyline + rendering API which allows a lot of ways to draw 2D content to screen. + In fact it is probably more powerful than needed but allows even more crazy + things than this library provides by default. +*/ +typedef nk_ushort nk_draw_index; +enum nk_draw_list_stroke { + NK_STROKE_OPEN = nk_false, + /* build up path has no connection back to the beginning */ + NK_STROKE_CLOSED = nk_true + /* build up path has a connection back to the beginning */ +}; + +enum nk_draw_vertex_layout_attribute { + NK_VERTEX_POSITION, + NK_VERTEX_COLOR, + NK_VERTEX_TEXCOORD, + NK_VERTEX_ATTRIBUTE_COUNT +}; + +enum nk_draw_vertex_layout_format { + NK_FORMAT_SCHAR, + NK_FORMAT_SSHORT, + NK_FORMAT_SINT, + NK_FORMAT_UCHAR, + NK_FORMAT_USHORT, + NK_FORMAT_UINT, + NK_FORMAT_FLOAT, + NK_FORMAT_DOUBLE, + +NK_FORMAT_COLOR_BEGIN, + NK_FORMAT_R8G8B8 = NK_FORMAT_COLOR_BEGIN, + NK_FORMAT_R16G15B16, + NK_FORMAT_R32G32B32, + + NK_FORMAT_R8G8B8A8, + NK_FORMAT_B8G8R8A8, + NK_FORMAT_R16G15B16A16, + NK_FORMAT_R32G32B32A32, + NK_FORMAT_R32G32B32A32_FLOAT, + NK_FORMAT_R32G32B32A32_DOUBLE, + + NK_FORMAT_RGB32, + NK_FORMAT_RGBA32, +NK_FORMAT_COLOR_END = NK_FORMAT_RGBA32, + NK_FORMAT_COUNT +}; + +#define NK_VERTEX_LAYOUT_END NK_VERTEX_ATTRIBUTE_COUNT,NK_FORMAT_COUNT,0 +struct nk_draw_vertex_layout_element { + enum nk_draw_vertex_layout_attribute attribute; + enum nk_draw_vertex_layout_format format; + nk_size offset; +}; + +struct nk_draw_command { + unsigned int elem_count; + /* number of elements in the current draw batch */ + struct nk_rect clip_rect; + /* current screen clipping rectangle */ + nk_handle texture; + /* current texture to set */ +#ifdef NK_INCLUDE_COMMAND_USERDATA + nk_handle userdata; +#endif +}; + +struct nk_draw_list { + struct nk_rect clip_rect; + struct nk_vec2 circle_vtx[12]; + struct nk_convert_config config; + + struct nk_buffer *buffer; + struct nk_buffer *vertices; + struct nk_buffer *elements; + + unsigned int element_count; + unsigned int vertex_count; + unsigned int cmd_count; + nk_size cmd_offset; + + unsigned int path_count; + unsigned int path_offset; + + enum nk_anti_aliasing line_AA; + enum nk_anti_aliasing shape_AA; + +#ifdef NK_INCLUDE_COMMAND_USERDATA + nk_handle userdata; +#endif +}; + +/* draw list */ +NK_API void nk_draw_list_init(struct nk_draw_list*); +NK_API void nk_draw_list_setup(struct nk_draw_list*, const struct nk_convert_config*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, enum nk_anti_aliasing line_aa,enum nk_anti_aliasing shape_aa); +NK_API void nk_draw_list_clear(struct nk_draw_list*); + +/* drawing */ +#define nk_draw_list_foreach(cmd, can, b) for((cmd)=nk__draw_list_begin(can, b); (cmd)!=0; (cmd)=nk__draw_list_next(cmd, b, can)) +NK_API const struct nk_draw_command* nk__draw_list_begin(const struct nk_draw_list*, const struct nk_buffer*); +NK_API const struct nk_draw_command* nk__draw_list_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_draw_list*); +NK_API const struct nk_draw_command* nk__draw_list_end(const struct nk_draw_list*, const struct nk_buffer*); +NK_API void nk_draw_list_clear(struct nk_draw_list *list); + +/* path */ +NK_API void nk_draw_list_path_clear(struct nk_draw_list*); +NK_API void nk_draw_list_path_line_to(struct nk_draw_list*, struct nk_vec2 pos); +NK_API void nk_draw_list_path_arc_to_fast(struct nk_draw_list*, struct nk_vec2 center, float radius, int a_min, int a_max); +NK_API void nk_draw_list_path_arc_to(struct nk_draw_list*, struct nk_vec2 center, float radius, float a_min, float a_max, unsigned int segments); +NK_API void nk_draw_list_path_rect_to(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, float rounding); +NK_API void nk_draw_list_path_curve_to(struct nk_draw_list*, struct nk_vec2 p2, struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments); +NK_API void nk_draw_list_path_fill(struct nk_draw_list*, struct nk_color); +NK_API void nk_draw_list_path_stroke(struct nk_draw_list*, struct nk_color, enum nk_draw_list_stroke closed, float thickness); + +/* stroke */ +NK_API void nk_draw_list_stroke_line(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_color, float thickness); +NK_API void nk_draw_list_stroke_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding, float thickness); +NK_API void nk_draw_list_stroke_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color, float thickness); +NK_API void nk_draw_list_stroke_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color, unsigned int segs, float thickness); +NK_API void nk_draw_list_stroke_curve(struct nk_draw_list*, struct nk_vec2 p0, struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, struct nk_color, unsigned int segments, float thickness); +NK_API void nk_draw_list_stroke_poly_line(struct nk_draw_list*, const struct nk_vec2 *pnts, const unsigned int cnt, struct nk_color, enum nk_draw_list_stroke, float thickness, enum nk_anti_aliasing); + +/* fill */ +NK_API void nk_draw_list_fill_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding); +NK_API void nk_draw_list_fill_rect_multi_color(struct nk_draw_list*, struct nk_rect rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom); +NK_API void nk_draw_list_fill_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color); +NK_API void nk_draw_list_fill_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color col, unsigned int segs); +NK_API void nk_draw_list_fill_poly_convex(struct nk_draw_list*, const struct nk_vec2 *points, const unsigned int count, struct nk_color, enum nk_anti_aliasing); + +/* misc */ +NK_API void nk_draw_list_add_image(struct nk_draw_list*, struct nk_image texture, struct nk_rect rect, struct nk_color); +NK_API void nk_draw_list_add_text(struct nk_draw_list*, const struct nk_user_font*, struct nk_rect, const char *text, int len, float font_height, struct nk_color); +#ifdef NK_INCLUDE_COMMAND_USERDATA +NK_API void nk_draw_list_push_userdata(struct nk_draw_list*, nk_handle userdata); +#endif + +#endif + +/* =============================================================== + * + * GUI + * + * ===============================================================*/ +enum nk_style_item_type { + NK_STYLE_ITEM_COLOR, + NK_STYLE_ITEM_IMAGE +}; + +union nk_style_item_data { + struct nk_image image; + struct nk_color color; +}; + +struct nk_style_item { + enum nk_style_item_type type; + union nk_style_item_data data; +}; + +struct nk_style_text { + struct nk_color color; + struct nk_vec2 padding; +}; + +struct nk_style_button { + /* background */ + struct nk_style_item normal; + struct nk_style_item hover; + struct nk_style_item active; + struct nk_color border_color; + + /* text */ + struct nk_color text_background; + struct nk_color text_normal; + struct nk_color text_hover; + struct nk_color text_active; + nk_flags text_alignment; + + /* properties */ + float border; + float rounding; + struct nk_vec2 padding; + struct nk_vec2 image_padding; + struct nk_vec2 touch_padding; + + /* optional user callbacks */ + nk_handle userdata; + void(*draw_begin)(struct nk_command_buffer*, nk_handle userdata); + void(*draw_end)(struct nk_command_buffer*, nk_handle userdata); +}; + +struct nk_style_toggle { + /* background */ + struct nk_style_item normal; + struct nk_style_item hover; + struct nk_style_item active; + struct nk_color border_color; + + /* cursor */ + struct nk_style_item cursor_normal; + struct nk_style_item cursor_hover; + + /* text */ + struct nk_color text_normal; + struct nk_color text_hover; + struct nk_color text_active; + struct nk_color text_background; + nk_flags text_alignment; + + /* properties */ + struct nk_vec2 padding; + struct nk_vec2 touch_padding; + float spacing; + float border; + + /* optional user callbacks */ + nk_handle userdata; + void(*draw_begin)(struct nk_command_buffer*, nk_handle); + void(*draw_end)(struct nk_command_buffer*, nk_handle); +}; + +struct nk_style_selectable { + /* background (inactive) */ + struct nk_style_item normal; + struct nk_style_item hover; + struct nk_style_item pressed; + + /* background (active) */ + struct nk_style_item normal_active; + struct nk_style_item hover_active; + struct nk_style_item pressed_active; + + /* text color (inactive) */ + struct nk_color text_normal; + struct nk_color text_hover; + struct nk_color text_pressed; + + /* text color (active) */ + struct nk_color text_normal_active; + struct nk_color text_hover_active; + struct nk_color text_pressed_active; + struct nk_color text_background; + nk_flags text_alignment; + + /* properties */ + float rounding; + struct nk_vec2 padding; + struct nk_vec2 touch_padding; + struct nk_vec2 image_padding; + + /* optional user callbacks */ + nk_handle userdata; + void(*draw_begin)(struct nk_command_buffer*, nk_handle); + void(*draw_end)(struct nk_command_buffer*, nk_handle); +}; + +struct nk_style_slider { + /* background */ + struct nk_style_item normal; + struct nk_style_item hover; + struct nk_style_item active; + struct nk_color border_color; + + /* background bar */ + struct nk_color bar_normal; + struct nk_color bar_hover; + struct nk_color bar_active; + struct nk_color bar_filled; + + /* cursor */ + struct nk_style_item cursor_normal; + struct nk_style_item cursor_hover; + struct nk_style_item cursor_active; + + /* properties */ + float border; + float rounding; + float bar_height; + struct nk_vec2 padding; + struct nk_vec2 spacing; + struct nk_vec2 cursor_size; + + /* optional buttons */ + int show_buttons; + struct nk_style_button inc_button; + struct nk_style_button dec_button; + enum nk_symbol_type inc_symbol; + enum nk_symbol_type dec_symbol; + + /* optional user callbacks */ + nk_handle userdata; + void(*draw_begin)(struct nk_command_buffer*, nk_handle); + void(*draw_end)(struct nk_command_buffer*, nk_handle); +}; + +struct nk_style_progress { + /* background */ + struct nk_style_item normal; + struct nk_style_item hover; + struct nk_style_item active; + struct nk_color border_color; + + /* cursor */ + struct nk_style_item cursor_normal; + struct nk_style_item cursor_hover; + struct nk_style_item cursor_active; + struct nk_color cursor_border_color; + + /* properties */ + float rounding; + float border; + float cursor_border; + float cursor_rounding; + struct nk_vec2 padding; + + /* optional user callbacks */ + nk_handle userdata; + void(*draw_begin)(struct nk_command_buffer*, nk_handle); + void(*draw_end)(struct nk_command_buffer*, nk_handle); +}; + +struct nk_style_scrollbar { + /* background */ + struct nk_style_item normal; + struct nk_style_item hover; + struct nk_style_item active; + struct nk_color border_color; + + /* cursor */ + struct nk_style_item cursor_normal; + struct nk_style_item cursor_hover; + struct nk_style_item cursor_active; + struct nk_color cursor_border_color; + + /* properties */ + float border; + float rounding; + float border_cursor; + float rounding_cursor; + struct nk_vec2 padding; + + /* optional buttons */ + int show_buttons; + struct nk_style_button inc_button; + struct nk_style_button dec_button; + enum nk_symbol_type inc_symbol; + enum nk_symbol_type dec_symbol; + + /* optional user callbacks */ + nk_handle userdata; + void(*draw_begin)(struct nk_command_buffer*, nk_handle); + void(*draw_end)(struct nk_command_buffer*, nk_handle); +}; + +struct nk_style_edit { + /* background */ + struct nk_style_item normal; + struct nk_style_item hover; + struct nk_style_item active; + struct nk_color border_color; + struct nk_style_scrollbar scrollbar; + + /* cursor */ + struct nk_color cursor_normal; + struct nk_color cursor_hover; + struct nk_color cursor_text_normal; + struct nk_color cursor_text_hover; + + /* text (unselected) */ + struct nk_color text_normal; + struct nk_color text_hover; + struct nk_color text_active; + + /* text (selected) */ + struct nk_color selected_normal; + struct nk_color selected_hover; + struct nk_color selected_text_normal; + struct nk_color selected_text_hover; + + /* properties */ + float border; + float rounding; + float cursor_size; + struct nk_vec2 scrollbar_size; + struct nk_vec2 padding; + float row_padding; +}; + +struct nk_style_property { + /* background */ + struct nk_style_item normal; + struct nk_style_item hover; + struct nk_style_item active; + struct nk_color border_color; + + /* text */ + struct nk_color label_normal; + struct nk_color label_hover; + struct nk_color label_active; + + /* symbols */ + enum nk_symbol_type sym_left; + enum nk_symbol_type sym_right; + + /* properties */ + float border; + float rounding; + struct nk_vec2 padding; + + struct nk_style_edit edit; + struct nk_style_button inc_button; + struct nk_style_button dec_button; + + /* optional user callbacks */ + nk_handle userdata; + void(*draw_begin)(struct nk_command_buffer*, nk_handle); + void(*draw_end)(struct nk_command_buffer*, nk_handle); +}; + +struct nk_style_chart { + /* colors */ + struct nk_style_item background; + struct nk_color border_color; + struct nk_color selected_color; + struct nk_color color; + + /* properties */ + float border; + float rounding; + struct nk_vec2 padding; +}; + +struct nk_style_combo { + /* background */ + struct nk_style_item normal; + struct nk_style_item hover; + struct nk_style_item active; + struct nk_color border_color; + + /* label */ + struct nk_color label_normal; + struct nk_color label_hover; + struct nk_color label_active; + + /* symbol */ + struct nk_color symbol_normal; + struct nk_color symbol_hover; + struct nk_color symbol_active; + + /* button */ + struct nk_style_button button; + enum nk_symbol_type sym_normal; + enum nk_symbol_type sym_hover; + enum nk_symbol_type sym_active; + + /* properties */ + float border; + float rounding; + struct nk_vec2 content_padding; + struct nk_vec2 button_padding; + struct nk_vec2 spacing; +}; + +struct nk_style_tab { + /* background */ + struct nk_style_item background; + struct nk_color border_color; + struct nk_color text; + + /* button */ + struct nk_style_button tab_maximize_button; + struct nk_style_button tab_minimize_button; + struct nk_style_button node_maximize_button; + struct nk_style_button node_minimize_button; + enum nk_symbol_type sym_minimize; + enum nk_symbol_type sym_maximize; + + /* properties */ + float border; + float rounding; + float indent; + struct nk_vec2 padding; + struct nk_vec2 spacing; +}; + +enum nk_style_header_align { + NK_HEADER_LEFT, + NK_HEADER_RIGHT +}; +struct nk_style_window_header { + /* background */ + struct nk_style_item normal; + struct nk_style_item hover; + struct nk_style_item active; + + /* button */ + struct nk_style_button close_button; + struct nk_style_button minimize_button; + enum nk_symbol_type close_symbol; + enum nk_symbol_type minimize_symbol; + enum nk_symbol_type maximize_symbol; + + /* title */ + struct nk_color label_normal; + struct nk_color label_hover; + struct nk_color label_active; + + /* properties */ + enum nk_style_header_align align; + struct nk_vec2 padding; + struct nk_vec2 label_padding; + struct nk_vec2 spacing; +}; + +struct nk_style_window { + struct nk_style_window_header header; + struct nk_style_item fixed_background; + struct nk_color background; + + struct nk_color border_color; + struct nk_color popup_border_color; + struct nk_color combo_border_color; + struct nk_color contextual_border_color; + struct nk_color menu_border_color; + struct nk_color group_border_color; + struct nk_color tooltip_border_color; + struct nk_style_item scaler; + + float border; + float combo_border; + float contextual_border; + float menu_border; + float group_border; + float tooltip_border; + float popup_border; + float min_row_height_padding; + + float rounding; + struct nk_vec2 spacing; + struct nk_vec2 scrollbar_size; + struct nk_vec2 min_size; + + struct nk_vec2 padding; + struct nk_vec2 group_padding; + struct nk_vec2 popup_padding; + struct nk_vec2 combo_padding; + struct nk_vec2 contextual_padding; + struct nk_vec2 menu_padding; + struct nk_vec2 tooltip_padding; +}; + +struct nk_style { + const struct nk_user_font *font; + const struct nk_cursor *cursors[NK_CURSOR_COUNT]; + const struct nk_cursor *cursor_active; + struct nk_cursor *cursor_last; + int cursor_visible; + + struct nk_style_text text; + struct nk_style_button button; + struct nk_style_button contextual_button; + struct nk_style_button menu_button; + struct nk_style_toggle option; + struct nk_style_toggle checkbox; + struct nk_style_selectable selectable; + struct nk_style_slider slider; + struct nk_style_progress progress; + struct nk_style_property property; + struct nk_style_edit edit; + struct nk_style_chart chart; + struct nk_style_scrollbar scrollh; + struct nk_style_scrollbar scrollv; + struct nk_style_tab tab; + struct nk_style_combo combo; + struct nk_style_window window; +}; + +NK_API struct nk_style_item nk_style_item_image(struct nk_image img); +NK_API struct nk_style_item nk_style_item_color(struct nk_color); +NK_API struct nk_style_item nk_style_item_hide(void); + +/*============================================================== + * PANEL + * =============================================================*/ +#ifndef NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS +#define NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS 16 +#endif +#ifndef NK_CHART_MAX_SLOT +#define NK_CHART_MAX_SLOT 4 +#endif + +enum nk_panel_type { + NK_PANEL_WINDOW = NK_FLAG(0), + NK_PANEL_GROUP = NK_FLAG(1), + NK_PANEL_POPUP = NK_FLAG(2), + NK_PANEL_CONTEXTUAL = NK_FLAG(4), + NK_PANEL_COMBO = NK_FLAG(5), + NK_PANEL_MENU = NK_FLAG(6), + NK_PANEL_TOOLTIP = NK_FLAG(7) +}; +enum nk_panel_set { + NK_PANEL_SET_NONBLOCK = NK_PANEL_CONTEXTUAL|NK_PANEL_COMBO|NK_PANEL_MENU|NK_PANEL_TOOLTIP, + NK_PANEL_SET_POPUP = NK_PANEL_SET_NONBLOCK|NK_PANEL_POPUP, + NK_PANEL_SET_SUB = NK_PANEL_SET_POPUP|NK_PANEL_GROUP +}; + +struct nk_chart_slot { + enum nk_chart_type type; + struct nk_color color; + struct nk_color highlight; + float min, max, range; + int count; + struct nk_vec2 last; + int index; +}; + +struct nk_chart { + int slot; + float x, y, w, h; + struct nk_chart_slot slots[NK_CHART_MAX_SLOT]; +}; + +enum nk_panel_row_layout_type { + NK_LAYOUT_DYNAMIC_FIXED = 0, + NK_LAYOUT_DYNAMIC_ROW, + NK_LAYOUT_DYNAMIC_FREE, + NK_LAYOUT_DYNAMIC, + NK_LAYOUT_STATIC_FIXED, + NK_LAYOUT_STATIC_ROW, + NK_LAYOUT_STATIC_FREE, + NK_LAYOUT_STATIC, + NK_LAYOUT_TEMPLATE, + NK_LAYOUT_COUNT +}; +struct nk_row_layout { + enum nk_panel_row_layout_type type; + int index; + float height; + float min_height; + int columns; + const float *ratio; + float item_width; + float item_height; + float item_offset; + float filled; + struct nk_rect item; + int tree_depth; + float templates[NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS]; +}; + +struct nk_popup_buffer { + nk_size begin; + nk_size parent; + nk_size last; + nk_size end; + int active; +}; + +struct nk_menu_state { + float x, y, w, h; + struct nk_scroll offset; +}; + +struct nk_panel { + enum nk_panel_type type; + nk_flags flags; + struct nk_rect bounds; + nk_uint *offset_x; + nk_uint *offset_y; + float at_x, at_y, max_x; + float footer_height; + float header_height; + float border; + unsigned int has_scrolling; + struct nk_rect clip; + struct nk_menu_state menu; + struct nk_row_layout row; + struct nk_chart chart; + struct nk_command_buffer *buffer; + struct nk_panel *parent; +}; + +/*============================================================== + * WINDOW + * =============================================================*/ +#ifndef NK_WINDOW_MAX_NAME +#define NK_WINDOW_MAX_NAME 64 +#endif + +struct nk_table; +enum nk_window_flags { + NK_WINDOW_PRIVATE = NK_FLAG(11), + NK_WINDOW_DYNAMIC = NK_WINDOW_PRIVATE, + /* special window type growing up in height while being filled to a certain maximum height */ + NK_WINDOW_ROM = NK_FLAG(12), + /* sets window widgets into a read only mode and does not allow input changes */ + NK_WINDOW_NOT_INTERACTIVE = NK_WINDOW_ROM|NK_WINDOW_NO_INPUT, + /* prevents all interaction caused by input to either window or widgets inside */ + NK_WINDOW_HIDDEN = NK_FLAG(13), + /* Hides window and stops any window interaction and drawing */ + NK_WINDOW_CLOSED = NK_FLAG(14), + /* Directly closes and frees the window at the end of the frame */ + NK_WINDOW_MINIMIZED = NK_FLAG(15), + /* marks the window as minimized */ + NK_WINDOW_REMOVE_ROM = NK_FLAG(16) + /* Removes read only mode at the end of the window */ +}; + +struct nk_popup_state { + struct nk_window *win; + enum nk_panel_type type; + struct nk_popup_buffer buf; + nk_hash name; + int active; + unsigned combo_count; + unsigned con_count, con_old; + unsigned active_con; + struct nk_rect header; +}; + +struct nk_edit_state { + nk_hash name; + unsigned int seq; + unsigned int old; + int active, prev; + int cursor; + int sel_start; + int sel_end; + struct nk_scroll scrollbar; + unsigned char mode; + unsigned char single_line; +}; + +struct nk_property_state { + int active, prev; + char buffer[NK_MAX_NUMBER_BUFFER]; + int length; + int cursor; + int select_start; + int select_end; + nk_hash name; + unsigned int seq; + unsigned int old; + int state; +}; + +struct nk_window { + unsigned int seq; + nk_hash name; + char name_string[NK_WINDOW_MAX_NAME]; + nk_flags flags; + + struct nk_rect bounds; + struct nk_scroll scrollbar; + struct nk_command_buffer buffer; + struct nk_panel *layout; + float scrollbar_hiding_timer; + + /* persistent widget state */ + struct nk_property_state property; + struct nk_popup_state popup; + struct nk_edit_state edit; + unsigned int scrolled; + + struct nk_table *tables; + unsigned int table_count; + + /* window list hooks */ + struct nk_window *next; + struct nk_window *prev; + struct nk_window *parent; +}; + +/*============================================================== + * STACK + * =============================================================*/ +/* The style modifier stack can be used to temporarily change a + * property inside `nk_style`. For example if you want a special + * red button you can temporarily push the old button color onto a stack + * draw the button with a red color and then you just pop the old color + * back from the stack: + * + * nk_style_push_style_item(ctx, &ctx->style.button.normal, nk_style_item_color(nk_rgb(255,0,0))); + * nk_style_push_style_item(ctx, &ctx->style.button.hover, nk_style_item_color(nk_rgb(255,0,0))); + * nk_style_push_style_item(ctx, &ctx->style.button.active, nk_style_item_color(nk_rgb(255,0,0))); + * nk_style_push_vec2(ctx, &cx->style.button.padding, nk_vec2(2,2)); + * + * nk_button(...); + * + * nk_style_pop_style_item(ctx); + * nk_style_pop_style_item(ctx); + * nk_style_pop_style_item(ctx); + * nk_style_pop_vec2(ctx); + * + * Nuklear has a stack for style_items, float properties, vector properties, + * flags, colors, fonts and for button_behavior. Each has it's own fixed size stack + * which can be changed at compile time. + */ +#ifndef NK_BUTTON_BEHAVIOR_STACK_SIZE +#define NK_BUTTON_BEHAVIOR_STACK_SIZE 8 +#endif + +#ifndef NK_FONT_STACK_SIZE +#define NK_FONT_STACK_SIZE 8 +#endif + +#ifndef NK_STYLE_ITEM_STACK_SIZE +#define NK_STYLE_ITEM_STACK_SIZE 16 +#endif + +#ifndef NK_FLOAT_STACK_SIZE +#define NK_FLOAT_STACK_SIZE 32 +#endif + +#ifndef NK_VECTOR_STACK_SIZE +#define NK_VECTOR_STACK_SIZE 16 +#endif + +#ifndef NK_FLAGS_STACK_SIZE +#define NK_FLAGS_STACK_SIZE 32 +#endif + +#ifndef NK_COLOR_STACK_SIZE +#define NK_COLOR_STACK_SIZE 32 +#endif + +#define NK_CONFIGURATION_STACK_TYPE(prefix, name, type)\ + struct nk_config_stack_##name##_element {\ + prefix##_##type *address;\ + prefix##_##type old_value;\ + } +#define NK_CONFIG_STACK(type,size)\ + struct nk_config_stack_##type {\ + int head;\ + struct nk_config_stack_##type##_element elements[size];\ + } + +#define nk_float float +NK_CONFIGURATION_STACK_TYPE(struct nk, style_item, style_item); +NK_CONFIGURATION_STACK_TYPE(nk ,float, float); +NK_CONFIGURATION_STACK_TYPE(struct nk, vec2, vec2); +NK_CONFIGURATION_STACK_TYPE(nk ,flags, flags); +NK_CONFIGURATION_STACK_TYPE(struct nk, color, color); +NK_CONFIGURATION_STACK_TYPE(const struct nk, user_font, user_font*); +NK_CONFIGURATION_STACK_TYPE(enum nk, button_behavior, button_behavior); + +NK_CONFIG_STACK(style_item, NK_STYLE_ITEM_STACK_SIZE); +NK_CONFIG_STACK(float, NK_FLOAT_STACK_SIZE); +NK_CONFIG_STACK(vec2, NK_VECTOR_STACK_SIZE); +NK_CONFIG_STACK(flags, NK_FLAGS_STACK_SIZE); +NK_CONFIG_STACK(color, NK_COLOR_STACK_SIZE); +NK_CONFIG_STACK(user_font, NK_FONT_STACK_SIZE); +NK_CONFIG_STACK(button_behavior, NK_BUTTON_BEHAVIOR_STACK_SIZE); + +struct nk_configuration_stacks { + struct nk_config_stack_style_item style_items; + struct nk_config_stack_float floats; + struct nk_config_stack_vec2 vectors; + struct nk_config_stack_flags flags; + struct nk_config_stack_color colors; + struct nk_config_stack_user_font fonts; + struct nk_config_stack_button_behavior button_behaviors; +}; + +/*============================================================== + * CONTEXT + * =============================================================*/ +#define NK_VALUE_PAGE_CAPACITY \ + (((NK_MAX(sizeof(struct nk_window),sizeof(struct nk_panel)) / sizeof(nk_uint))) / 2) + +struct nk_table { + unsigned int seq; + unsigned int size; + nk_hash keys[NK_VALUE_PAGE_CAPACITY]; + nk_uint values[NK_VALUE_PAGE_CAPACITY]; + struct nk_table *next, *prev; +}; + +union nk_page_data { + struct nk_table tbl; + struct nk_panel pan; + struct nk_window win; +}; + +struct nk_page_element { + union nk_page_data data; + struct nk_page_element *next; + struct nk_page_element *prev; +}; + +struct nk_page { + unsigned int size; + struct nk_page *next; + struct nk_page_element win[1]; +}; + +struct nk_pool { + struct nk_allocator alloc; + enum nk_allocation_type type; + unsigned int page_count; + struct nk_page *pages; + struct nk_page_element *freelist; + unsigned capacity; + nk_size size; + nk_size cap; +}; + +struct nk_context { +/* public: can be accessed freely */ + struct nk_input input; + struct nk_style style; + struct nk_buffer memory; + struct nk_clipboard clip; + nk_flags last_widget_state; + enum nk_button_behavior button_behavior; + struct nk_configuration_stacks stacks; + float delta_time_seconds; + +/* private: + should only be accessed if you + know what you are doing */ +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT + struct nk_draw_list draw_list; +#endif +#ifdef NK_INCLUDE_COMMAND_USERDATA + nk_handle userdata; +#endif + /* text editor objects are quite big because of an internal + * undo/redo stack. Therefore it does not make sense to have one for + * each window for temporary use cases, so I only provide *one* instance + * for all windows. This works because the content is cleared anyway */ + struct nk_text_edit text_edit; + /* draw buffer used for overlay drawing operation like cursor */ + struct nk_command_buffer overlay; + + /* windows */ + int build; + int use_pool; + struct nk_pool pool; + struct nk_window *begin; + struct nk_window *end; + struct nk_window *active; + struct nk_window *current; + struct nk_page_element *freelist; + unsigned int count; + unsigned int seq; +}; + +/* ============================================================== + * MATH + * =============================================================== */ +#define NK_PI 3.141592654f +#define NK_UTF_INVALID 0xFFFD +#define NK_MAX_FLOAT_PRECISION 2 + +#define NK_UNUSED(x) ((void)(x)) +#define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x))) +#define NK_LEN(a) (sizeof(a)/sizeof(a)[0]) +#define NK_ABS(a) (((a) < 0) ? -(a) : (a)) +#define NK_BETWEEN(x, a, b) ((a) <= (x) && (x) < (b)) +#define NK_INBOX(px, py, x, y, w, h)\ + (NK_BETWEEN(px,x,x+w) && NK_BETWEEN(py,y,y+h)) +#define NK_INTERSECT(x0, y0, w0, h0, x1, y1, w1, h1) \ + (!(((x1 > (x0 + w0)) || ((x1 + w1) < x0) || (y1 > (y0 + h0)) || (y1 + h1) < y0))) +#define NK_CONTAINS(x, y, w, h, bx, by, bw, bh)\ + (NK_INBOX(x,y, bx, by, bw, bh) && NK_INBOX(x+w,y+h, bx, by, bw, bh)) + +#define nk_vec2_sub(a, b) nk_vec2((a).x - (b).x, (a).y - (b).y) +#define nk_vec2_add(a, b) nk_vec2((a).x + (b).x, (a).y + (b).y) +#define nk_vec2_len_sqr(a) ((a).x*(a).x+(a).y*(a).y) +#define nk_vec2_muls(a, t) nk_vec2((a).x * (t), (a).y * (t)) + +#define nk_ptr_add(t, p, i) ((t*)((void*)((nk_byte*)(p) + (i)))) +#define nk_ptr_add_const(t, p, i) ((const t*)((const void*)((const nk_byte*)(p) + (i)))) +#define nk_zero_struct(s) nk_zero(&s, sizeof(s)) + +/* ============================================================== + * ALIGNMENT + * =============================================================== */ +/* Pointer to Integer type conversion for pointer alignment */ +#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC*/ +# define NK_UINT_TO_PTR(x) ((void*)(__PTRDIFF_TYPE__)(x)) +# define NK_PTR_TO_UINT(x) ((nk_size)(__PTRDIFF_TYPE__)(x)) +#elif !defined(__GNUC__) /* works for compilers other than LLVM */ +# define NK_UINT_TO_PTR(x) ((void*)&((char*)0)[x]) +# define NK_PTR_TO_UINT(x) ((nk_size)(((char*)x)-(char*)0)) +#elif defined(NK_USE_FIXED_TYPES) /* used if we have */ +# define NK_UINT_TO_PTR(x) ((void*)(uintptr_t)(x)) +# define NK_PTR_TO_UINT(x) ((uintptr_t)(x)) +#else /* generates warning but works */ +# define NK_UINT_TO_PTR(x) ((void*)(x)) +# define NK_PTR_TO_UINT(x) ((nk_size)(x)) +#endif + +#define NK_ALIGN_PTR(x, mask)\ + (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x) + (mask-1)) & ~(mask-1)))) +#define NK_ALIGN_PTR_BACK(x, mask)\ + (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x)) & ~(mask-1)))) + +#define NK_OFFSETOF(st,m) ((nk_ptr)&(((st*)0)->m)) +#define NK_CONTAINER_OF(ptr,type,member)\ + (type*)((void*)((char*)(1 ? (ptr): &((type*)0)->member) - NK_OFFSETOF(type, member))) + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +template struct nk_alignof; +template struct nk_helper{enum {value = size_diff};}; +template struct nk_helper{enum {value = nk_alignof::value};}; +template struct nk_alignof{struct Big {T x; char c;}; enum { + diff = sizeof(Big) - sizeof(T), value = nk_helper::value};}; +#define NK_ALIGNOF(t) (nk_alignof::value) +#elif defined(_MSC_VER) +#define NK_ALIGNOF(t) (__alignof(t)) +#else +#define NK_ALIGNOF(t) ((char*)(&((struct {char c; t _h;}*)0)->_h) - (char*)0) +#endif + +#endif /* NK_H_ */ +/* + * ============================================================== + * + * IMPLEMENTATION + * + * =============================================================== + */ +#ifdef NK_IMPLEMENTATION + +#ifndef NK_POOL_DEFAULT_CAPACITY +#define NK_POOL_DEFAULT_CAPACITY 16 +#endif + +#ifndef NK_DEFAULT_COMMAND_BUFFER_SIZE +#define NK_DEFAULT_COMMAND_BUFFER_SIZE (4*1024) +#endif + +#ifndef NK_BUFFER_DEFAULT_INITIAL_SIZE +#define NK_BUFFER_DEFAULT_INITIAL_SIZE (4*1024) +#endif + +/* standard library headers */ +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +#include /* malloc, free */ +#endif +#ifdef NK_INCLUDE_STANDARD_IO +#include /* fopen, fclose,... */ +#endif +#ifdef NK_INCLUDE_STANDARD_VARARGS +#include /* valist, va_start, va_end, ... */ +#endif +#ifndef NK_ASSERT +#include +#define NK_ASSERT(expr) assert(expr) +#endif + +#ifndef NK_MEMSET +#define NK_MEMSET nk_memset +#endif +#ifndef NK_MEMCPY +#define NK_MEMCPY nk_memcopy +#endif +#ifndef NK_SQRT +#define NK_SQRT nk_sqrt +#endif +#ifndef NK_SIN +#define NK_SIN nk_sin +#endif +#ifndef NK_COS +#define NK_COS nk_cos +#endif +#ifndef NK_STRTOD +#define NK_STRTOD nk_strtod +#endif +#ifndef NK_DTOA +#define NK_DTOA nk_dtoa +#endif + +#define NK_DEFAULT (-1) + +#ifndef NK_VSNPRINTF +/* If your compiler does support `vsnprintf` I would highly recommend + * defining this to vsnprintf instead since `vsprintf` is basically + * unbelievable unsafe and should *NEVER* be used. But I have to support + * it since C89 only provides this unsafe version. */ + #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) ||\ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) ||\ + (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) ||\ + defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE) + #define NK_VSNPRINTF(s,n,f,a) vsnprintf(s,n,f,a) + #else + #define NK_VSNPRINTF(s,n,f,a) vsprintf(s,f,a) + #endif +#endif + +#define NK_SCHAR_MIN (-127) +#define NK_SCHAR_MAX 127 +#define NK_UCHAR_MIN 0 +#define NK_UCHAR_MAX 256 +#define NK_SSHORT_MIN (-32767) +#define NK_SSHORT_MAX 32767 +#define NK_USHORT_MIN 0 +#define NK_USHORT_MAX 65535 +#define NK_SINT_MIN (-2147483647) +#define NK_SINT_MAX 2147483647 +#define NK_UINT_MIN 0 +#define NK_UINT_MAX 4294967295u + +/* Make sure correct type size: + * This will fire with a negative subscript error if the type sizes + * are set incorrectly by the compiler, and compile out if not */ +NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*)); +NK_STATIC_ASSERT(sizeof(nk_ptr) == sizeof(void*)); +NK_STATIC_ASSERT(sizeof(nk_flags) >= 4); +NK_STATIC_ASSERT(sizeof(nk_rune) >= 4); +NK_STATIC_ASSERT(sizeof(nk_ushort) == 2); +NK_STATIC_ASSERT(sizeof(nk_short) == 2); +NK_STATIC_ASSERT(sizeof(nk_uint) == 4); +NK_STATIC_ASSERT(sizeof(nk_int) == 4); +NK_STATIC_ASSERT(sizeof(nk_byte) == 1); + +NK_GLOBAL const struct nk_rect nk_null_rect = {-8192.0f, -8192.0f, 16384, 16384}; +#define NK_FLOAT_PRECISION 0.00000000000001 + +NK_GLOBAL const struct nk_color nk_red = {255,0,0,255}; +NK_GLOBAL const struct nk_color nk_green = {0,255,0,255}; +NK_GLOBAL const struct nk_color nk_blue = {0,0,255,255}; +NK_GLOBAL const struct nk_color nk_white = {255,255,255,255}; +NK_GLOBAL const struct nk_color nk_black = {0,0,0,255}; +NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255}; + +/* + * ============================================================== + * + * MATH + * + * =============================================================== + */ +/* Since nuklear is supposed to work on all systems providing floating point + math without any dependencies I also had to implement my own math functions + for sqrt, sin and cos. Since the actual highly accurate implementations for + the standard library functions are quite complex and I do not need high + precision for my use cases I use approximations. + + Sqrt + ---- + For square root nuklear uses the famous fast inverse square root: + https://en.wikipedia.org/wiki/Fast_inverse_square_root with + slightly tweaked magic constant. While on todays hardware it is + probably not faster it is still fast and accurate enough for + nuklear's use cases. IMPORTANT: this requires float format IEEE 754 + + Sine/Cosine + ----------- + All constants inside both function are generated Remez's minimax + approximations for value range 0...2*PI. The reason why I decided to + approximate exactly that range is that nuklear only needs sine and + cosine to generate circles which only requires that exact range. + In addition I used Remez instead of Taylor for additional precision: + www.lolengine.net/blog/2011/12/21/better-function-approximatations. + + The tool I used to generate constants for both sine and cosine + (it can actually approximate a lot more functions) can be + found here: www.lolengine.net/wiki/oss/lolremez +*/ +NK_INTERN float +nk_inv_sqrt(float number) +{ + float x2; + const float threehalfs = 1.5f; + union {nk_uint i; float f;} conv = {0}; + conv.f = number; + x2 = number * 0.5f; + conv.i = 0x5f375A84 - (conv.i >> 1); + conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f)); + return conv.f; +} + +NK_INTERN float +nk_sqrt(float x) +{ + return x * nk_inv_sqrt(x); +} + +NK_INTERN float +nk_sin(float x) +{ + NK_STORAGE const float a0 = +1.91059300966915117e-31f; + NK_STORAGE const float a1 = +1.00086760103908896f; + NK_STORAGE const float a2 = -1.21276126894734565e-2f; + NK_STORAGE const float a3 = -1.38078780785773762e-1f; + NK_STORAGE const float a4 = -2.67353392911981221e-2f; + NK_STORAGE const float a5 = +2.08026600266304389e-2f; + NK_STORAGE const float a6 = -3.03996055049204407e-3f; + NK_STORAGE const float a7 = +1.38235642404333740e-4f; + return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7)))))); +} + +NK_INTERN float +nk_cos(float x) +{ + NK_STORAGE const float a0 = +1.00238601909309722f; + NK_STORAGE const float a1 = -3.81919947353040024e-2f; + NK_STORAGE const float a2 = -3.94382342128062756e-1f; + NK_STORAGE const float a3 = -1.18134036025221444e-1f; + NK_STORAGE const float a4 = +1.07123798512170878e-1f; + NK_STORAGE const float a5 = -1.86637164165180873e-2f; + NK_STORAGE const float a6 = +9.90140908664079833e-4f; + NK_STORAGE const float a7 = -5.23022132118824778e-14f; + return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7)))))); +} + +NK_INTERN nk_uint +nk_round_up_pow2(nk_uint v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +NK_API struct nk_rect +nk_get_null_rect(void) +{ + return nk_null_rect; +} + +NK_API struct nk_rect +nk_rect(float x, float y, float w, float h) +{ + struct nk_rect r; + r.x = x; r.y = y; + r.w = w; r.h = h; + return r; +} + +NK_API struct nk_rect +nk_recti(int x, int y, int w, int h) +{ + struct nk_rect r; + r.x = (float)x; + r.y = (float)y; + r.w = (float)w; + r.h = (float)h; + return r; +} + +NK_API struct nk_rect +nk_recta(struct nk_vec2 pos, struct nk_vec2 size) +{ + return nk_rect(pos.x, pos.y, size.x, size.y); +} + +NK_API struct nk_rect +nk_rectv(const float *r) +{ + return nk_rect(r[0], r[1], r[2], r[3]); +} + +NK_API struct nk_rect +nk_rectiv(const int *r) +{ + return nk_recti(r[0], r[1], r[2], r[3]); +} + +NK_API struct nk_vec2 +nk_rect_pos(struct nk_rect r) +{ + struct nk_vec2 ret; + ret.x = r.x; ret.y = r.y; + return ret; +} + +NK_API struct nk_vec2 +nk_rect_size(struct nk_rect r) +{ + struct nk_vec2 ret; + ret.x = r.w; ret.y = r.h; + return ret; +} + +NK_INTERN struct nk_rect +nk_shrink_rect(struct nk_rect r, float amount) +{ + struct nk_rect res; + r.w = NK_MAX(r.w, 2 * amount); + r.h = NK_MAX(r.h, 2 * amount); + res.x = r.x + amount; + res.y = r.y + amount; + res.w = r.w - 2 * amount; + res.h = r.h - 2 * amount; + return res; +} + +NK_INTERN struct nk_rect +nk_pad_rect(struct nk_rect r, struct nk_vec2 pad) +{ + r.w = NK_MAX(r.w, 2 * pad.x); + r.h = NK_MAX(r.h, 2 * pad.y); + r.x += pad.x; r.y += pad.y; + r.w -= 2 * pad.x; + r.h -= 2 * pad.y; + return r; +} + +NK_API struct nk_vec2 +nk_vec2(float x, float y) +{ + struct nk_vec2 ret; + ret.x = x; ret.y = y; + return ret; +} + +NK_API struct nk_vec2 +nk_vec2i(int x, int y) +{ + struct nk_vec2 ret; + ret.x = (float)x; + ret.y = (float)y; + return ret; +} + +NK_API struct nk_vec2 +nk_vec2v(const float *v) +{ + return nk_vec2(v[0], v[1]); +} + +NK_API struct nk_vec2 +nk_vec2iv(const int *v) +{ + return nk_vec2i(v[0], v[1]); +} + +/* + * ============================================================== + * + * UTIL + * + * =============================================================== + */ +NK_INTERN int nk_str_match_here(const char *regexp, const char *text); +NK_INTERN int nk_str_match_star(int c, const char *regexp, const char *text); +NK_INTERN int nk_is_lower(int c) {return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF);} +NK_INTERN int nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && c <= 0xDF);} +NK_INTERN int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;} +NK_INTERN int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;} + +NK_INTERN void* +nk_memcopy(void *dst0, const void *src0, nk_size length) +{ + nk_ptr t; + char *dst = (char*)dst0; + const char *src = (const char*)src0; + if (length == 0 || dst == src) + goto done; + + #define nk_word int + #define nk_wsize sizeof(nk_word) + #define nk_wmask (nk_wsize-1) + #define NK_TLOOP(s) if (t) NK_TLOOP1(s) + #define NK_TLOOP1(s) do { s; } while (--t) + + if (dst < src) { + t = (nk_ptr)src; /* only need low bits */ + if ((t | (nk_ptr)dst) & nk_wmask) { + if ((t ^ (nk_ptr)dst) & nk_wmask || length < nk_wsize) + t = length; + else + t = nk_wsize - (t & nk_wmask); + length -= t; + NK_TLOOP1(*dst++ = *src++); + } + t = length / nk_wsize; + NK_TLOOP(*(nk_word*)(void*)dst = *(const nk_word*)(const void*)src; + src += nk_wsize; dst += nk_wsize); + t = length & nk_wmask; + NK_TLOOP(*dst++ = *src++); + } else { + src += length; + dst += length; + t = (nk_ptr)src; + if ((t | (nk_ptr)dst) & nk_wmask) { + if ((t ^ (nk_ptr)dst) & nk_wmask || length <= nk_wsize) + t = length; + else + t &= nk_wmask; + length -= t; + NK_TLOOP1(*--dst = *--src); + } + t = length / nk_wsize; + NK_TLOOP(src -= nk_wsize; dst -= nk_wsize; + *(nk_word*)(void*)dst = *(const nk_word*)(const void*)src); + t = length & nk_wmask; + NK_TLOOP(*--dst = *--src); + } + #undef nk_word + #undef nk_wsize + #undef nk_wmask + #undef NK_TLOOP + #undef NK_TLOOP1 +done: + return (dst0); +} + +NK_INTERN void +nk_memset(void *ptr, int c0, nk_size size) +{ + #define nk_word unsigned + #define nk_wsize sizeof(nk_word) + #define nk_wmask (nk_wsize - 1) + nk_byte *dst = (nk_byte*)ptr; + unsigned c = 0; + nk_size t = 0; + + if ((c = (nk_byte)c0) != 0) { + c = (c << 8) | c; /* at least 16-bits */ + if (sizeof(unsigned int) > 2) + c = (c << 16) | c; /* at least 32-bits*/ + } + + /* too small of a word count */ + dst = (nk_byte*)ptr; + if (size < 3 * nk_wsize) { + while (size--) *dst++ = (nk_byte)c0; + return; + } + + /* align destination */ + if ((t = NK_PTR_TO_UINT(dst) & nk_wmask) != 0) { + t = nk_wsize -t; + size -= t; + do { + *dst++ = (nk_byte)c0; + } while (--t != 0); + } + + /* fill word */ + t = size / nk_wsize; + do { + *(nk_word*)((void*)dst) = c; + dst += nk_wsize; + } while (--t != 0); + + /* fill trailing bytes */ + t = (size & nk_wmask); + if (t != 0) { + do { + *dst++ = (nk_byte)c0; + } while (--t != 0); + } + + #undef nk_word + #undef nk_wsize + #undef nk_wmask +} + +NK_INTERN void +nk_zero(void *ptr, nk_size size) +{ + NK_ASSERT(ptr); + NK_MEMSET(ptr, 0, size); +} + +NK_API int +nk_strlen(const char *str) +{ + int siz = 0; + NK_ASSERT(str); + while (str && *str++ != '\0') siz++; + return siz; +} + +NK_API int +nk_strtoi(const char *str, const char **endptr) +{ + int neg = 1; + const char *p = str; + int value = 0; + + NK_ASSERT(str); + if (!str) return 0; + + /* skip whitespace */ + while (*p == ' ') p++; + if (*p == '-') { + neg = -1; + p++; + } + while (*p && *p >= '0' && *p <= '9') { + value = value * 10 + (int) (*p - '0'); + p++; + } + if (endptr) + *endptr = p; + return neg*value; +} + +NK_API double +nk_strtod(const char *str, const char **endptr) +{ + double m; + double neg = 1.0; + const char *p = str; + double value = 0; + double number = 0; + + NK_ASSERT(str); + if (!str) return 0; + + /* skip whitespace */ + while (*p == ' ') p++; + if (*p == '-') { + neg = -1.0; + p++; + } + + while (*p && *p != '.' && *p != 'e') { + value = value * 10.0 + (double) (*p - '0'); + p++; + } + + if (*p == '.') { + p++; + for(m = 0.1; *p && *p != 'e'; p++ ) { + value = value + (double) (*p - '0') * m; + m *= 0.1; + } + } + if (*p == 'e') { + int i, pow, div; + p++; + if (*p == '-') { + div = nk_true; + p++; + } else if (*p == '+') { + div = nk_false; + p++; + } else div = nk_false; + + for (pow = 0; *p; p++) + pow = pow * 10 + (int) (*p - '0'); + + for (m = 1.0, i = 0; i < pow; i++) + m *= 10.0; + + if (div) + value /= m; + else value *= m; + } + number = value * neg; + if (endptr) + *endptr = p; + return number; +} + +NK_API float +nk_strtof(const char *str, const char **endptr) +{ + float float_value; + double double_value; + double_value = NK_STRTOD(str, endptr); + float_value = (float)double_value; + return float_value; +} + +NK_API int +nk_stricmp(const char *s1, const char *s2) +{ + nk_int c1,c2,d; + do { + c1 = *s1++; + c2 = *s2++; + d = c1 - c2; + while (d) { + if (c1 <= 'Z' && c1 >= 'A') { + d += ('a' - 'A'); + if (!d) break; + } + if (c2 <= 'Z' && c2 >= 'A') { + d -= ('a' - 'A'); + if (!d) break; + } + return ((d >= 0) << 1) - 1; + } + } while (c1); + return 0; +} + +NK_API int +nk_stricmpn(const char *s1, const char *s2, int n) +{ + int c1,c2,d; + NK_ASSERT(n >= 0); + do { + c1 = *s1++; + c2 = *s2++; + if (!n--) return 0; + + d = c1 - c2; + while (d) { + if (c1 <= 'Z' && c1 >= 'A') { + d += ('a' - 'A'); + if (!d) break; + } + if (c2 <= 'Z' && c2 >= 'A') { + d -= ('a' - 'A'); + if (!d) break; + } + return ((d >= 0) << 1) - 1; + } + } while (c1); + return 0; +} + +NK_INTERN int +nk_str_match_here(const char *regexp, const char *text) +{ + if (regexp[0] == '\0') + return 1; + if (regexp[1] == '*') + return nk_str_match_star(regexp[0], regexp+2, text); + if (regexp[0] == '$' && regexp[1] == '\0') + return *text == '\0'; + if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text)) + return nk_str_match_here(regexp+1, text+1); + return 0; +} + +NK_INTERN int +nk_str_match_star(int c, const char *regexp, const char *text) +{ + do {/* a '* matches zero or more instances */ + if (nk_str_match_here(regexp, text)) + return 1; + } while (*text != '\0' && (*text++ == c || c == '.')); + return 0; +} + +NK_API int +nk_strfilter(const char *text, const char *regexp) +{ + /* + c matches any literal character c + . matches any single character + ^ matches the beginning of the input string + $ matches the end of the input string + * matches zero or more occurrences of the previous character*/ + if (regexp[0] == '^') + return nk_str_match_here(regexp+1, text); + do { /* must look even if string is empty */ + if (nk_str_match_here(regexp, text)) + return 1; + } while (*text++ != '\0'); + return 0; +} + +NK_API int +nk_strmatch_fuzzy_text(const char *str, int str_len, + const char *pattern, int *out_score) +{ + /* Returns true if each character in pattern is found sequentially within str + * if found then outScore is also set. Score value has no intrinsic meaning. + * Range varies with pattern. Can only compare scores with same search pattern. */ + + /* ------- scores --------- */ + /* bonus for adjacent matches */ + #define NK_ADJACENCY_BONUS 5 + /* bonus if match occurs after a separator */ + #define NK_SEPARATOR_BONUS 10 + /* bonus if match is uppercase and prev is lower */ + #define NK_CAMEL_BONUS 10 + /* penalty applied for every letter in str before the first match */ + #define NK_LEADING_LETTER_PENALTY (-3) + /* maximum penalty for leading letters */ + #define NK_MAX_LEADING_LETTER_PENALTY (-9) + /* penalty for every letter that doesn't matter */ + #define NK_UNMATCHED_LETTER_PENALTY (-1) + + /* loop variables */ + int score = 0; + char const * pattern_iter = pattern; + int str_iter = 0; + int prev_matched = nk_false; + int prev_lower = nk_false; + /* true so if first letter match gets separator bonus*/ + int prev_separator = nk_true; + + /* use "best" matched letter if multiple string letters match the pattern */ + char const * best_letter = 0; + int best_letter_score = 0; + + /* loop over strings */ + NK_ASSERT(str); + NK_ASSERT(pattern); + if (!str || !str_len || !pattern) return 0; + while (str_iter < str_len) + { + const char pattern_letter = *pattern_iter; + const char str_letter = str[str_iter]; + + int next_match = *pattern_iter != '\0' && + nk_to_lower(pattern_letter) == nk_to_lower(str_letter); + int rematch = best_letter && nk_to_upper(*best_letter) == nk_to_upper(str_letter); + + int advanced = next_match && best_letter; + int pattern_repeat = best_letter && *pattern_iter != '\0'; + pattern_repeat = pattern_repeat && + nk_to_lower(*best_letter) == nk_to_lower(pattern_letter); + + if (advanced || pattern_repeat) { + score += best_letter_score; + best_letter = 0; + best_letter_score = 0; + } + + if (next_match || rematch) + { + int new_score = 0; + /* Apply penalty for each letter before the first pattern match */ + if (pattern_iter == pattern) { + int count = (int)(&str[str_iter] - str); + int penalty = NK_LEADING_LETTER_PENALTY * count; + if (penalty < NK_MAX_LEADING_LETTER_PENALTY) + penalty = NK_MAX_LEADING_LETTER_PENALTY; + + score += penalty; + } + + /* apply bonus for consecutive bonuses */ + if (prev_matched) + new_score += NK_ADJACENCY_BONUS; + + /* apply bonus for matches after a separator */ + if (prev_separator) + new_score += NK_SEPARATOR_BONUS; + + /* apply bonus across camel case boundaries */ + if (prev_lower && nk_is_upper(str_letter)) + new_score += NK_CAMEL_BONUS; + + /* update pattern iter IFF the next pattern letter was matched */ + if (next_match) + ++pattern_iter; + + /* update best letter in str which may be for a "next" letter or a rematch */ + if (new_score >= best_letter_score) { + /* apply penalty for now skipped letter */ + if (best_letter != 0) + score += NK_UNMATCHED_LETTER_PENALTY; + + best_letter = &str[str_iter]; + best_letter_score = new_score; + } + prev_matched = nk_true; + } else { + score += NK_UNMATCHED_LETTER_PENALTY; + prev_matched = nk_false; + } + + /* separators should be more easily defined */ + prev_lower = nk_is_lower(str_letter) != 0; + prev_separator = str_letter == '_' || str_letter == ' '; + + ++str_iter; + } + + /* apply score for last match */ + if (best_letter) + score += best_letter_score; + + /* did not match full pattern */ + if (*pattern_iter != '\0') + return nk_false; + + if (out_score) + *out_score = score; + return nk_true; +} + +NK_API int +nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score) +{return nk_strmatch_fuzzy_text(str, nk_strlen(str), pattern, out_score);} + +NK_INTERN int +nk_string_float_limit(char *string, int prec) +{ + int dot = 0; + char *c = string; + while (*c) { + if (*c == '.') { + dot = 1; + c++; + continue; + } + if (dot == (prec+1)) { + *c = 0; + break; + } + if (dot > 0) dot++; + c++; + } + return (int)(c - string); +} + +NK_INTERN double +nk_pow(double x, int n) +{ + /* check the sign of n */ + double r = 1; + int plus = n >= 0; + n = (plus) ? n : -n; + while (n > 0) { + if ((n & 1) == 1) + r *= x; + n /= 2; + x *= x; + } + return plus ? r : 1.0 / r; +} + +NK_INTERN int +nk_ifloord(double x) +{ + x = (double)((int)x - ((x < 0.0) ? 1 : 0)); + return (int)x; +} + +NK_INTERN int +nk_ifloorf(float x) +{ + x = (float)((int)x - ((x < 0.0f) ? 1 : 0)); + return (int)x; +} + +NK_INTERN int +nk_iceilf(float x) +{ + if (x >= 0) { + int i = (int)x; + return i; + } else { + int t = (int)x; + float r = x - (float)t; + return (r > 0.0f) ? t+1: t; + } +} + +NK_INTERN int +nk_log10(double n) +{ + int neg; + int ret; + int exp = 0; + + neg = (n < 0) ? 1 : 0; + ret = (neg) ? (int)-n : (int)n; + while ((ret / 10) > 0) { + ret /= 10; + exp++; + } + if (neg) exp = -exp; + return exp; +} + +NK_INTERN void +nk_strrev_ascii(char *s) +{ + int len = nk_strlen(s); + int end = len / 2; + int i = 0; + char t; + for (; i < end; ++i) { + t = s[i]; + s[i] = s[len - 1 - i]; + s[len -1 - i] = t; + } +} + +NK_INTERN char* +nk_itoa(char *s, long n) +{ + long i = 0; + if (n == 0) { + s[i++] = '0'; + s[i] = 0; + return s; + } + if (n < 0) { + s[i++] = '-'; + n = -n; + } + while (n > 0) { + s[i++] = (char)('0' + (n % 10)); + n /= 10; + } + s[i] = 0; + if (s[0] == '-') + ++s; + + nk_strrev_ascii(s); + return s; +} + +NK_INTERN char* +nk_dtoa(char *s, double n) +{ + int useExp = 0; + int digit = 0, m = 0, m1 = 0; + char *c = s; + int neg = 0; + + NK_ASSERT(s); + if (!s) return 0; + + if (n == 0.0) { + s[0] = '0'; s[1] = '\0'; + return s; + } + + neg = (n < 0); + if (neg) n = -n; + + /* calculate magnitude */ + m = nk_log10(n); + useExp = (m >= 14 || (neg && m >= 9) || m <= -9); + if (neg) *(c++) = '-'; + + /* set up for scientific notation */ + if (useExp) { + if (m < 0) + m -= 1; + n = n / (double)nk_pow(10.0, m); + m1 = m; + m = 0; + } + if (m < 1.0) { + m = 0; + } + + /* convert the number */ + while (n > NK_FLOAT_PRECISION || m >= 0) { + double weight = nk_pow(10.0, m); + if (weight > 0) { + double t = (double)n / weight; + digit = nk_ifloord(t); + n -= ((double)digit * weight); + *(c++) = (char)('0' + (char)digit); + } + if (m == 0 && n > 0) + *(c++) = '.'; + m--; + } + + if (useExp) { + /* convert the exponent */ + int i, j; + *(c++) = 'e'; + if (m1 > 0) { + *(c++) = '+'; + } else { + *(c++) = '-'; + m1 = -m1; + } + m = 0; + while (m1 > 0) { + *(c++) = (char)('0' + (char)(m1 % 10)); + m1 /= 10; + m++; + } + c -= m; + for (i = 0, j = m-1; i= buf_size) break; + iter++; + + /* flag arguments */ + while (*iter) { + if (*iter == '-') flag |= NK_ARG_FLAG_LEFT; + else if (*iter == '+') flag |= NK_ARG_FLAG_PLUS; + else if (*iter == ' ') flag |= NK_ARG_FLAG_SPACE; + else if (*iter == '#') flag |= NK_ARG_FLAG_NUM; + else if (*iter == '0') flag |= NK_ARG_FLAG_ZERO; + else break; + iter++; + } + + /* width argument */ + width = NK_DEFAULT; + if (*iter >= '1' && *iter <= '9') { + const char *end; + width = nk_strtoi(iter, &end); + if (end == iter) + width = -1; + else iter = end; + } else if (*iter == '*') { + width = va_arg(args, int); + iter++; + } + + /* precision argument */ + precision = NK_DEFAULT; + if (*iter == '.') { + iter++; + if (*iter == '*') { + precision = va_arg(args, int); + iter++; + } else { + const char *end; + precision = nk_strtoi(iter, &end); + if (end == iter) + precision = -1; + else iter = end; + } + } + + /* length modifier */ + if (*iter == 'h') { + if (*(iter+1) == 'h') { + arg_type = NK_ARG_TYPE_CHAR; + iter++; + } else arg_type = NK_ARG_TYPE_SHORT; + iter++; + } else if (*iter == 'l') { + arg_type = NK_ARG_TYPE_LONG; + iter++; + } else arg_type = NK_ARG_TYPE_DEFAULT; + + /* specifier */ + if (*iter == '%') { + NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); + NK_ASSERT(precision == NK_DEFAULT); + NK_ASSERT(width == NK_DEFAULT); + if (len < buf_size) + buf[len++] = '%'; + } else if (*iter == 's') { + /* string */ + const char *str = va_arg(args, const char*); + NK_ASSERT(str != buf && "buffer and argument are not allowed to overlap!"); + NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); + NK_ASSERT(precision == NK_DEFAULT); + NK_ASSERT(width == NK_DEFAULT); + if (str == buf) return -1; + while (str && *str && len < buf_size) + buf[len++] = *str++; + } else if (*iter == 'n') { + /* current length callback */ + signed int *n = va_arg(args, int*); + NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); + NK_ASSERT(precision == NK_DEFAULT); + NK_ASSERT(width == NK_DEFAULT); + if (n) *n = len; + } else if (*iter == 'c' || *iter == 'i' || *iter == 'd') { + /* signed integer */ + long value = 0; + const char *num_iter; + int num_len, num_print, padding; + int cur_precision = NK_MAX(precision, 1); + int cur_width = NK_MAX(width, 0); + + /* retrieve correct value type */ + if (arg_type == NK_ARG_TYPE_CHAR) + value = (signed char)va_arg(args, int); + else if (arg_type == NK_ARG_TYPE_SHORT) + value = (signed short)va_arg(args, int); + else if (arg_type == NK_ARG_TYPE_LONG) + value = va_arg(args, signed long); + else if (*iter == 'c') + value = (unsigned char)va_arg(args, int); + else value = va_arg(args, signed int); + + /* convert number to string */ + nk_itoa(number_buffer, value); + num_len = nk_strlen(number_buffer); + padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0); + if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE)) + padding = NK_MAX(padding-1, 0); + + /* fill left padding up to a total of `width` characters */ + if (!(flag & NK_ARG_FLAG_LEFT)) { + while (padding-- > 0 && (len < buf_size)) { + if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT)) + buf[len++] = '0'; + else buf[len++] = ' '; + } + } + + /* copy string value representation into buffer */ + if ((flag & NK_ARG_FLAG_PLUS) && value >= 0 && len < buf_size) + buf[len++] = '+'; + else if ((flag & NK_ARG_FLAG_SPACE) && value >= 0 && len < buf_size) + buf[len++] = ' '; + + /* fill up to precision number of digits with '0' */ + num_print = NK_MAX(cur_precision, num_len); + while (precision && (num_print > num_len) && (len < buf_size)) { + buf[len++] = '0'; + num_print--; + } + + /* copy string value representation into buffer */ + num_iter = number_buffer; + while (precision && *num_iter && len < buf_size) + buf[len++] = *num_iter++; + + /* fill right padding up to width characters */ + if (flag & NK_ARG_FLAG_LEFT) { + while ((padding-- > 0) && (len < buf_size)) + buf[len++] = ' '; + } + } else if (*iter == 'o' || *iter == 'x' || *iter == 'X' || *iter == 'u') { + /* unsigned integer */ + unsigned long value = 0; + int num_len = 0, num_print, padding = 0; + int cur_precision = NK_MAX(precision, 1); + int cur_width = NK_MAX(width, 0); + unsigned int base = (*iter == 'o') ? 8: (*iter == 'u')? 10: 16; + + /* print oct/hex/dec value */ + const char *upper_output_format = "0123456789ABCDEF"; + const char *lower_output_format = "0123456789abcdef"; + const char *output_format = (*iter == 'x') ? + lower_output_format: upper_output_format; + + /* retrieve correct value type */ + if (arg_type == NK_ARG_TYPE_CHAR) + value = (unsigned char)va_arg(args, int); + else if (arg_type == NK_ARG_TYPE_SHORT) + value = (unsigned short)va_arg(args, int); + else if (arg_type == NK_ARG_TYPE_LONG) + value = va_arg(args, unsigned long); + else value = va_arg(args, unsigned int); + + do { + /* convert decimal number into hex/oct number */ + int digit = output_format[value % base]; + if (num_len < NK_MAX_NUMBER_BUFFER) + number_buffer[num_len++] = (char)digit; + value /= base; + } while (value > 0); + + num_print = NK_MAX(cur_precision, num_len); + padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0); + if (flag & NK_ARG_FLAG_NUM) + padding = NK_MAX(padding-1, 0); + + /* fill left padding up to a total of `width` characters */ + if (!(flag & NK_ARG_FLAG_LEFT)) { + while ((padding-- > 0) && (len < buf_size)) { + if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT)) + buf[len++] = '0'; + else buf[len++] = ' '; + } + } + + /* fill up to precision number of digits */ + if (num_print && (flag & NK_ARG_FLAG_NUM)) { + if ((*iter == 'o') && (len < buf_size)) { + buf[len++] = '0'; + } else if ((*iter == 'x') && ((len+1) < buf_size)) { + buf[len++] = '0'; + buf[len++] = 'x'; + } else if ((*iter == 'X') && ((len+1) < buf_size)) { + buf[len++] = '0'; + buf[len++] = 'X'; + } + } + while (precision && (num_print > num_len) && (len < buf_size)) { + buf[len++] = '0'; + num_print--; + } + + /* reverse number direction */ + while (num_len > 0) { + if (precision && (len < buf_size)) + buf[len++] = number_buffer[num_len-1]; + num_len--; + } + + /* fill right padding up to width characters */ + if (flag & NK_ARG_FLAG_LEFT) { + while ((padding-- > 0) && (len < buf_size)) + buf[len++] = ' '; + } + } else if (*iter == 'f') { + /* floating point */ + const char *num_iter; + int cur_precision = (precision < 0) ? 6: precision; + int prefix, cur_width = NK_MAX(width, 0); + double value = va_arg(args, double); + int num_len = 0, frac_len = 0, dot = 0; + int padding = 0; + + NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); + NK_DTOA(number_buffer, value); + num_len = nk_strlen(number_buffer); + + /* calculate padding */ + num_iter = number_buffer; + while (*num_iter && *num_iter != '.') + num_iter++; + + prefix = (*num_iter == '.')?(int)(num_iter - number_buffer)+1:0; + padding = NK_MAX(cur_width - (prefix + NK_MIN(cur_precision, num_len - prefix)) , 0); + if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE)) + padding = NK_MAX(padding-1, 0); + + /* fill left padding up to a total of `width` characters */ + if (!(flag & NK_ARG_FLAG_LEFT)) { + while (padding-- > 0 && (len < buf_size)) { + if (flag & NK_ARG_FLAG_ZERO) + buf[len++] = '0'; + else buf[len++] = ' '; + } + } + + /* copy string value representation into buffer */ + num_iter = number_buffer; + if ((flag & NK_ARG_FLAG_PLUS) && (value >= 0) && (len < buf_size)) + buf[len++] = '+'; + else if ((flag & NK_ARG_FLAG_SPACE) && (value >= 0) && (len < buf_size)) + buf[len++] = ' '; + while (*num_iter) { + if (dot) frac_len++; + if (len < buf_size) + buf[len++] = *num_iter; + if (*num_iter == '.') dot = 1; + if (frac_len >= cur_precision) break; + num_iter++; + } + + /* fill number up to precision */ + while (frac_len < cur_precision) { + if (!dot && len < buf_size) { + buf[len++] = '.'; + dot = 1; + } + if (len < buf_size) + buf[len++] = '0'; + frac_len++; + } + + /* fill right padding up to width characters */ + if (flag & NK_ARG_FLAG_LEFT) { + while ((padding-- > 0) && (len < buf_size)) + buf[len++] = ' '; + } + } else { + /* Specifier not supported: g,G,e,E,p,z */ + NK_ASSERT(0 && "specifier is not supported!"); + return result; + } + } + buf[(len >= buf_size)?(buf_size-1):len] = 0; + result = (len >= buf_size)?-1:len; + return result; +} +#endif + +NK_INTERN int +nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args) +{ + int result = -1; + NK_ASSERT(buf); + NK_ASSERT(buf_size); + if (!buf || !buf_size || !fmt) return 0; +#ifdef NK_INCLUDE_STANDARD_IO + result = NK_VSNPRINTF(buf, (nk_size)buf_size, fmt, args); + result = (result >= buf_size) ? -1: result; + buf[buf_size-1] = 0; +#else + result = nk_vsnprintf(buf, buf_size, fmt, args); +#endif + return result; +} +#endif + +NK_API nk_hash +nk_murmur_hash(const void * key, int len, nk_hash seed) +{ + /* 32-Bit MurmurHash3: https://code.google.com/p/smhasher/wiki/MurmurHash3*/ + #define NK_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r))) + union {const nk_uint *i; const nk_byte *b;} conv = {0}; + const nk_byte *data = (const nk_byte*)key; + const int nblocks = len/4; + nk_uint h1 = seed; + const nk_uint c1 = 0xcc9e2d51; + const nk_uint c2 = 0x1b873593; + const nk_byte *tail; + const nk_uint *blocks; + nk_uint k1; + int i; + + /* body */ + if (!key) return 0; + conv.b = (data + nblocks*4); + blocks = (const nk_uint*)conv.i; + for (i = -nblocks; i; ++i) { + k1 = blocks[i]; + k1 *= c1; + k1 = NK_ROTL(k1,15); + k1 *= c2; + + h1 ^= k1; + h1 = NK_ROTL(h1,13); + h1 = h1*5+0xe6546b64; + } + + /* tail */ + tail = (const nk_byte*)(data + nblocks*4); + k1 = 0; + switch (len & 3) { + case 3: k1 ^= (nk_uint)(tail[2] << 16); + case 2: k1 ^= (nk_uint)(tail[1] << 8u); + case 1: k1 ^= tail[0]; + k1 *= c1; + k1 = NK_ROTL(k1,15); + k1 *= c2; + h1 ^= k1; + default: break; + } + + /* finalization */ + h1 ^= (nk_uint)len; + /* fmix32 */ + h1 ^= h1 >> 16; + h1 *= 0x85ebca6b; + h1 ^= h1 >> 13; + h1 *= 0xc2b2ae35; + h1 ^= h1 >> 16; + + #undef NK_ROTL + return h1; +} + +#ifdef NK_INCLUDE_STANDARD_IO +NK_INTERN char* +nk_file_load(const char* path, nk_size* siz, struct nk_allocator *alloc) +{ + char *buf; + FILE *fd; + long ret; + + NK_ASSERT(path); + NK_ASSERT(siz); + NK_ASSERT(alloc); + if (!path || !siz || !alloc) + return 0; + + fd = fopen(path, "rb"); + if (!fd) return 0; + fseek(fd, 0, SEEK_END); + ret = ftell(fd); + if (ret < 0) { + fclose(fd); + return 0; + } + *siz = (nk_size)ret; + fseek(fd, 0, SEEK_SET); + buf = (char*)alloc->alloc(alloc->userdata,0, *siz); + NK_ASSERT(buf); + if (!buf) { + fclose(fd); + return 0; + } + *siz = (nk_size)fread(buf, *siz, 1, fd); + fclose(fd); + return buf; +} +#endif + +/* + * ============================================================== + * + * COLOR + * + * =============================================================== + */ +NK_INTERN int +nk_parse_hex(const char *p, int length) +{ + int i = 0; + int len = 0; + while (len < length) { + i <<= 4; + if (p[len] >= 'a' && p[len] <= 'f') + i += ((p[len] - 'a') + 10); + else if (p[len] >= 'A' && p[len] <= 'F') + i += ((p[len] - 'A') + 10); + else i += (p[len] - '0'); + len++; + } + return i; +} + +NK_API struct nk_color +nk_rgba(int r, int g, int b, int a) +{ + struct nk_color ret; + ret.r = (nk_byte)NK_CLAMP(0, r, 255); + ret.g = (nk_byte)NK_CLAMP(0, g, 255); + ret.b = (nk_byte)NK_CLAMP(0, b, 255); + ret.a = (nk_byte)NK_CLAMP(0, a, 255); + return ret; +} + +NK_API struct nk_color +nk_rgb_hex(const char *rgb) +{ + struct nk_color col; + const char *c = rgb; + if (*c == '#') c++; + col.r = (nk_byte)nk_parse_hex(c, 2); + col.g = (nk_byte)nk_parse_hex(c+2, 2); + col.b = (nk_byte)nk_parse_hex(c+4, 2); + col.a = 255; + return col; +} + +NK_API struct nk_color +nk_rgba_hex(const char *rgb) +{ + struct nk_color col; + const char *c = rgb; + if (*c == '#') c++; + col.r = (nk_byte)nk_parse_hex(c, 2); + col.g = (nk_byte)nk_parse_hex(c+2, 2); + col.b = (nk_byte)nk_parse_hex(c+4, 2); + col.a = (nk_byte)nk_parse_hex(c+6, 2); + return col; +} + +NK_API void +nk_color_hex_rgba(char *output, struct nk_color col) +{ + #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i)) + output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4); + output[1] = (char)NK_TO_HEX((col.r & 0x0F)); + output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4); + output[3] = (char)NK_TO_HEX((col.g & 0x0F)); + output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4); + output[5] = (char)NK_TO_HEX((col.b & 0x0F)); + output[6] = (char)NK_TO_HEX((col.a & 0xF0) >> 4); + output[7] = (char)NK_TO_HEX((col.a & 0x0F)); + output[8] = '\0'; + #undef NK_TO_HEX +} + +NK_API void +nk_color_hex_rgb(char *output, struct nk_color col) +{ + #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i)) + output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4); + output[1] = (char)NK_TO_HEX((col.r & 0x0F)); + output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4); + output[3] = (char)NK_TO_HEX((col.g & 0x0F)); + output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4); + output[5] = (char)NK_TO_HEX((col.b & 0x0F)); + output[6] = '\0'; + #undef NK_TO_HEX +} + +NK_API struct nk_color +nk_rgba_iv(const int *c) +{ + return nk_rgba(c[0], c[1], c[2], c[3]); +} + +NK_API struct nk_color +nk_rgba_bv(const nk_byte *c) +{ + return nk_rgba(c[0], c[1], c[2], c[3]); +} + +NK_API struct nk_color +nk_rgb(int r, int g, int b) +{ + struct nk_color ret; + ret.r = (nk_byte)NK_CLAMP(0, r, 255); + ret.g = (nk_byte)NK_CLAMP(0, g, 255); + ret.b = (nk_byte)NK_CLAMP(0, b, 255); + ret.a = (nk_byte)255; + return ret; +} + +NK_API struct nk_color +nk_rgb_iv(const int *c) +{ + return nk_rgb(c[0], c[1], c[2]); +} + +NK_API struct nk_color +nk_rgb_bv(const nk_byte* c) +{ + return nk_rgb(c[0], c[1], c[2]); +} + +NK_API struct nk_color +nk_rgba_u32(nk_uint in) +{ + struct nk_color ret; + ret.r = (in & 0xFF); + ret.g = ((in >> 8) & 0xFF); + ret.b = ((in >> 16) & 0xFF); + ret.a = (nk_byte)((in >> 24) & 0xFF); + return ret; +} + +NK_API struct nk_color +nk_rgba_f(float r, float g, float b, float a) +{ + struct nk_color ret; + ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f); + ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f); + ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f); + ret.a = (nk_byte)(NK_SATURATE(a) * 255.0f); + return ret; +} + +NK_API struct nk_color +nk_rgba_fv(const float *c) +{ + return nk_rgba_f(c[0], c[1], c[2], c[3]); +} + +NK_API struct nk_color +nk_rgb_f(float r, float g, float b) +{ + struct nk_color ret; + ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f); + ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f); + ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f); + ret.a = 255; + return ret; +} + +NK_API struct nk_color +nk_rgb_fv(const float *c) +{ + return nk_rgb_f(c[0], c[1], c[2]); +} + +NK_API struct nk_color +nk_hsv(int h, int s, int v) +{ + return nk_hsva(h, s, v, 255); +} + +NK_API struct nk_color +nk_hsv_iv(const int *c) +{ + return nk_hsv(c[0], c[1], c[2]); +} + +NK_API struct nk_color +nk_hsv_bv(const nk_byte *c) +{ + return nk_hsv(c[0], c[1], c[2]); +} + +NK_API struct nk_color +nk_hsv_f(float h, float s, float v) +{ + return nk_hsva_f(h, s, v, 1.0f); +} + +NK_API struct nk_color +nk_hsv_fv(const float *c) +{ + return nk_hsv_f(c[0], c[1], c[2]); +} + +NK_API struct nk_color +nk_hsva(int h, int s, int v, int a) +{ + float hf = ((float)NK_CLAMP(0, h, 255)) / 255.0f; + float sf = ((float)NK_CLAMP(0, s, 255)) / 255.0f; + float vf = ((float)NK_CLAMP(0, v, 255)) / 255.0f; + float af = ((float)NK_CLAMP(0, a, 255)) / 255.0f; + return nk_hsva_f(hf, sf, vf, af); +} + +NK_API struct nk_color +nk_hsva_iv(const int *c) +{ + return nk_hsva(c[0], c[1], c[2], c[3]); +} + +NK_API struct nk_color +nk_hsva_bv(const nk_byte *c) +{ + return nk_hsva(c[0], c[1], c[2], c[3]); +} + +NK_API struct nk_color +nk_hsva_f(float h, float s, float v, float a) +{ + struct nk_colorf out = {0,0,0,0}; + float p, q, t, f; + int i; + + if (s <= 0.0f) { + out.r = v; out.g = v; out.b = v; + return nk_rgb_f(out.r, out.g, out.b); + } + + h = h / (60.0f/360.0f); + i = (int)h; + f = h - (float)i; + p = v * (1.0f - s); + q = v * (1.0f - (s * f)); + t = v * (1.0f - s * (1.0f - f)); + + switch (i) { + case 0: default: out.r = v; out.g = t; out.b = p; break; + case 1: out.r = q; out.g = v; out.b = p; break; + case 2: out.r = p; out.g = v; out.b = t; break; + case 3: out.r = p; out.g = q; out.b = v; break; + case 4: out.r = t; out.g = p; out.b = v; break; + case 5: out.r = v; out.g = p; out.b = q; break; + } + return nk_rgba_f(out.r, out.g, out.b, a); +} + +NK_API struct nk_color +nk_hsva_fv(const float *c) +{ + return nk_hsva_f(c[0], c[1], c[2], c[3]); +} + +NK_API nk_uint +nk_color_u32(struct nk_color in) +{ + nk_uint out = (nk_uint)in.r; + out |= ((nk_uint)in.g << 8); + out |= ((nk_uint)in.b << 16); + out |= ((nk_uint)in.a << 24); + return out; +} + +NK_API void +nk_color_f(float *r, float *g, float *b, float *a, struct nk_color in) +{ + NK_STORAGE const float s = 1.0f/255.0f; + *r = (float)in.r * s; + *g = (float)in.g * s; + *b = (float)in.b * s; + *a = (float)in.a * s; +} + +NK_API void +nk_color_fv(float *c, struct nk_color in) +{ + nk_color_f(&c[0], &c[1], &c[2], &c[3], in); +} + +NK_API void +nk_color_d(double *r, double *g, double *b, double *a, struct nk_color in) +{ + NK_STORAGE const double s = 1.0/255.0; + *r = (double)in.r * s; + *g = (double)in.g * s; + *b = (double)in.b * s; + *a = (double)in.a * s; +} + +NK_API void +nk_color_dv(double *c, struct nk_color in) +{ + nk_color_d(&c[0], &c[1], &c[2], &c[3], in); +} + +NK_API void +nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color in) +{ + float a; + nk_color_hsva_f(out_h, out_s, out_v, &a, in); +} + +NK_API void +nk_color_hsv_fv(float *out, struct nk_color in) +{ + float a; + nk_color_hsva_f(&out[0], &out[1], &out[2], &a, in); +} + +NK_API void +nk_color_hsva_f(float *out_h, float *out_s, + float *out_v, float *out_a, struct nk_color in) +{ + float chroma; + float K = 0.0f; + float r,g,b,a; + + nk_color_f(&r,&g,&b,&a, in); + if (g < b) { + const float t = g; g = b; b = t; + K = -1.f; + } + if (r < g) { + const float t = r; r = g; g = t; + K = -2.f/6.0f - K; + } + chroma = r - ((g < b) ? g: b); + *out_h = NK_ABS(K + (g - b)/(6.0f * chroma + 1e-20f)); + *out_s = chroma / (r + 1e-20f); + *out_v = r; + *out_a = (float)in.a / 255.0f; +} + +NK_API void +nk_color_hsva_fv(float *out, struct nk_color in) +{ + nk_color_hsva_f(&out[0], &out[1], &out[2], &out[3], in); +} + +NK_API void +nk_color_hsva_i(int *out_h, int *out_s, int *out_v, + int *out_a, struct nk_color in) +{ + float h,s,v,a; + nk_color_hsva_f(&h, &s, &v, &a, in); + *out_h = (nk_byte)(h * 255.0f); + *out_s = (nk_byte)(s * 255.0f); + *out_v = (nk_byte)(v * 255.0f); + *out_a = (nk_byte)(a * 255.0f); +} + +NK_API void +nk_color_hsva_iv(int *out, struct nk_color in) +{ + nk_color_hsva_i(&out[0], &out[1], &out[2], &out[3], in); +} + +NK_API void +nk_color_hsva_bv(nk_byte *out, struct nk_color in) +{ + int tmp[4]; + nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); + out[0] = (nk_byte)tmp[0]; + out[1] = (nk_byte)tmp[1]; + out[2] = (nk_byte)tmp[2]; + out[3] = (nk_byte)tmp[3]; +} + +NK_API void +nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color in) +{ + int tmp[4]; + nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); + *h = (nk_byte)tmp[0]; + *s = (nk_byte)tmp[1]; + *v = (nk_byte)tmp[2]; + *a = (nk_byte)tmp[3]; +} + +NK_API void +nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color in) +{ + int a; + nk_color_hsva_i(out_h, out_s, out_v, &a, in); +} + +NK_API void +nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color in) +{ + int tmp[4]; + nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); + *out_h = (nk_byte)tmp[0]; + *out_s = (nk_byte)tmp[1]; + *out_v = (nk_byte)tmp[2]; +} + +NK_API void +nk_color_hsv_iv(int *out, struct nk_color in) +{ + nk_color_hsv_i(&out[0], &out[1], &out[2], in); +} + +NK_API void +nk_color_hsv_bv(nk_byte *out, struct nk_color in) +{ + int tmp[4]; + nk_color_hsv_i(&tmp[0], &tmp[1], &tmp[2], in); + out[0] = (nk_byte)tmp[0]; + out[1] = (nk_byte)tmp[1]; + out[2] = (nk_byte)tmp[2]; +} +/* + * ============================================================== + * + * IMAGE + * + * =============================================================== + */ +NK_API nk_handle +nk_handle_ptr(void *ptr) +{ + nk_handle handle = {0}; + handle.ptr = ptr; + return handle; +} + +NK_API nk_handle +nk_handle_id(int id) +{ + nk_handle handle; + nk_zero_struct(handle); + handle.id = id; + return handle; +} + +NK_API struct nk_image +nk_subimage_ptr(void *ptr, unsigned short w, unsigned short h, struct nk_rect r) +{ + struct nk_image s; + nk_zero(&s, sizeof(s)); + s.handle.ptr = ptr; + s.w = w; s.h = h; + s.region[0] = (unsigned short)r.x; + s.region[1] = (unsigned short)r.y; + s.region[2] = (unsigned short)r.w; + s.region[3] = (unsigned short)r.h; + return s; +} + +NK_API struct nk_image +nk_subimage_id(int id, unsigned short w, unsigned short h, struct nk_rect r) +{ + struct nk_image s; + nk_zero(&s, sizeof(s)); + s.handle.id = id; + s.w = w; s.h = h; + s.region[0] = (unsigned short)r.x; + s.region[1] = (unsigned short)r.y; + s.region[2] = (unsigned short)r.w; + s.region[3] = (unsigned short)r.h; + return s; +} + +NK_API struct nk_image +nk_subimage_handle(nk_handle handle, unsigned short w, unsigned short h, + struct nk_rect r) +{ + struct nk_image s; + nk_zero(&s, sizeof(s)); + s.handle = handle; + s.w = w; s.h = h; + s.region[0] = (unsigned short)r.x; + s.region[1] = (unsigned short)r.y; + s.region[2] = (unsigned short)r.w; + s.region[3] = (unsigned short)r.h; + return s; +} + +NK_API struct nk_image +nk_image_handle(nk_handle handle) +{ + struct nk_image s; + nk_zero(&s, sizeof(s)); + s.handle = handle; + s.w = 0; s.h = 0; + s.region[0] = 0; + s.region[1] = 0; + s.region[2] = 0; + s.region[3] = 0; + return s; +} + +NK_API struct nk_image +nk_image_ptr(void *ptr) +{ + struct nk_image s; + nk_zero(&s, sizeof(s)); + NK_ASSERT(ptr); + s.handle.ptr = ptr; + s.w = 0; s.h = 0; + s.region[0] = 0; + s.region[1] = 0; + s.region[2] = 0; + s.region[3] = 0; + return s; +} + +NK_API struct nk_image +nk_image_id(int id) +{ + struct nk_image s; + nk_zero(&s, sizeof(s)); + s.handle.id = id; + s.w = 0; s.h = 0; + s.region[0] = 0; + s.region[1] = 0; + s.region[2] = 0; + s.region[3] = 0; + return s; +} + +NK_API int +nk_image_is_subimage(const struct nk_image* img) +{ + NK_ASSERT(img); + return !(img->w == 0 && img->h == 0); +} + +NK_INTERN void +nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0, + float x1, float y1) +{ + NK_ASSERT(a); + NK_ASSERT(clip); + clip->x = NK_MAX(a->x, x0); + clip->y = NK_MAX(a->y, y0); + clip->w = NK_MIN(a->x + a->w, x1) - clip->x; + clip->h = NK_MIN(a->y + a->h, y1) - clip->y; + clip->w = NK_MAX(0, clip->w); + clip->h = NK_MAX(0, clip->h); +} + +NK_API void +nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, + float pad_x, float pad_y, enum nk_heading direction) +{ + float w_half, h_half; + NK_ASSERT(result); + + r.w = NK_MAX(2 * pad_x, r.w); + r.h = NK_MAX(2 * pad_y, r.h); + r.w = r.w - 2 * pad_x; + r.h = r.h - 2 * pad_y; + + r.x = r.x + pad_x; + r.y = r.y + pad_y; + + w_half = r.w / 2.0f; + h_half = r.h / 2.0f; + + if (direction == NK_UP) { + result[0] = nk_vec2(r.x + w_half, r.y); + result[1] = nk_vec2(r.x + r.w, r.y + r.h); + result[2] = nk_vec2(r.x, r.y + r.h); + } else if (direction == NK_RIGHT) { + result[0] = nk_vec2(r.x, r.y); + result[1] = nk_vec2(r.x + r.w, r.y + h_half); + result[2] = nk_vec2(r.x, r.y + r.h); + } else if (direction == NK_DOWN) { + result[0] = nk_vec2(r.x, r.y); + result[1] = nk_vec2(r.x + r.w, r.y); + result[2] = nk_vec2(r.x + w_half, r.y + r.h); + } else { + result[0] = nk_vec2(r.x, r.y + h_half); + result[1] = nk_vec2(r.x + r.w, r.y); + result[2] = nk_vec2(r.x + r.w, r.y + r.h); + } +} + +NK_INTERN int +nk_text_clamp(const struct nk_user_font *font, const char *text, + int text_len, float space, int *glyphs, float *text_width, + nk_rune *sep_list, int sep_count) +{ + int i = 0; + int glyph_len = 0; + float last_width = 0; + nk_rune unicode = 0; + float width = 0; + int len = 0; + int g = 0; + float s; + + int sep_len = 0; + int sep_g = 0; + float sep_width = 0; + sep_count = NK_MAX(sep_count,0); + + glyph_len = nk_utf_decode(text, &unicode, text_len); + while (glyph_len && (width < space) && (len < text_len)) { + len += glyph_len; + s = font->width(font->userdata, font->height, text, len); + for (i = 0; i < sep_count; ++i) { + if (unicode != sep_list[i]) continue; + sep_width = last_width = width; + sep_g = g+1; + sep_len = len; + break; + } + if (i == sep_count){ + last_width = sep_width = width; + sep_g = g+1; + } + width = s; + glyph_len = nk_utf_decode(&text[len], &unicode, text_len - len); + g++; + } + if (len >= text_len) { + *glyphs = g; + *text_width = last_width; + return len; + } else { + *glyphs = sep_g; + *text_width = sep_width; + return (!sep_len) ? len: sep_len; + } +} + +enum {NK_DO_NOT_STOP_ON_NEW_LINE, NK_STOP_ON_NEW_LINE}; +NK_INTERN struct nk_vec2 +nk_text_calculate_text_bounds(const struct nk_user_font *font, + const char *begin, int byte_len, float row_height, const char **remaining, + struct nk_vec2 *out_offset, int *glyphs, int op) +{ + float line_height = row_height; + struct nk_vec2 text_size = nk_vec2(0,0); + float line_width = 0.0f; + + float glyph_width; + int glyph_len = 0; + nk_rune unicode = 0; + int text_len = 0; + if (!begin || byte_len <= 0 || !font) + return nk_vec2(0,row_height); + + glyph_len = nk_utf_decode(begin, &unicode, byte_len); + if (!glyph_len) return text_size; + glyph_width = font->width(font->userdata, font->height, begin, glyph_len); + + *glyphs = 0; + while ((text_len < byte_len) && glyph_len) { + if (unicode == '\n') { + text_size.x = NK_MAX(text_size.x, line_width); + text_size.y += line_height; + line_width = 0; + *glyphs+=1; + if (op == NK_STOP_ON_NEW_LINE) + break; + + text_len++; + glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); + continue; + } + + if (unicode == '\r') { + text_len++; + *glyphs+=1; + glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); + continue; + } + + *glyphs = *glyphs + 1; + text_len += glyph_len; + line_width += (float)glyph_width; + glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); + glyph_width = font->width(font->userdata, font->height, begin+text_len, glyph_len); + continue; + } + + if (text_size.x < line_width) + text_size.x = line_width; + if (out_offset) + *out_offset = nk_vec2(line_width, text_size.y + line_height); + if (line_width > 0 || text_size.y == 0.0f) + text_size.y += line_height; + if (remaining) + *remaining = begin+text_len; + return text_size; +} + +/* ============================================================== + * + * UTF-8 + * + * ===============================================================*/ +NK_GLOBAL const nk_byte nk_utfbyte[NK_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +NK_GLOBAL const nk_byte nk_utfmask[NK_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +NK_GLOBAL const nk_uint nk_utfmin[NK_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x10000}; +NK_GLOBAL const nk_uint nk_utfmax[NK_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +NK_INTERN int +nk_utf_validate(nk_rune *u, int i) +{ + NK_ASSERT(u); + if (!u) return 0; + if (!NK_BETWEEN(*u, nk_utfmin[i], nk_utfmax[i]) || + NK_BETWEEN(*u, 0xD800, 0xDFFF)) + *u = NK_UTF_INVALID; + for (i = 1; *u > nk_utfmax[i]; ++i); + return i; +} + +NK_INTERN nk_rune +nk_utf_decode_byte(char c, int *i) +{ + NK_ASSERT(i); + if (!i) return 0; + for(*i = 0; *i < (int)NK_LEN(nk_utfmask); ++(*i)) { + if (((nk_byte)c & nk_utfmask[*i]) == nk_utfbyte[*i]) + return (nk_byte)(c & ~nk_utfmask[*i]); + } + return 0; +} + +NK_API int +nk_utf_decode(const char *c, nk_rune *u, int clen) +{ + int i, j, len, type=0; + nk_rune udecoded; + + NK_ASSERT(c); + NK_ASSERT(u); + + if (!c || !u) return 0; + if (!clen) return 0; + *u = NK_UTF_INVALID; + + udecoded = nk_utf_decode_byte(c[0], &len); + if (!NK_BETWEEN(len, 1, NK_UTF_SIZE)) + return 1; + + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | nk_utf_decode_byte(c[i], &type); + if (type != 0) + return j; + } + if (j < len) + return 0; + *u = udecoded; + nk_utf_validate(u, len); + return len; +} + +NK_INTERN char +nk_utf_encode_byte(nk_rune u, int i) +{ + return (char)((nk_utfbyte[i]) | ((nk_byte)u & ~nk_utfmask[i])); +} + +NK_API int +nk_utf_encode(nk_rune u, char *c, int clen) +{ + int len, i; + len = nk_utf_validate(&u, 0); + if (clen < len || !len || len > NK_UTF_SIZE) + return 0; + + for (i = len - 1; i != 0; --i) { + c[i] = nk_utf_encode_byte(u, 0); + u >>= 6; + } + c[0] = nk_utf_encode_byte(u, len); + return len; +} + +NK_API int +nk_utf_len(const char *str, int len) +{ + const char *text; + int glyphs = 0; + int text_len; + int glyph_len; + int src_len = 0; + nk_rune unicode; + + NK_ASSERT(str); + if (!str || !len) return 0; + + text = str; + text_len = len; + glyph_len = nk_utf_decode(text, &unicode, text_len); + while (glyph_len && src_len < len) { + glyphs++; + src_len = src_len + glyph_len; + glyph_len = nk_utf_decode(text + src_len, &unicode, text_len - src_len); + } + return glyphs; +} + +NK_API const char* +nk_utf_at(const char *buffer, int length, int index, + nk_rune *unicode, int *len) +{ + int i = 0; + int src_len = 0; + int glyph_len = 0; + const char *text; + int text_len; + + NK_ASSERT(buffer); + NK_ASSERT(unicode); + NK_ASSERT(len); + + if (!buffer || !unicode || !len) return 0; + if (index < 0) { + *unicode = NK_UTF_INVALID; + *len = 0; + return 0; + } + + text = buffer; + text_len = length; + glyph_len = nk_utf_decode(text, unicode, text_len); + while (glyph_len) { + if (i == index) { + *len = glyph_len; + break; + } + + i++; + src_len = src_len + glyph_len; + glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); + } + if (i != index) return 0; + return buffer + src_len; +} + +/* ============================================================== + * + * BUFFER + * + * ===============================================================*/ +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +NK_INTERN void* nk_malloc(nk_handle unused, void *old,nk_size size) +{NK_UNUSED(unused); NK_UNUSED(old); return malloc(size);} +NK_INTERN void nk_mfree(nk_handle unused, void *ptr) +{NK_UNUSED(unused); free(ptr);} + +NK_API void +nk_buffer_init_default(struct nk_buffer *buffer) +{ + struct nk_allocator alloc; + alloc.userdata.ptr = 0; + alloc.alloc = nk_malloc; + alloc.free = nk_mfree; + nk_buffer_init(buffer, &alloc, NK_BUFFER_DEFAULT_INITIAL_SIZE); +} +#endif + +NK_API void +nk_buffer_init(struct nk_buffer *b, const struct nk_allocator *a, + nk_size initial_size) +{ + NK_ASSERT(b); + NK_ASSERT(a); + NK_ASSERT(initial_size); + if (!b || !a || !initial_size) return; + + nk_zero(b, sizeof(*b)); + b->type = NK_BUFFER_DYNAMIC; + b->memory.ptr = a->alloc(a->userdata,0, initial_size); + b->memory.size = initial_size; + b->size = initial_size; + b->grow_factor = 2.0f; + b->pool = *a; +} + +NK_API void +nk_buffer_init_fixed(struct nk_buffer *b, void *m, nk_size size) +{ + NK_ASSERT(b); + NK_ASSERT(m); + NK_ASSERT(size); + if (!b || !m || !size) return; + + nk_zero(b, sizeof(*b)); + b->type = NK_BUFFER_FIXED; + b->memory.ptr = m; + b->memory.size = size; + b->size = size; +} + +NK_INTERN void* +nk_buffer_align(void *unaligned, nk_size align, nk_size *alignment, + enum nk_buffer_allocation_type type) +{ + void *memory = 0; + switch (type) { + default: + case NK_BUFFER_MAX: + case NK_BUFFER_FRONT: + if (align) { + memory = NK_ALIGN_PTR(unaligned, align); + *alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned); + } else { + memory = unaligned; + *alignment = 0; + } + break; + case NK_BUFFER_BACK: + if (align) { + memory = NK_ALIGN_PTR_BACK(unaligned, align); + *alignment = (nk_size)((nk_byte*)unaligned - (nk_byte*)memory); + } else { + memory = unaligned; + *alignment = 0; + } + break; + } + return memory; +} + +NK_INTERN void* +nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size) +{ + void *temp; + nk_size buffer_size; + + NK_ASSERT(b); + NK_ASSERT(size); + if (!b || !size || !b->pool.alloc || !b->pool.free) + return 0; + + buffer_size = b->memory.size; + temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity); + NK_ASSERT(temp); + if (!temp) return 0; + + *size = capacity; + if (temp != b->memory.ptr) { + NK_MEMCPY(temp, b->memory.ptr, buffer_size); + b->pool.free(b->pool.userdata, b->memory.ptr); + } + + if (b->size == buffer_size) { + /* no back buffer so just set correct size */ + b->size = capacity; + return temp; + } else { + /* copy back buffer to the end of the new buffer */ + void *dst, *src; + nk_size back_size; + back_size = buffer_size - b->size; + dst = nk_ptr_add(void, temp, capacity - back_size); + src = nk_ptr_add(void, temp, b->size); + NK_MEMCPY(dst, src, back_size); + b->size = capacity - back_size; + } + return temp; +} + +NK_INTERN void* +nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, + nk_size size, nk_size align) +{ + int full; + nk_size alignment; + void *unaligned; + void *memory; + + NK_ASSERT(b); + NK_ASSERT(size); + if (!b || !size) return 0; + b->needed += size; + + /* calculate total size with needed alignment + size */ + if (type == NK_BUFFER_FRONT) + unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated); + else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size); + memory = nk_buffer_align(unaligned, align, &alignment, type); + + /* check if buffer has enough memory*/ + if (type == NK_BUFFER_FRONT) + full = ((b->allocated + size + alignment) > b->size); + else full = ((b->size - NK_MIN(b->size,(size + alignment))) <= b->allocated); + + if (full) { + nk_size capacity; + if (b->type != NK_BUFFER_DYNAMIC) + return 0; + NK_ASSERT(b->pool.alloc && b->pool.free); + if (b->type != NK_BUFFER_DYNAMIC || !b->pool.alloc || !b->pool.free) + return 0; + + /* buffer is full so allocate bigger buffer if dynamic */ + capacity = (nk_size)((float)b->memory.size * b->grow_factor); + capacity = NK_MAX(capacity, nk_round_up_pow2((nk_uint)(b->allocated + size))); + b->memory.ptr = nk_buffer_realloc(b, capacity, &b->memory.size); + if (!b->memory.ptr) return 0; + + /* align newly allocated pointer */ + if (type == NK_BUFFER_FRONT) + unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated); + else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size); + memory = nk_buffer_align(unaligned, align, &alignment, type); + } + if (type == NK_BUFFER_FRONT) + b->allocated += size + alignment; + else b->size -= (size + alignment); + b->needed += alignment; + b->calls++; + return memory; +} + +NK_API void +nk_buffer_push(struct nk_buffer *b, enum nk_buffer_allocation_type type, + const void *memory, nk_size size, nk_size align) +{ + void *mem = nk_buffer_alloc(b, type, size, align); + if (!mem) return; + NK_MEMCPY(mem, memory, size); +} + +NK_API void +nk_buffer_mark(struct nk_buffer *buffer, enum nk_buffer_allocation_type type) +{ + NK_ASSERT(buffer); + if (!buffer) return; + buffer->marker[type].active = nk_true; + if (type == NK_BUFFER_BACK) + buffer->marker[type].offset = buffer->size; + else buffer->marker[type].offset = buffer->allocated; +} + +NK_API void +nk_buffer_reset(struct nk_buffer *buffer, enum nk_buffer_allocation_type type) +{ + NK_ASSERT(buffer); + if (!buffer) return; + if (type == NK_BUFFER_BACK) { + /* reset back buffer either back to marker or empty */ + buffer->needed -= (buffer->memory.size - buffer->marker[type].offset); + if (buffer->marker[type].active) + buffer->size = buffer->marker[type].offset; + else buffer->size = buffer->memory.size; + buffer->marker[type].active = nk_false; + } else { + /* reset front buffer either back to back marker or empty */ + buffer->needed -= (buffer->allocated - buffer->marker[type].offset); + if (buffer->marker[type].active) + buffer->allocated = buffer->marker[type].offset; + else buffer->allocated = 0; + buffer->marker[type].active = nk_false; + } +} + +NK_API void +nk_buffer_clear(struct nk_buffer *b) +{ + NK_ASSERT(b); + if (!b) return; + b->allocated = 0; + b->size = b->memory.size; + b->calls = 0; + b->needed = 0; +} + +NK_API void +nk_buffer_free(struct nk_buffer *b) +{ + NK_ASSERT(b); + if (!b || !b->memory.ptr) return; + if (b->type == NK_BUFFER_FIXED) return; + if (!b->pool.free) return; + NK_ASSERT(b->pool.free); + b->pool.free(b->pool.userdata, b->memory.ptr); +} + +NK_API void +nk_buffer_info(struct nk_memory_status *s, struct nk_buffer *b) +{ + NK_ASSERT(b); + NK_ASSERT(s); + if (!s || !b) return; + s->allocated = b->allocated; + s->size = b->memory.size; + s->needed = b->needed; + s->memory = b->memory.ptr; + s->calls = b->calls; +} + +NK_API void* +nk_buffer_memory(struct nk_buffer *buffer) +{ + NK_ASSERT(buffer); + if (!buffer) return 0; + return buffer->memory.ptr; +} + +NK_API const void* +nk_buffer_memory_const(const struct nk_buffer *buffer) +{ + NK_ASSERT(buffer); + if (!buffer) return 0; + return buffer->memory.ptr; +} + +NK_API nk_size +nk_buffer_total(struct nk_buffer *buffer) +{ + NK_ASSERT(buffer); + if (!buffer) return 0; + return buffer->memory.size; +} + +/* + * ============================================================== + * + * STRING + * + * =============================================================== + */ +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +NK_API void +nk_str_init_default(struct nk_str *str) +{ + struct nk_allocator alloc; + alloc.userdata.ptr = 0; + alloc.alloc = nk_malloc; + alloc.free = nk_mfree; + nk_buffer_init(&str->buffer, &alloc, 32); + str->len = 0; +} +#endif + +NK_API void +nk_str_init(struct nk_str *str, const struct nk_allocator *alloc, nk_size size) +{ + nk_buffer_init(&str->buffer, alloc, size); + str->len = 0; +} + +NK_API void +nk_str_init_fixed(struct nk_str *str, void *memory, nk_size size) +{ + nk_buffer_init_fixed(&str->buffer, memory, size); + str->len = 0; +} + +NK_API int +nk_str_append_text_char(struct nk_str *s, const char *str, int len) +{ + char *mem; + NK_ASSERT(s); + NK_ASSERT(str); + if (!s || !str || !len) return 0; + mem = (char*)nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0); + if (!mem) return 0; + NK_MEMCPY(mem, str, (nk_size)len * sizeof(char)); + s->len += nk_utf_len(str, len); + return len; +} + +NK_API int +nk_str_append_str_char(struct nk_str *s, const char *str) +{ + return nk_str_append_text_char(s, str, nk_strlen(str)); +} + +NK_API int +nk_str_append_text_utf8(struct nk_str *str, const char *text, int len) +{ + int i = 0; + int byte_len = 0; + nk_rune unicode; + if (!str || !text || !len) return 0; + for (i = 0; i < len; ++i) + byte_len += nk_utf_decode(text+byte_len, &unicode, 4); + nk_str_append_text_char(str, text, byte_len); + return len; +} + +NK_API int +nk_str_append_str_utf8(struct nk_str *str, const char *text) +{ + int runes = 0; + int byte_len = 0; + int num_runes = 0; + int glyph_len = 0; + nk_rune unicode; + if (!str || !text) return 0; + + glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4); + while (unicode != '\0' && glyph_len) { + glyph_len = nk_utf_decode(text+byte_len, &unicode, 4); + byte_len += glyph_len; + num_runes++; + } + nk_str_append_text_char(str, text, byte_len); + return runes; +} + +NK_API int +nk_str_append_text_runes(struct nk_str *str, const nk_rune *text, int len) +{ + int i = 0; + int byte_len = 0; + nk_glyph glyph; + + NK_ASSERT(str); + if (!str || !text || !len) return 0; + for (i = 0; i < len; ++i) { + byte_len = nk_utf_encode(text[i], glyph, NK_UTF_SIZE); + if (!byte_len) break; + nk_str_append_text_char(str, glyph, byte_len); + } + return len; +} + +NK_API int +nk_str_append_str_runes(struct nk_str *str, const nk_rune *runes) +{ + int i = 0; + nk_glyph glyph; + int byte_len; + NK_ASSERT(str); + if (!str || !runes) return 0; + while (runes[i] != '\0') { + byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); + nk_str_append_text_char(str, glyph, byte_len); + i++; + } + return i; +} + +NK_API int +nk_str_insert_at_char(struct nk_str *s, int pos, const char *str, int len) +{ + int i; + void *mem; + char *src; + char *dst; + + int copylen; + NK_ASSERT(s); + NK_ASSERT(str); + NK_ASSERT(len >= 0); + if (!s || !str || !len || (nk_size)pos > s->buffer.allocated) return 0; + if ((s->buffer.allocated + (nk_size)len >= s->buffer.memory.size) && + (s->buffer.type == NK_BUFFER_FIXED)) return 0; + + copylen = (int)s->buffer.allocated - pos; + if (!copylen) { + nk_str_append_text_char(s, str, len); + return 1; + } + mem = nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0); + if (!mem) return 0; + + /* memmove */ + NK_ASSERT(((int)pos + (int)len + ((int)copylen - 1)) >= 0); + NK_ASSERT(((int)pos + ((int)copylen - 1)) >= 0); + dst = nk_ptr_add(char, s->buffer.memory.ptr, pos + len + (copylen - 1)); + src = nk_ptr_add(char, s->buffer.memory.ptr, pos + (copylen-1)); + for (i = 0; i < copylen; ++i) *dst-- = *src--; + mem = nk_ptr_add(void, s->buffer.memory.ptr, pos); + NK_MEMCPY(mem, str, (nk_size)len * sizeof(char)); + s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); + return 1; +} + +NK_API int +nk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len) +{ + int glyph_len; + nk_rune unicode; + const char *begin; + const char *buffer; + + NK_ASSERT(str); + NK_ASSERT(cstr); + NK_ASSERT(len); + if (!str || !cstr || !len) return 0; + begin = nk_str_at_rune(str, pos, &unicode, &glyph_len); + if (!str->len) + return nk_str_append_text_char(str, cstr, len); + buffer = nk_str_get_const(str); + if (!begin) return 0; + return nk_str_insert_at_char(str, (int)(begin - buffer), cstr, len); +} + +NK_API int +nk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len) +{ + return nk_str_insert_text_utf8(str, pos, text, len); +} + +NK_API int +nk_str_insert_str_char(struct nk_str *str, int pos, const char *text) +{ + return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text)); +} + +NK_API int +nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len) +{ + int i = 0; + int byte_len = 0; + nk_rune unicode; + + NK_ASSERT(str); + NK_ASSERT(text); + if (!str || !text || !len) return 0; + for (i = 0; i < len; ++i) + byte_len += nk_utf_decode(text+byte_len, &unicode, 4); + nk_str_insert_at_rune(str, pos, text, byte_len); + return len; +} + +NK_API int +nk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text) +{ + int runes = 0; + int byte_len = 0; + int num_runes = 0; + int glyph_len = 0; + nk_rune unicode; + if (!str || !text) return 0; + + glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4); + while (unicode != '\0' && glyph_len) { + glyph_len = nk_utf_decode(text+byte_len, &unicode, 4); + byte_len += glyph_len; + num_runes++; + } + nk_str_insert_at_rune(str, pos, text, byte_len); + return runes; +} + +NK_API int +nk_str_insert_text_runes(struct nk_str *str, int pos, const nk_rune *runes, int len) +{ + int i = 0; + int byte_len = 0; + nk_glyph glyph; + + NK_ASSERT(str); + if (!str || !runes || !len) return 0; + for (i = 0; i < len; ++i) { + byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); + if (!byte_len) break; + nk_str_insert_at_rune(str, pos+i, glyph, byte_len); + } + return len; +} + +NK_API int +nk_str_insert_str_runes(struct nk_str *str, int pos, const nk_rune *runes) +{ + int i = 0; + nk_glyph glyph; + int byte_len; + NK_ASSERT(str); + if (!str || !runes) return 0; + while (runes[i] != '\0') { + byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); + nk_str_insert_at_rune(str, pos+i, glyph, byte_len); + i++; + } + return i; +} + +NK_API void +nk_str_remove_chars(struct nk_str *s, int len) +{ + NK_ASSERT(s); + NK_ASSERT(len >= 0); + if (!s || len < 0 || (nk_size)len > s->buffer.allocated) return; + NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0); + s->buffer.allocated -= (nk_size)len; + s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); +} + +NK_API void +nk_str_remove_runes(struct nk_str *str, int len) +{ + int index; + const char *begin; + const char *end; + nk_rune unicode; + + NK_ASSERT(str); + NK_ASSERT(len >= 0); + if (!str || len < 0) return; + if (len >= str->len) { + str->len = 0; + return; + } + + index = str->len - len; + begin = nk_str_at_rune(str, index, &unicode, &len); + end = (const char*)str->buffer.memory.ptr + str->buffer.allocated; + nk_str_remove_chars(str, (int)(end-begin)+1); +} + +NK_API void +nk_str_delete_chars(struct nk_str *s, int pos, int len) +{ + NK_ASSERT(s); + if (!s || !len || (nk_size)pos > s->buffer.allocated || + (nk_size)(pos + len) > s->buffer.allocated) return; + + if ((nk_size)(pos + len) < s->buffer.allocated) { + /* memmove */ + char *dst = nk_ptr_add(char, s->buffer.memory.ptr, pos); + char *src = nk_ptr_add(char, s->buffer.memory.ptr, pos + len); + NK_MEMCPY(dst, src, s->buffer.allocated - (nk_size)(pos + len)); + NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0); + s->buffer.allocated -= (nk_size)len; + } else nk_str_remove_chars(s, len); + s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); +} + +NK_API void +nk_str_delete_runes(struct nk_str *s, int pos, int len) +{ + char *temp; + nk_rune unicode; + char *begin; + char *end; + int unused; + + NK_ASSERT(s); + NK_ASSERT(s->len >= pos + len); + if (s->len < pos + len) + len = NK_CLAMP(0, (s->len - pos), s->len); + if (!len) return; + + temp = (char *)s->buffer.memory.ptr; + begin = nk_str_at_rune(s, pos, &unicode, &unused); + if (!begin) return; + s->buffer.memory.ptr = begin; + end = nk_str_at_rune(s, len, &unicode, &unused); + s->buffer.memory.ptr = temp; + if (!end) return; + nk_str_delete_chars(s, (int)(begin - temp), (int)(end - begin)); +} + +NK_API char* +nk_str_at_char(struct nk_str *s, int pos) +{ + NK_ASSERT(s); + if (!s || pos > (int)s->buffer.allocated) return 0; + return nk_ptr_add(char, s->buffer.memory.ptr, pos); +} + +NK_API char* +nk_str_at_rune(struct nk_str *str, int pos, nk_rune *unicode, int *len) +{ + int i = 0; + int src_len = 0; + int glyph_len = 0; + char *text; + int text_len; + + NK_ASSERT(str); + NK_ASSERT(unicode); + NK_ASSERT(len); + + if (!str || !unicode || !len) return 0; + if (pos < 0) { + *unicode = 0; + *len = 0; + return 0; + } + + text = (char*)str->buffer.memory.ptr; + text_len = (int)str->buffer.allocated; + glyph_len = nk_utf_decode(text, unicode, text_len); + while (glyph_len) { + if (i == pos) { + *len = glyph_len; + break; + } + + i++; + src_len = src_len + glyph_len; + glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); + } + if (i != pos) return 0; + return text + src_len; +} + +NK_API const char* +nk_str_at_char_const(const struct nk_str *s, int pos) +{ + NK_ASSERT(s); + if (!s || pos > (int)s->buffer.allocated) return 0; + return nk_ptr_add(char, s->buffer.memory.ptr, pos); +} + +NK_API const char* +nk_str_at_const(const struct nk_str *str, int pos, nk_rune *unicode, int *len) +{ + int i = 0; + int src_len = 0; + int glyph_len = 0; + char *text; + int text_len; + + NK_ASSERT(str); + NK_ASSERT(unicode); + NK_ASSERT(len); + + if (!str || !unicode || !len) return 0; + if (pos < 0) { + *unicode = 0; + *len = 0; + return 0; + } + + text = (char*)str->buffer.memory.ptr; + text_len = (int)str->buffer.allocated; + glyph_len = nk_utf_decode(text, unicode, text_len); + while (glyph_len) { + if (i == pos) { + *len = glyph_len; + break; + } + + i++; + src_len = src_len + glyph_len; + glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); + } + if (i != pos) return 0; + return text + src_len; +} + +NK_API nk_rune +nk_str_rune_at(const struct nk_str *str, int pos) +{ + int len; + nk_rune unicode = 0; + nk_str_at_const(str, pos, &unicode, &len); + return unicode; +} + +NK_API char* +nk_str_get(struct nk_str *s) +{ + NK_ASSERT(s); + if (!s || !s->len || !s->buffer.allocated) return 0; + return (char*)s->buffer.memory.ptr; +} + +NK_API const char* +nk_str_get_const(const struct nk_str *s) +{ + NK_ASSERT(s); + if (!s || !s->len || !s->buffer.allocated) return 0; + return (const char*)s->buffer.memory.ptr; +} + +NK_API int +nk_str_len(struct nk_str *s) +{ + NK_ASSERT(s); + if (!s || !s->len || !s->buffer.allocated) return 0; + return s->len; +} + +NK_API int +nk_str_len_char(struct nk_str *s) +{ + NK_ASSERT(s); + if (!s || !s->len || !s->buffer.allocated) return 0; + return (int)s->buffer.allocated; +} + +NK_API void +nk_str_clear(struct nk_str *str) +{ + NK_ASSERT(str); + nk_buffer_clear(&str->buffer); + str->len = 0; +} + +NK_API void +nk_str_free(struct nk_str *str) +{ + NK_ASSERT(str); + nk_buffer_free(&str->buffer); + str->len = 0; +} + +/* + * ============================================================== + * + * Command buffer + * + * =============================================================== +*/ +NK_INTERN void +nk_command_buffer_init(struct nk_command_buffer *cmdbuf, + struct nk_buffer *buffer, enum nk_command_clipping clip) +{ + NK_ASSERT(cmdbuf); + NK_ASSERT(buffer); + if (!cmdbuf || !buffer) return; + cmdbuf->base = buffer; + cmdbuf->use_clipping = clip; + cmdbuf->begin = buffer->allocated; + cmdbuf->end = buffer->allocated; + cmdbuf->last = buffer->allocated; +} + +NK_INTERN void +nk_command_buffer_reset(struct nk_command_buffer *buffer) +{ + NK_ASSERT(buffer); + if (!buffer) return; + buffer->begin = 0; + buffer->end = 0; + buffer->last = 0; + buffer->clip = nk_null_rect; +#ifdef NK_INCLUDE_COMMAND_USERDATA + buffer->userdata.ptr = 0; +#endif +} + +NK_INTERN void* +nk_command_buffer_push(struct nk_command_buffer* b, + enum nk_command_type t, nk_size size) +{ + NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_command); + struct nk_command *cmd; + nk_size alignment; + void *unaligned; + void *memory; + + NK_ASSERT(b); + NK_ASSERT(b->base); + if (!b) return 0; + cmd = (struct nk_command*)nk_buffer_alloc(b->base,NK_BUFFER_FRONT,size,align); + if (!cmd) return 0; + + /* make sure the offset to the next command is aligned */ + b->last = (nk_size)((nk_byte*)cmd - (nk_byte*)b->base->memory.ptr); + unaligned = (nk_byte*)cmd + size; + memory = NK_ALIGN_PTR(unaligned, align); + alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned); +#ifdef NK_ZERO_COMMAND_MEMORY + NK_MEMSET(cmd, 0, size + alignment); +#endif + + cmd->type = t; + cmd->next = b->base->allocated + alignment; +#ifdef NK_INCLUDE_COMMAND_USERDATA + cmd->userdata = b->userdata; +#endif + b->end = cmd->next; + return cmd; +} + +NK_API void +nk_push_scissor(struct nk_command_buffer *b, struct nk_rect r) +{ + struct nk_command_scissor *cmd; + NK_ASSERT(b); + if (!b) return; + + b->clip.x = r.x; + b->clip.y = r.y; + b->clip.w = r.w; + b->clip.h = r.h; + cmd = (struct nk_command_scissor*) + nk_command_buffer_push(b, NK_COMMAND_SCISSOR, sizeof(*cmd)); + + if (!cmd) return; + cmd->x = (short)r.x; + cmd->y = (short)r.y; + cmd->w = (unsigned short)NK_MAX(0, r.w); + cmd->h = (unsigned short)NK_MAX(0, r.h); +} + +NK_API void +nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, + float x1, float y1, float line_thickness, struct nk_color c) +{ + struct nk_command_line *cmd; + NK_ASSERT(b); + if (!b || line_thickness <= 0) return; + cmd = (struct nk_command_line*) + nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd)); + if (!cmd) return; + cmd->line_thickness = (unsigned short)line_thickness; + cmd->begin.x = (short)x0; + cmd->begin.y = (short)y0; + cmd->end.x = (short)x1; + cmd->end.y = (short)y1; + cmd->color = c; +} + +NK_API void +nk_stroke_curve(struct nk_command_buffer *b, float ax, float ay, + float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y, + float bx, float by, float line_thickness, struct nk_color col) +{ + struct nk_command_curve *cmd; + NK_ASSERT(b); + if (!b || col.a == 0 || line_thickness <= 0) return; + + cmd = (struct nk_command_curve*) + nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd)); + if (!cmd) return; + cmd->line_thickness = (unsigned short)line_thickness; + cmd->begin.x = (short)ax; + cmd->begin.y = (short)ay; + cmd->ctrl[0].x = (short)ctrl0x; + cmd->ctrl[0].y = (short)ctrl0y; + cmd->ctrl[1].x = (short)ctrl1x; + cmd->ctrl[1].y = (short)ctrl1y; + cmd->end.x = (short)bx; + cmd->end.y = (short)by; + cmd->color = col; +} + +NK_API void +nk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect, + float rounding, float line_thickness, struct nk_color c) +{ + struct nk_command_rect *cmd; + NK_ASSERT(b); + if (!b || c.a == 0 || rect.w == 0 || rect.h == 0 || line_thickness <= 0) return; + if (b->use_clipping) { + const struct nk_rect *clip = &b->clip; + if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, + clip->x, clip->y, clip->w, clip->h)) return; + } + cmd = (struct nk_command_rect*) + nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd)); + if (!cmd) return; + cmd->rounding = (unsigned short)rounding; + cmd->line_thickness = (unsigned short)line_thickness; + cmd->x = (short)rect.x; + cmd->y = (short)rect.y; + cmd->w = (unsigned short)NK_MAX(0, rect.w); + cmd->h = (unsigned short)NK_MAX(0, rect.h); + cmd->color = c; +} + +NK_API void +nk_fill_rect(struct nk_command_buffer *b, struct nk_rect rect, + float rounding, struct nk_color c) +{ + struct nk_command_rect_filled *cmd; + NK_ASSERT(b); + if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return; + if (b->use_clipping) { + const struct nk_rect *clip = &b->clip; + if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, + clip->x, clip->y, clip->w, clip->h)) return; + } + + cmd = (struct nk_command_rect_filled*) + nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, sizeof(*cmd)); + if (!cmd) return; + cmd->rounding = (unsigned short)rounding; + cmd->x = (short)rect.x; + cmd->y = (short)rect.y; + cmd->w = (unsigned short)NK_MAX(0, rect.w); + cmd->h = (unsigned short)NK_MAX(0, rect.h); + cmd->color = c; +} + +NK_API void +nk_fill_rect_multi_color(struct nk_command_buffer *b, struct nk_rect rect, + struct nk_color left, struct nk_color top, struct nk_color right, + struct nk_color bottom) +{ + struct nk_command_rect_multi_color *cmd; + NK_ASSERT(b); + if (!b || rect.w == 0 || rect.h == 0) return; + if (b->use_clipping) { + const struct nk_rect *clip = &b->clip; + if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, + clip->x, clip->y, clip->w, clip->h)) return; + } + + cmd = (struct nk_command_rect_multi_color*) + nk_command_buffer_push(b, NK_COMMAND_RECT_MULTI_COLOR, sizeof(*cmd)); + if (!cmd) return; + cmd->x = (short)rect.x; + cmd->y = (short)rect.y; + cmd->w = (unsigned short)NK_MAX(0, rect.w); + cmd->h = (unsigned short)NK_MAX(0, rect.h); + cmd->left = left; + cmd->top = top; + cmd->right = right; + cmd->bottom = bottom; +} + +NK_API void +nk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r, + float line_thickness, struct nk_color c) +{ + struct nk_command_circle *cmd; + if (!b || r.w == 0 || r.h == 0 || line_thickness <= 0) return; + if (b->use_clipping) { + const struct nk_rect *clip = &b->clip; + if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h)) + return; + } + + cmd = (struct nk_command_circle*) + nk_command_buffer_push(b, NK_COMMAND_CIRCLE, sizeof(*cmd)); + if (!cmd) return; + cmd->line_thickness = (unsigned short)line_thickness; + cmd->x = (short)r.x; + cmd->y = (short)r.y; + cmd->w = (unsigned short)NK_MAX(r.w, 0); + cmd->h = (unsigned short)NK_MAX(r.h, 0); + cmd->color = c; +} + +NK_API void +nk_fill_circle(struct nk_command_buffer *b, struct nk_rect r, struct nk_color c) +{ + struct nk_command_circle_filled *cmd; + NK_ASSERT(b); + if (!b || c.a == 0 || r.w == 0 || r.h == 0) return; + if (b->use_clipping) { + const struct nk_rect *clip = &b->clip; + if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h)) + return; + } + + cmd = (struct nk_command_circle_filled*) + nk_command_buffer_push(b, NK_COMMAND_CIRCLE_FILLED, sizeof(*cmd)); + if (!cmd) return; + cmd->x = (short)r.x; + cmd->y = (short)r.y; + cmd->w = (unsigned short)NK_MAX(r.w, 0); + cmd->h = (unsigned short)NK_MAX(r.h, 0); + cmd->color = c; +} + +NK_API void +nk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius, + float a_min, float a_max, float line_thickness, struct nk_color c) +{ + struct nk_command_arc *cmd; + if (!b || c.a == 0 || line_thickness <= 0) return; + cmd = (struct nk_command_arc*) + nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd)); + if (!cmd) return; + cmd->line_thickness = (unsigned short)line_thickness; + cmd->cx = (short)cx; + cmd->cy = (short)cy; + cmd->r = (unsigned short)radius; + cmd->a[0] = a_min; + cmd->a[1] = a_max; + cmd->color = c; +} + +NK_API void +nk_fill_arc(struct nk_command_buffer *b, float cx, float cy, float radius, + float a_min, float a_max, struct nk_color c) +{ + struct nk_command_arc_filled *cmd; + NK_ASSERT(b); + if (!b || c.a == 0) return; + cmd = (struct nk_command_arc_filled*) + nk_command_buffer_push(b, NK_COMMAND_ARC_FILLED, sizeof(*cmd)); + if (!cmd) return; + cmd->cx = (short)cx; + cmd->cy = (short)cy; + cmd->r = (unsigned short)radius; + cmd->a[0] = a_min; + cmd->a[1] = a_max; + cmd->color = c; +} + +NK_API void +nk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1, + float y1, float x2, float y2, float line_thickness, struct nk_color c) +{ + struct nk_command_triangle *cmd; + NK_ASSERT(b); + if (!b || c.a == 0 || line_thickness <= 0) return; + if (b->use_clipping) { + const struct nk_rect *clip = &b->clip; + if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) && + !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) && + !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h)) + return; + } + + cmd = (struct nk_command_triangle*) + nk_command_buffer_push(b, NK_COMMAND_TRIANGLE, sizeof(*cmd)); + if (!cmd) return; + cmd->line_thickness = (unsigned short)line_thickness; + cmd->a.x = (short)x0; + cmd->a.y = (short)y0; + cmd->b.x = (short)x1; + cmd->b.y = (short)y1; + cmd->c.x = (short)x2; + cmd->c.y = (short)y2; + cmd->color = c; +} + +NK_API void +nk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1, + float y1, float x2, float y2, struct nk_color c) +{ + struct nk_command_triangle_filled *cmd; + NK_ASSERT(b); + if (!b || c.a == 0) return; + if (!b) return; + if (b->use_clipping) { + const struct nk_rect *clip = &b->clip; + if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) && + !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) && + !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h)) + return; + } + + cmd = (struct nk_command_triangle_filled*) + nk_command_buffer_push(b, NK_COMMAND_TRIANGLE_FILLED, sizeof(*cmd)); + if (!cmd) return; + cmd->a.x = (short)x0; + cmd->a.y = (short)y0; + cmd->b.x = (short)x1; + cmd->b.y = (short)y1; + cmd->c.x = (short)x2; + cmd->c.y = (short)y2; + cmd->color = c; +} + +NK_API void +nk_stroke_polygon(struct nk_command_buffer *b, float *points, int point_count, + float line_thickness, struct nk_color col) +{ + int i; + nk_size size = 0; + struct nk_command_polygon *cmd; + + NK_ASSERT(b); + if (!b || col.a == 0 || line_thickness <= 0) return; + size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; + cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size); + if (!cmd) return; + cmd->color = col; + cmd->line_thickness = (unsigned short)line_thickness; + cmd->point_count = (unsigned short)point_count; + for (i = 0; i < point_count; ++i) { + cmd->points[i].x = (short)points[i*2]; + cmd->points[i].y = (short)points[i*2+1]; + } +} + +NK_API void +nk_fill_polygon(struct nk_command_buffer *b, float *points, int point_count, + struct nk_color col) +{ + int i; + nk_size size = 0; + struct nk_command_polygon_filled *cmd; + + NK_ASSERT(b); + if (!b || col.a == 0) return; + size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; + cmd = (struct nk_command_polygon_filled*) + nk_command_buffer_push(b, NK_COMMAND_POLYGON_FILLED, size); + if (!cmd) return; + cmd->color = col; + cmd->point_count = (unsigned short)point_count; + for (i = 0; i < point_count; ++i) { + cmd->points[i].x = (short)points[i*2+0]; + cmd->points[i].y = (short)points[i*2+1]; + } +} + +NK_API void +nk_stroke_polyline(struct nk_command_buffer *b, float *points, int point_count, + float line_thickness, struct nk_color col) +{ + int i; + nk_size size = 0; + struct nk_command_polyline *cmd; + + NK_ASSERT(b); + if (!b || col.a == 0 || line_thickness <= 0) return; + size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; + cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size); + if (!cmd) return; + cmd->color = col; + cmd->point_count = (unsigned short)point_count; + cmd->line_thickness = (unsigned short)line_thickness; + for (i = 0; i < point_count; ++i) { + cmd->points[i].x = (short)points[i*2]; + cmd->points[i].y = (short)points[i*2+1]; + } +} + +NK_API void +nk_draw_image(struct nk_command_buffer *b, struct nk_rect r, + const struct nk_image *img, struct nk_color col) +{ + struct nk_command_image *cmd; + NK_ASSERT(b); + if (!b) return; + if (b->use_clipping) { + const struct nk_rect *c = &b->clip; + if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) + return; + } + + cmd = (struct nk_command_image*) + nk_command_buffer_push(b, NK_COMMAND_IMAGE, sizeof(*cmd)); + if (!cmd) return; + cmd->x = (short)r.x; + cmd->y = (short)r.y; + cmd->w = (unsigned short)NK_MAX(0, r.w); + cmd->h = (unsigned short)NK_MAX(0, r.h); + cmd->img = *img; + cmd->col = col; +} + +NK_API void +nk_push_custom(struct nk_command_buffer *b, struct nk_rect r, + nk_command_custom_callback cb, nk_handle usr) +{ + struct nk_command_custom *cmd; + NK_ASSERT(b); + if (!b) return; + if (b->use_clipping) { + const struct nk_rect *c = &b->clip; + if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) + return; + } + + cmd = (struct nk_command_custom*) + nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd)); + if (!cmd) return; + cmd->x = (short)r.x; + cmd->y = (short)r.y; + cmd->w = (unsigned short)NK_MAX(0, r.w); + cmd->h = (unsigned short)NK_MAX(0, r.h); + cmd->callback_data = usr; + cmd->callback = cb; +} + +NK_API void +nk_draw_text(struct nk_command_buffer *b, struct nk_rect r, + const char *string, int length, const struct nk_user_font *font, + struct nk_color bg, struct nk_color fg) +{ + float text_width = 0; + struct nk_command_text *cmd; + + NK_ASSERT(b); + NK_ASSERT(font); + if (!b || !string || !length || (bg.a == 0 && fg.a == 0)) return; + if (b->use_clipping) { + const struct nk_rect *c = &b->clip; + if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) + return; + } + + /* make sure text fits inside bounds */ + text_width = font->width(font->userdata, font->height, string, length); + if (text_width > r.w){ + int glyphs = 0; + float txt_width = (float)text_width; + length = nk_text_clamp(font, string, length, r.w, &glyphs, &txt_width, 0,0); + } + + if (!length) return; + cmd = (struct nk_command_text*) + nk_command_buffer_push(b, NK_COMMAND_TEXT, sizeof(*cmd) + (nk_size)(length + 1)); + if (!cmd) return; + cmd->x = (short)r.x; + cmd->y = (short)r.y; + cmd->w = (unsigned short)r.w; + cmd->h = (unsigned short)r.h; + cmd->background = bg; + cmd->foreground = fg; + cmd->font = font; + cmd->length = length; + cmd->height = font->height; + NK_MEMCPY(cmd->string, string, (nk_size)length); + cmd->string[length] = '\0'; +} + +/* ============================================================== + * + * DRAW LIST + * + * ===============================================================*/ +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT +NK_API void +nk_draw_list_init(struct nk_draw_list *list) +{ + nk_size i = 0; + NK_ASSERT(list); + if (!list) return; + nk_zero(list, sizeof(*list)); + for (i = 0; i < NK_LEN(list->circle_vtx); ++i) { + const float a = ((float)i / (float)NK_LEN(list->circle_vtx)) * 2 * NK_PI; + list->circle_vtx[i].x = (float)NK_COS(a); + list->circle_vtx[i].y = (float)NK_SIN(a); + } +} + +NK_API void +nk_draw_list_setup(struct nk_draw_list *canvas, const struct nk_convert_config *config, + struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, + enum nk_anti_aliasing line_aa, enum nk_anti_aliasing shape_aa) +{ + NK_ASSERT(canvas); + NK_ASSERT(config); + NK_ASSERT(cmds); + NK_ASSERT(vertices); + NK_ASSERT(elements); + if (!canvas || !config || !cmds || !vertices || !elements) + return; + + canvas->buffer = cmds; + canvas->config = *config; + canvas->elements = elements; + canvas->vertices = vertices; + canvas->line_AA = line_aa; + canvas->shape_AA = shape_aa; + canvas->clip_rect = nk_null_rect; +} + +NK_API const struct nk_draw_command* +nk__draw_list_begin(const struct nk_draw_list *canvas, const struct nk_buffer *buffer) +{ + nk_byte *memory; + nk_size offset; + const struct nk_draw_command *cmd; + + NK_ASSERT(buffer); + if (!buffer || !buffer->size || !canvas->cmd_count) + return 0; + + memory = (nk_byte*)buffer->memory.ptr; + offset = buffer->memory.size - canvas->cmd_offset; + cmd = nk_ptr_add(const struct nk_draw_command, memory, offset); + return cmd; +} + +NK_API const struct nk_draw_command* +nk__draw_list_end(const struct nk_draw_list *canvas, const struct nk_buffer *buffer) +{ + nk_size size; + nk_size offset; + nk_byte *memory; + const struct nk_draw_command *end; + + NK_ASSERT(buffer); + NK_ASSERT(canvas); + if (!buffer || !canvas) + return 0; + + memory = (nk_byte*)buffer->memory.ptr; + size = buffer->memory.size; + offset = size - canvas->cmd_offset; + end = nk_ptr_add(const struct nk_draw_command, memory, offset); + end -= (canvas->cmd_count-1); + return end; +} + +NK_API const struct nk_draw_command* +nk__draw_list_next(const struct nk_draw_command *cmd, + const struct nk_buffer *buffer, const struct nk_draw_list *canvas) +{ + const struct nk_draw_command *end; + NK_ASSERT(buffer); + NK_ASSERT(canvas); + if (!cmd || !buffer || !canvas) + return 0; + + end = nk__draw_list_end(canvas, buffer); + if (cmd <= end) return 0; + return (cmd-1); +} + +NK_API void +nk_draw_list_clear(struct nk_draw_list *list) +{ + NK_ASSERT(list); + if (!list) return; + if (list->buffer) + nk_buffer_clear(list->buffer); + if (list->vertices) + nk_buffer_clear(list->vertices); + if (list->elements) + nk_buffer_clear(list->elements); + + list->element_count = 0; + list->vertex_count = 0; + list->cmd_offset = 0; + list->cmd_count = 0; + list->path_count = 0; + list->vertices = 0; + list->elements = 0; + list->clip_rect = nk_null_rect; +} + +NK_INTERN struct nk_vec2* +nk_draw_list_alloc_path(struct nk_draw_list *list, int count) +{ + struct nk_vec2 *points; + NK_STORAGE const nk_size point_align = NK_ALIGNOF(struct nk_vec2); + NK_STORAGE const nk_size point_size = sizeof(struct nk_vec2); + points = (struct nk_vec2*) + nk_buffer_alloc(list->buffer, NK_BUFFER_FRONT, + point_size * (nk_size)count, point_align); + + if (!points) return 0; + if (!list->path_offset) { + void *memory = nk_buffer_memory(list->buffer); + list->path_offset = (unsigned int)((nk_byte*)points - (nk_byte*)memory); + } + list->path_count += (unsigned int)count; + return points; +} + +NK_INTERN struct nk_vec2 +nk_draw_list_path_last(struct nk_draw_list *list) +{ + void *memory; + struct nk_vec2 *point; + NK_ASSERT(list->path_count); + memory = nk_buffer_memory(list->buffer); + point = nk_ptr_add(struct nk_vec2, memory, list->path_offset); + point += (list->path_count-1); + return *point; +} + +NK_INTERN struct nk_draw_command* +nk_draw_list_push_command(struct nk_draw_list *list, struct nk_rect clip, + nk_handle texture) +{ + NK_STORAGE const nk_size cmd_align = NK_ALIGNOF(struct nk_draw_command); + NK_STORAGE const nk_size cmd_size = sizeof(struct nk_draw_command); + struct nk_draw_command *cmd; + + NK_ASSERT(list); + cmd = (struct nk_draw_command*) + nk_buffer_alloc(list->buffer, NK_BUFFER_BACK, cmd_size, cmd_align); + + if (!cmd) return 0; + if (!list->cmd_count) { + nk_byte *memory = (nk_byte*)nk_buffer_memory(list->buffer); + nk_size total = nk_buffer_total(list->buffer); + memory = nk_ptr_add(nk_byte, memory, total); + list->cmd_offset = (nk_size)(memory - (nk_byte*)cmd); + } + + cmd->elem_count = 0; + cmd->clip_rect = clip; + cmd->texture = texture; +#ifdef NK_INCLUDE_COMMAND_USERDATA + cmd->userdata = list->userdata; +#endif + + list->cmd_count++; + list->clip_rect = clip; + return cmd; +} + +NK_INTERN struct nk_draw_command* +nk_draw_list_command_last(struct nk_draw_list *list) +{ + void *memory; + nk_size size; + struct nk_draw_command *cmd; + NK_ASSERT(list->cmd_count); + + memory = nk_buffer_memory(list->buffer); + size = nk_buffer_total(list->buffer); + cmd = nk_ptr_add(struct nk_draw_command, memory, size - list->cmd_offset); + return (cmd - (list->cmd_count-1)); +} + +NK_INTERN void +nk_draw_list_add_clip(struct nk_draw_list *list, struct nk_rect rect) +{ + NK_ASSERT(list); + if (!list) return; + if (!list->cmd_count) { + nk_draw_list_push_command(list, rect, list->config.null.texture); + } else { + struct nk_draw_command *prev = nk_draw_list_command_last(list); + if (prev->elem_count == 0) + prev->clip_rect = rect; + nk_draw_list_push_command(list, rect, prev->texture); + } +} + +NK_INTERN void +nk_draw_list_push_image(struct nk_draw_list *list, nk_handle texture) +{ + NK_ASSERT(list); + if (!list) return; + if (!list->cmd_count) { + nk_draw_list_push_command(list, nk_null_rect, texture); + } else { + struct nk_draw_command *prev = nk_draw_list_command_last(list); + if (prev->elem_count == 0) + prev->texture = texture; + else if (prev->texture.id != texture.id) + nk_draw_list_push_command(list, prev->clip_rect, texture); + } +} + +#ifdef NK_INCLUDE_COMMAND_USERDATA +NK_API void +nk_draw_list_push_userdata(struct nk_draw_list *list, nk_handle userdata) +{ + list->userdata = userdata; +} +#endif + +NK_INTERN void* +nk_draw_list_alloc_vertices(struct nk_draw_list *list, nk_size count) +{ + void *vtx; + NK_ASSERT(list); + if (!list) return 0; + vtx = nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, + list->config.vertex_size*count, list->config.vertex_alignment); + if (!vtx) return 0; + list->vertex_count += (unsigned int)count; + return vtx; +} + +NK_INTERN nk_draw_index* +nk_draw_list_alloc_elements(struct nk_draw_list *list, nk_size count) +{ + nk_draw_index *ids; + struct nk_draw_command *cmd; + NK_STORAGE const nk_size elem_align = NK_ALIGNOF(nk_draw_index); + NK_STORAGE const nk_size elem_size = sizeof(nk_draw_index); + NK_ASSERT(list); + if (!list) return 0; + + ids = (nk_draw_index*) + nk_buffer_alloc(list->elements, NK_BUFFER_FRONT, elem_size*count, elem_align); + if (!ids) return 0; + cmd = nk_draw_list_command_last(list); + list->element_count += (unsigned int)count; + cmd->elem_count += (unsigned int)count; + return ids; +} + +NK_INTERN int +nk_draw_vertex_layout_element_is_end_of_layout( + const struct nk_draw_vertex_layout_element *element) +{ + return (element->attribute == NK_VERTEX_ATTRIBUTE_COUNT || + element->format == NK_FORMAT_COUNT); +} + +NK_INTERN void +nk_draw_vertex_color(void *attribute, const float *values, + enum nk_draw_vertex_layout_format format) +{ + /* if this triggers you tried to provide a value format for a color */ + NK_ASSERT(format >= NK_FORMAT_COLOR_BEGIN); + NK_ASSERT(format <= NK_FORMAT_COLOR_END); + if (format < NK_FORMAT_COLOR_BEGIN || format > NK_FORMAT_COLOR_END) return; + + switch (format) { + default: NK_ASSERT(0 && "Invalid vertex layout color format"); break; + case NK_FORMAT_R8G8B8A8: + case NK_FORMAT_R8G8B8: { + struct nk_color col = nk_rgba_fv(values); + NK_MEMCPY(attribute, &col.r, sizeof(col)); + } break; + case NK_FORMAT_B8G8R8A8: { + struct nk_color col = nk_rgba_fv(values); + struct nk_color bgra = nk_rgba(col.b, col.g, col.r, col.a); + NK_MEMCPY(attribute, &bgra, sizeof(bgra)); + } break; + case NK_FORMAT_R16G15B16: { + nk_ushort col[3]; + col[0] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[0] * NK_USHORT_MAX, NK_USHORT_MAX); + col[1] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[1] * NK_USHORT_MAX, NK_USHORT_MAX); + col[2] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[2] * NK_USHORT_MAX, NK_USHORT_MAX); + NK_MEMCPY(attribute, col, sizeof(col)); + } break; + case NK_FORMAT_R16G15B16A16: { + nk_ushort col[4]; + col[0] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[0] * NK_USHORT_MAX, NK_USHORT_MAX); + col[1] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[1] * NK_USHORT_MAX, NK_USHORT_MAX); + col[2] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[2] * NK_USHORT_MAX, NK_USHORT_MAX); + col[3] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[3] * NK_USHORT_MAX, NK_USHORT_MAX); + NK_MEMCPY(attribute, col, sizeof(col)); + } break; + case NK_FORMAT_R32G32B32: { + nk_uint col[3]; + col[0] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[0] * NK_UINT_MAX, NK_UINT_MAX); + col[1] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[1] * NK_UINT_MAX, NK_UINT_MAX); + col[2] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[2] * NK_UINT_MAX, NK_UINT_MAX); + NK_MEMCPY(attribute, col, sizeof(col)); + } break; + case NK_FORMAT_R32G32B32A32: { + nk_uint col[4]; + col[0] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[0] * NK_UINT_MAX, NK_UINT_MAX); + col[1] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[1] * NK_UINT_MAX, NK_UINT_MAX); + col[2] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[2] * NK_UINT_MAX, NK_UINT_MAX); + col[3] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[3] * NK_UINT_MAX, NK_UINT_MAX); + NK_MEMCPY(attribute, col, sizeof(col)); + } break; + case NK_FORMAT_R32G32B32A32_FLOAT: + NK_MEMCPY(attribute, values, sizeof(float)*4); + break; + case NK_FORMAT_R32G32B32A32_DOUBLE: { + double col[4]; + col[0] = (double)NK_SATURATE(values[0]); + col[1] = (double)NK_SATURATE(values[1]); + col[2] = (double)NK_SATURATE(values[2]); + col[3] = (double)NK_SATURATE(values[3]); + NK_MEMCPY(attribute, col, sizeof(col)); + } break; + case NK_FORMAT_RGB32: + case NK_FORMAT_RGBA32: { + struct nk_color col = nk_rgba_fv(values); + nk_uint color = nk_color_u32(col); + NK_MEMCPY(attribute, &color, sizeof(color)); + } break; + } +} + +NK_INTERN void +nk_draw_vertex_element(void *dst, const float *values, int value_count, + enum nk_draw_vertex_layout_format format) +{ + int value_index; + void *attribute = dst; + /* if this triggers you tried to provide a color format for a value */ + NK_ASSERT(format < NK_FORMAT_COLOR_BEGIN); + if (format >= NK_FORMAT_COLOR_BEGIN && format <= NK_FORMAT_COLOR_END) return; + for (value_index = 0; value_index < value_count; ++value_index) { + switch (format) { + default: NK_ASSERT(0 && "invalid vertex layout format"); break; + case NK_FORMAT_SCHAR: { + char value = (char)NK_CLAMP(NK_SCHAR_MIN, values[value_index], NK_SCHAR_MAX); + NK_MEMCPY(attribute, &value, sizeof(value)); + attribute = (void*)((char*)attribute + sizeof(char)); + } break; + case NK_FORMAT_SSHORT: { + nk_short value = (nk_short)NK_CLAMP(NK_SSHORT_MIN, values[value_index], NK_SSHORT_MAX); + NK_MEMCPY(attribute, &value, sizeof(value)); + attribute = (void*)((char*)attribute + sizeof(value)); + } break; + case NK_FORMAT_SINT: { + nk_int value = (nk_int)NK_CLAMP(NK_SINT_MIN, values[value_index], NK_SINT_MAX); + NK_MEMCPY(attribute, &value, sizeof(value)); + attribute = (void*)((char*)attribute + sizeof(nk_int)); + } break; + case NK_FORMAT_UCHAR: { + unsigned char value = (unsigned char)NK_CLAMP(NK_UCHAR_MIN, values[value_index], NK_UCHAR_MAX); + NK_MEMCPY(attribute, &value, sizeof(value)); + attribute = (void*)((char*)attribute + sizeof(unsigned char)); + } break; + case NK_FORMAT_USHORT: { + nk_ushort value = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[value_index], NK_USHORT_MAX); + NK_MEMCPY(attribute, &value, sizeof(value)); + attribute = (void*)((char*)attribute + sizeof(value)); + } break; + case NK_FORMAT_UINT: { + nk_uint value = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[value_index], NK_UINT_MAX); + NK_MEMCPY(attribute, &value, sizeof(value)); + attribute = (void*)((char*)attribute + sizeof(nk_uint)); + } break; + case NK_FORMAT_FLOAT: + NK_MEMCPY(attribute, &values[value_index], sizeof(values[value_index])); + attribute = (void*)((char*)attribute + sizeof(float)); + break; + case NK_FORMAT_DOUBLE: { + double value = (double)values[value_index]; + NK_MEMCPY(attribute, &value, sizeof(value)); + attribute = (void*)((char*)attribute + sizeof(double)); + } break; + } + } +} + +NK_INTERN void* +nk_draw_vertex(void *dst, const struct nk_convert_config *config, + struct nk_vec2 pos, struct nk_vec2 uv, struct nk_colorf color) +{ + void *result = (void*)((char*)dst + config->vertex_size); + const struct nk_draw_vertex_layout_element *elem_iter = config->vertex_layout; + while (!nk_draw_vertex_layout_element_is_end_of_layout(elem_iter)) { + void *address = (void*)((char*)dst + elem_iter->offset); + switch (elem_iter->attribute) { + case NK_VERTEX_ATTRIBUTE_COUNT: + default: NK_ASSERT(0 && "wrong element attribute"); + case NK_VERTEX_POSITION: nk_draw_vertex_element(address, &pos.x, 2, elem_iter->format); break; + case NK_VERTEX_TEXCOORD: nk_draw_vertex_element(address, &uv.x, 2, elem_iter->format); break; + case NK_VERTEX_COLOR: nk_draw_vertex_color(address, &color.r, elem_iter->format); break; + } + elem_iter++; + } + return result; +} + +NK_API void +nk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *points, + const unsigned int points_count, struct nk_color color, enum nk_draw_list_stroke closed, + float thickness, enum nk_anti_aliasing aliasing) +{ + nk_size count; + int thick_line; + struct nk_colorf col; + struct nk_colorf col_trans; + NK_ASSERT(list); + if (!list || points_count < 2) return; + + color.a = (nk_byte)((float)color.a * list->config.global_alpha); + count = points_count; + if (!closed) count = points_count-1; + thick_line = thickness > 1.0f; + +#ifdef NK_INCLUDE_COMMAND_USERDATA + nk_draw_list_push_userdata(list, list->userdata); +#endif + + color.a = (nk_byte)((float)color.a * list->config.global_alpha); + nk_color_fv(&col.r, color); + col_trans = col; + col_trans.a = 0; + + if (aliasing == NK_ANTI_ALIASING_ON) { + /* ANTI-ALIASED STROKE */ + const float AA_SIZE = 1.0f; + NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2); + NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2); + + /* allocate vertices and elements */ + nk_size i1 = 0; + nk_size vertex_offset; + nk_size index = list->vertex_count; + + const nk_size idx_count = (thick_line) ? (count * 18) : (count * 12); + const nk_size vtx_count = (thick_line) ? (points_count * 4): (points_count *3); + + void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); + nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); + + nk_size size; + struct nk_vec2 *normals, *temp; + if (!vtx || !ids) return; + + /* temporary allocate normals + points */ + vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr); + nk_buffer_mark(list->vertices, NK_BUFFER_FRONT); + size = pnt_size * ((thick_line) ? 5 : 3) * points_count; + normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align); + NK_ASSERT(normals); + if (!normals) return; + temp = normals + points_count; + + /* make sure vertex pointer is still correct */ + vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset); + + /* calculate normals */ + for (i1 = 0; i1 < count; ++i1) { + const nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1); + struct nk_vec2 diff = nk_vec2_sub(points[i2], points[i1]); + float len; + + /* vec2 inverted length */ + len = nk_vec2_len_sqr(diff); + if (len != 0.0f) + len = nk_inv_sqrt(len); + else len = 1.0f; + + diff = nk_vec2_muls(diff, len); + normals[i1].x = diff.y; + normals[i1].y = -diff.x; + } + + if (!closed) + normals[points_count-1] = normals[points_count-2]; + + if (!thick_line) { + nk_size idx1, i; + if (!closed) { + struct nk_vec2 d; + temp[0] = nk_vec2_add(points[0], nk_vec2_muls(normals[0], AA_SIZE)); + temp[1] = nk_vec2_sub(points[0], nk_vec2_muls(normals[0], AA_SIZE)); + d = nk_vec2_muls(normals[points_count-1], AA_SIZE); + temp[(points_count-1) * 2 + 0] = nk_vec2_add(points[points_count-1], d); + temp[(points_count-1) * 2 + 1] = nk_vec2_sub(points[points_count-1], d); + } + + /* fill elements */ + idx1 = index; + for (i1 = 0; i1 < count; i1++) { + struct nk_vec2 dm; + float dmr2; + nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1); + nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 3); + + /* average normals */ + dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f); + dmr2 = dm.x * dm.x + dm.y* dm.y; + if (dmr2 > 0.000001f) { + float scale = 1.0f/dmr2; + scale = NK_MIN(100.0f, scale); + dm = nk_vec2_muls(dm, scale); + } + + dm = nk_vec2_muls(dm, AA_SIZE); + temp[i2*2+0] = nk_vec2_add(points[i2], dm); + temp[i2*2+1] = nk_vec2_sub(points[i2], dm); + + ids[0] = (nk_draw_index)(idx2 + 0); ids[1] = (nk_draw_index)(idx1+0); + ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2); + ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+0); + ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1); + ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0); + ids[10]= (nk_draw_index)(idx2 + 0); ids[11]= (nk_draw_index)(idx2+1); + ids += 12; + idx1 = idx2; + } + + /* fill vertices */ + for (i = 0; i < points_count; ++i) { + const struct nk_vec2 uv = list->config.null.uv; + vtx = nk_draw_vertex(vtx, &list->config, points[i], uv, col); + vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+0], uv, col_trans); + vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+1], uv, col_trans); + } + } else { + nk_size idx1, i; + const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; + if (!closed) { + struct nk_vec2 d1 = nk_vec2_muls(normals[0], half_inner_thickness + AA_SIZE); + struct nk_vec2 d2 = nk_vec2_muls(normals[0], half_inner_thickness); + + temp[0] = nk_vec2_add(points[0], d1); + temp[1] = nk_vec2_add(points[0], d2); + temp[2] = nk_vec2_sub(points[0], d2); + temp[3] = nk_vec2_sub(points[0], d1); + + d1 = nk_vec2_muls(normals[points_count-1], half_inner_thickness + AA_SIZE); + d2 = nk_vec2_muls(normals[points_count-1], half_inner_thickness); + + temp[(points_count-1)*4+0] = nk_vec2_add(points[points_count-1], d1); + temp[(points_count-1)*4+1] = nk_vec2_add(points[points_count-1], d2); + temp[(points_count-1)*4+2] = nk_vec2_sub(points[points_count-1], d2); + temp[(points_count-1)*4+3] = nk_vec2_sub(points[points_count-1], d1); + } + + /* add all elements */ + idx1 = index; + for (i1 = 0; i1 < count; ++i1) { + struct nk_vec2 dm_out, dm_in; + const nk_size i2 = ((i1+1) == points_count) ? 0: (i1 + 1); + nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 4); + + /* average normals */ + struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f); + float dmr2 = dm.x * dm.x + dm.y* dm.y; + if (dmr2 > 0.000001f) { + float scale = 1.0f/dmr2; + scale = NK_MIN(100.0f, scale); + dm = nk_vec2_muls(dm, scale); + } + + dm_out = nk_vec2_muls(dm, ((half_inner_thickness) + AA_SIZE)); + dm_in = nk_vec2_muls(dm, half_inner_thickness); + temp[i2*4+0] = nk_vec2_add(points[i2], dm_out); + temp[i2*4+1] = nk_vec2_add(points[i2], dm_in); + temp[i2*4+2] = nk_vec2_sub(points[i2], dm_in); + temp[i2*4+3] = nk_vec2_sub(points[i2], dm_out); + + /* add indexes */ + ids[0] = (nk_draw_index)(idx2 + 1); ids[1] = (nk_draw_index)(idx1+1); + ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2); + ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+1); + ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1); + ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0); + ids[10]= (nk_draw_index)(idx2 + 0); ids[11] = (nk_draw_index)(idx2+1); + ids[12]= (nk_draw_index)(idx2 + 2); ids[13] = (nk_draw_index)(idx1+2); + ids[14]= (nk_draw_index)(idx1 + 3); ids[15] = (nk_draw_index)(idx1+3); + ids[16]= (nk_draw_index)(idx2 + 3); ids[17] = (nk_draw_index)(idx2+2); + ids += 18; + idx1 = idx2; + } + + /* add vertices */ + for (i = 0; i < points_count; ++i) { + const struct nk_vec2 uv = list->config.null.uv; + vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+0], uv, col_trans); + vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+1], uv, col); + vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+2], uv, col); + vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+3], uv, col_trans); + } + } + /* free temporary normals + points */ + nk_buffer_reset(list->vertices, NK_BUFFER_FRONT); + } else { + /* NON ANTI-ALIASED STROKE */ + nk_size i1 = 0; + nk_size idx = list->vertex_count; + const nk_size idx_count = count * 6; + const nk_size vtx_count = count * 4; + void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); + nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); + if (!vtx || !ids) return; + + for (i1 = 0; i1 < count; ++i1) { + float dx, dy; + const struct nk_vec2 uv = list->config.null.uv; + const nk_size i2 = ((i1+1) == points_count) ? 0 : i1 + 1; + const struct nk_vec2 p1 = points[i1]; + const struct nk_vec2 p2 = points[i2]; + struct nk_vec2 diff = nk_vec2_sub(p2, p1); + float len; + + /* vec2 inverted length */ + len = nk_vec2_len_sqr(diff); + if (len != 0.0f) + len = nk_inv_sqrt(len); + else len = 1.0f; + diff = nk_vec2_muls(diff, len); + + /* add vertices */ + dx = diff.x * (thickness * 0.5f); + dy = diff.y * (thickness * 0.5f); + + vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x + dy, p1.y - dx), uv, col); + vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x + dy, p2.y - dx), uv, col); + vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x - dy, p2.y + dx), uv, col); + vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x - dy, p1.y + dx), uv, col); + + ids[0] = (nk_draw_index)(idx+0); ids[1] = (nk_draw_index)(idx+1); + ids[2] = (nk_draw_index)(idx+2); ids[3] = (nk_draw_index)(idx+0); + ids[4] = (nk_draw_index)(idx+2); ids[5] = (nk_draw_index)(idx+3); + + ids += 6; + idx += 4; + } + } +} + +NK_API void +nk_draw_list_fill_poly_convex(struct nk_draw_list *list, + const struct nk_vec2 *points, const unsigned int points_count, + struct nk_color color, enum nk_anti_aliasing aliasing) +{ + struct nk_colorf col; + struct nk_colorf col_trans; + + NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2); + NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2); + NK_ASSERT(list); + if (!list || points_count < 3) return; + +#ifdef NK_INCLUDE_COMMAND_USERDATA + nk_draw_list_push_userdata(list, list->userdata); +#endif + + color.a = (nk_byte)((float)color.a * list->config.global_alpha); + nk_color_fv(&col.r, color); + col_trans = col; + col_trans.a = 0; + + if (aliasing == NK_ANTI_ALIASING_ON) { + nk_size i = 0; + nk_size i0 = 0; + nk_size i1 = 0; + + const float AA_SIZE = 1.0f; + nk_size vertex_offset = 0; + nk_size index = list->vertex_count; + + const nk_size idx_count = (points_count-2)*3 + points_count*6; + const nk_size vtx_count = (points_count*2); + + void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); + nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); + + nk_size size = 0; + struct nk_vec2 *normals = 0; + unsigned int vtx_inner_idx = (unsigned int)(index + 0); + unsigned int vtx_outer_idx = (unsigned int)(index + 1); + if (!vtx || !ids) return; + + /* temporary allocate normals */ + vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr); + nk_buffer_mark(list->vertices, NK_BUFFER_FRONT); + size = pnt_size * points_count; + normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align); + NK_ASSERT(normals); + if (!normals) return; + vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset); + + /* add elements */ + for (i = 2; i < points_count; i++) { + ids[0] = (nk_draw_index)(vtx_inner_idx); + ids[1] = (nk_draw_index)(vtx_inner_idx + ((i-1) << 1)); + ids[2] = (nk_draw_index)(vtx_inner_idx + (i << 1)); + ids += 3; + } + + /* compute normals */ + for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) { + struct nk_vec2 p0 = points[i0]; + struct nk_vec2 p1 = points[i1]; + struct nk_vec2 diff = nk_vec2_sub(p1, p0); + + /* vec2 inverted length */ + float len = nk_vec2_len_sqr(diff); + if (len != 0.0f) + len = nk_inv_sqrt(len); + else len = 1.0f; + diff = nk_vec2_muls(diff, len); + + normals[i0].x = diff.y; + normals[i0].y = -diff.x; + } + + /* add vertices + indexes */ + for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) { + const struct nk_vec2 uv = list->config.null.uv; + struct nk_vec2 n0 = normals[i0]; + struct nk_vec2 n1 = normals[i1]; + struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(n0, n1), 0.5f); + float dmr2 = dm.x*dm.x + dm.y*dm.y; + if (dmr2 > 0.000001f) { + float scale = 1.0f / dmr2; + scale = NK_MIN(scale, 100.0f); + dm = nk_vec2_muls(dm, scale); + } + dm = nk_vec2_muls(dm, AA_SIZE * 0.5f); + + /* add vertices */ + vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_sub(points[i1], dm), uv, col); + vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_add(points[i1], dm), uv, col_trans); + + /* add indexes */ + ids[0] = (nk_draw_index)(vtx_inner_idx+(i1<<1)); + ids[1] = (nk_draw_index)(vtx_inner_idx+(i0<<1)); + ids[2] = (nk_draw_index)(vtx_outer_idx+(i0<<1)); + ids[3] = (nk_draw_index)(vtx_outer_idx+(i0<<1)); + ids[4] = (nk_draw_index)(vtx_outer_idx+(i1<<1)); + ids[5] = (nk_draw_index)(vtx_inner_idx+(i1<<1)); + ids += 6; + } + /* free temporary normals + points */ + nk_buffer_reset(list->vertices, NK_BUFFER_FRONT); + } else { + nk_size i = 0; + nk_size index = list->vertex_count; + const nk_size idx_count = (points_count-2)*3; + const nk_size vtx_count = points_count; + void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); + nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); + + if (!vtx || !ids) return; + for (i = 0; i < vtx_count; ++i) + vtx = nk_draw_vertex(vtx, &list->config, points[i], list->config.null.uv, col); + for (i = 2; i < points_count; ++i) { + ids[0] = (nk_draw_index)index; + ids[1] = (nk_draw_index)(index+ i - 1); + ids[2] = (nk_draw_index)(index+i); + ids += 3; + } + } +} + +NK_API void +nk_draw_list_path_clear(struct nk_draw_list *list) +{ + NK_ASSERT(list); + if (!list) return; + nk_buffer_reset(list->buffer, NK_BUFFER_FRONT); + list->path_count = 0; + list->path_offset = 0; +} + +NK_API void +nk_draw_list_path_line_to(struct nk_draw_list *list, struct nk_vec2 pos) +{ + struct nk_vec2 *points = 0; + struct nk_draw_command *cmd = 0; + NK_ASSERT(list); + if (!list) return; + if (!list->cmd_count) + nk_draw_list_add_clip(list, nk_null_rect); + + cmd = nk_draw_list_command_last(list); + if (cmd && cmd->texture.ptr != list->config.null.texture.ptr) + nk_draw_list_push_image(list, list->config.null.texture); + + points = nk_draw_list_alloc_path(list, 1); + if (!points) return; + points[0] = pos; +} + +NK_API void +nk_draw_list_path_arc_to_fast(struct nk_draw_list *list, struct nk_vec2 center, + float radius, int a_min, int a_max) +{ + int a = 0; + NK_ASSERT(list); + if (!list) return; + if (a_min <= a_max) { + for (a = a_min; a <= a_max; a++) { + const struct nk_vec2 c = list->circle_vtx[(nk_size)a % NK_LEN(list->circle_vtx)]; + const float x = center.x + c.x * radius; + const float y = center.y + c.y * radius; + nk_draw_list_path_line_to(list, nk_vec2(x, y)); + } + } +} + +NK_API void +nk_draw_list_path_arc_to(struct nk_draw_list *list, struct nk_vec2 center, + float radius, float a_min, float a_max, unsigned int segments) +{ + unsigned int i = 0; + NK_ASSERT(list); + if (!list) return; + if (radius == 0.0f) return; + for (i = 0; i <= segments; ++i) { + const float a = a_min + ((float)i / ((float)segments) * (a_max - a_min)); + const float x = center.x + (float)NK_COS(a) * radius; + const float y = center.y + (float)NK_SIN(a) * radius; + nk_draw_list_path_line_to(list, nk_vec2(x, y)); + } +} + +NK_API void +nk_draw_list_path_rect_to(struct nk_draw_list *list, struct nk_vec2 a, + struct nk_vec2 b, float rounding) +{ + float r; + NK_ASSERT(list); + if (!list) return; + r = rounding; + r = NK_MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x)); + r = NK_MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y)); + + if (r == 0.0f) { + nk_draw_list_path_line_to(list, a); + nk_draw_list_path_line_to(list, nk_vec2(b.x,a.y)); + nk_draw_list_path_line_to(list, b); + nk_draw_list_path_line_to(list, nk_vec2(a.x,b.y)); + } else { + nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, a.y + r), r, 6, 9); + nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, a.y + r), r, 9, 12); + nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, b.y - r), r, 0, 3); + nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, b.y - r), r, 3, 6); + } +} + +NK_API void +nk_draw_list_path_curve_to(struct nk_draw_list *list, struct nk_vec2 p2, + struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments) +{ + float t_step; + unsigned int i_step; + struct nk_vec2 p1; + + NK_ASSERT(list); + NK_ASSERT(list->path_count); + if (!list || !list->path_count) return; + num_segments = NK_MAX(num_segments, 1); + + p1 = nk_draw_list_path_last(list); + t_step = 1.0f/(float)num_segments; + for (i_step = 1; i_step <= num_segments; ++i_step) { + float t = t_step * (float)i_step; + float u = 1.0f - t; + float w1 = u*u*u; + float w2 = 3*u*u*t; + float w3 = 3*u*t*t; + float w4 = t * t *t; + float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x; + float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y; + nk_draw_list_path_line_to(list, nk_vec2(x,y)); + } +} + +NK_API void +nk_draw_list_path_fill(struct nk_draw_list *list, struct nk_color color) +{ + struct nk_vec2 *points; + NK_ASSERT(list); + if (!list) return; + points = (struct nk_vec2*)nk_buffer_memory(list->buffer); + nk_draw_list_fill_poly_convex(list, points, list->path_count, color, list->config.shape_AA); + nk_draw_list_path_clear(list); +} + +NK_API void +nk_draw_list_path_stroke(struct nk_draw_list *list, struct nk_color color, + enum nk_draw_list_stroke closed, float thickness) +{ + struct nk_vec2 *points; + NK_ASSERT(list); + if (!list) return; + points = (struct nk_vec2*)nk_buffer_memory(list->buffer); + nk_draw_list_stroke_poly_line(list, points, list->path_count, color, + closed, thickness, list->config.line_AA); + nk_draw_list_path_clear(list); +} + +NK_API void +nk_draw_list_stroke_line(struct nk_draw_list *list, struct nk_vec2 a, + struct nk_vec2 b, struct nk_color col, float thickness) +{ + NK_ASSERT(list); + if (!list || !col.a) return; + if (list->line_AA == NK_ANTI_ALIASING_ON) { + nk_draw_list_path_line_to(list, a); + nk_draw_list_path_line_to(list, b); + } else { + nk_draw_list_path_line_to(list, nk_vec2_sub(a,nk_vec2(0.5f,0.5f))); + nk_draw_list_path_line_to(list, nk_vec2_sub(b,nk_vec2(0.5f,0.5f))); + } + nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness); +} + +NK_API void +nk_draw_list_fill_rect(struct nk_draw_list *list, struct nk_rect rect, + struct nk_color col, float rounding) +{ + NK_ASSERT(list); + if (!list || !col.a) return; + + if (list->line_AA == NK_ANTI_ALIASING_ON) { + nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y), + nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); + } else { + nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f), + nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); + } nk_draw_list_path_fill(list, col); +} + +NK_API void +nk_draw_list_stroke_rect(struct nk_draw_list *list, struct nk_rect rect, + struct nk_color col, float rounding, float thickness) +{ + NK_ASSERT(list); + if (!list || !col.a) return; + if (list->line_AA == NK_ANTI_ALIASING_ON) { + nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y), + nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); + } else { + nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f), + nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); + } nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); +} + +NK_API void +nk_draw_list_fill_rect_multi_color(struct nk_draw_list *list, struct nk_rect rect, + struct nk_color left, struct nk_color top, struct nk_color right, + struct nk_color bottom) +{ + void *vtx; + struct nk_colorf col_left, col_top; + struct nk_colorf col_right, col_bottom; + nk_draw_index *idx; + nk_draw_index index; + + nk_color_fv(&col_left.r, left); + nk_color_fv(&col_right.r, right); + nk_color_fv(&col_top.r, top); + nk_color_fv(&col_bottom.r, bottom); + + NK_ASSERT(list); + if (!list) return; + + nk_draw_list_push_image(list, list->config.null.texture); + index = (nk_draw_index)list->vertex_count; + vtx = nk_draw_list_alloc_vertices(list, 4); + idx = nk_draw_list_alloc_elements(list, 6); + if (!vtx || !idx) return; + + idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1); + idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0); + idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3); + + vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y), list->config.null.uv, col_left); + vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y), list->config.null.uv, col_top); + vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y + rect.h), list->config.null.uv, col_right); + vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y + rect.h), list->config.null.uv, col_bottom); +} + +NK_API void +nk_draw_list_fill_triangle(struct nk_draw_list *list, struct nk_vec2 a, + struct nk_vec2 b, struct nk_vec2 c, struct nk_color col) +{ + NK_ASSERT(list); + if (!list || !col.a) return; + nk_draw_list_path_line_to(list, a); + nk_draw_list_path_line_to(list, b); + nk_draw_list_path_line_to(list, c); + nk_draw_list_path_fill(list, col); +} + +NK_API void +nk_draw_list_stroke_triangle(struct nk_draw_list *list, struct nk_vec2 a, + struct nk_vec2 b, struct nk_vec2 c, struct nk_color col, float thickness) +{ + NK_ASSERT(list); + if (!list || !col.a) return; + nk_draw_list_path_line_to(list, a); + nk_draw_list_path_line_to(list, b); + nk_draw_list_path_line_to(list, c); + nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); +} + +NK_API void +nk_draw_list_fill_circle(struct nk_draw_list *list, struct nk_vec2 center, + float radius, struct nk_color col, unsigned int segs) +{ + float a_max; + NK_ASSERT(list); + if (!list || !col.a) return; + a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs; + nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs); + nk_draw_list_path_fill(list, col); +} + +NK_API void +nk_draw_list_stroke_circle(struct nk_draw_list *list, struct nk_vec2 center, + float radius, struct nk_color col, unsigned int segs, float thickness) +{ + float a_max; + NK_ASSERT(list); + if (!list || !col.a) return; + a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs; + nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs); + nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); +} + +NK_API void +nk_draw_list_stroke_curve(struct nk_draw_list *list, struct nk_vec2 p0, + struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, + struct nk_color col, unsigned int segments, float thickness) +{ + NK_ASSERT(list); + if (!list || !col.a) return; + nk_draw_list_path_line_to(list, p0); + nk_draw_list_path_curve_to(list, cp0, cp1, p1, segments); + nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness); +} + +NK_INTERN void +nk_draw_list_push_rect_uv(struct nk_draw_list *list, struct nk_vec2 a, + struct nk_vec2 c, struct nk_vec2 uva, struct nk_vec2 uvc, + struct nk_color color) +{ + void *vtx; + struct nk_vec2 uvb; + struct nk_vec2 uvd; + struct nk_vec2 b; + struct nk_vec2 d; + + struct nk_colorf col; + nk_draw_index *idx; + nk_draw_index index; + NK_ASSERT(list); + if (!list) return; + + nk_color_fv(&col.r, color); + uvb = nk_vec2(uvc.x, uva.y); + uvd = nk_vec2(uva.x, uvc.y); + b = nk_vec2(c.x, a.y); + d = nk_vec2(a.x, c.y); + + index = (nk_draw_index)list->vertex_count; + vtx = nk_draw_list_alloc_vertices(list, 4); + idx = nk_draw_list_alloc_elements(list, 6); + if (!vtx || !idx) return; + + idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1); + idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0); + idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3); + + vtx = nk_draw_vertex(vtx, &list->config, a, uva, col); + vtx = nk_draw_vertex(vtx, &list->config, b, uvb, col); + vtx = nk_draw_vertex(vtx, &list->config, c, uvc, col); + vtx = nk_draw_vertex(vtx, &list->config, d, uvd, col); +} + +NK_API void +nk_draw_list_add_image(struct nk_draw_list *list, struct nk_image texture, + struct nk_rect rect, struct nk_color color) +{ + NK_ASSERT(list); + if (!list) return; + /* push new command with given texture */ + nk_draw_list_push_image(list, texture.handle); + if (nk_image_is_subimage(&texture)) { + /* add region inside of the texture */ + struct nk_vec2 uv[2]; + uv[0].x = (float)texture.region[0]/(float)texture.w; + uv[0].y = (float)texture.region[1]/(float)texture.h; + uv[1].x = (float)(texture.region[0] + texture.region[2])/(float)texture.w; + uv[1].y = (float)(texture.region[1] + texture.region[3])/(float)texture.h; + nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y), + nk_vec2(rect.x + rect.w, rect.y + rect.h), uv[0], uv[1], color); + } else nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y), + nk_vec2(rect.x + rect.w, rect.y + rect.h), + nk_vec2(0.0f, 0.0f), nk_vec2(1.0f, 1.0f),color); +} + +NK_API void +nk_draw_list_add_text(struct nk_draw_list *list, const struct nk_user_font *font, + struct nk_rect rect, const char *text, int len, float font_height, + struct nk_color fg) +{ + float x = 0; + int text_len = 0; + nk_rune unicode = 0; + nk_rune next = 0; + int glyph_len = 0; + int next_glyph_len = 0; + struct nk_user_font_glyph g; + + NK_ASSERT(list); + if (!list || !len || !text) return; + if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, + list->clip_rect.x, list->clip_rect.y, list->clip_rect.w, list->clip_rect.h)) return; + + nk_draw_list_push_image(list, font->texture); + x = rect.x; + glyph_len = nk_utf_decode(text, &unicode, len); + if (!glyph_len) return; + + /* draw every glyph image */ + fg.a = (nk_byte)((float)fg.a * list->config.global_alpha); + while (text_len < len && glyph_len) { + float gx, gy, gh, gw; + float char_width = 0; + if (unicode == NK_UTF_INVALID) break; + + /* query currently drawn glyph information */ + next_glyph_len = nk_utf_decode(text + text_len + glyph_len, &next, (int)len - text_len); + font->query(font->userdata, font_height, &g, unicode, + (next == NK_UTF_INVALID) ? '\0' : next); + + /* calculate and draw glyph drawing rectangle and image */ + gx = x + g.offset.x; + gy = rect.y + g.offset.y; + gw = g.width; gh = g.height; + char_width = g.xadvance; + nk_draw_list_push_rect_uv(list, nk_vec2(gx,gy), nk_vec2(gx + gw, gy+ gh), + g.uv[0], g.uv[1], fg); + + /* offset next glyph */ + text_len += glyph_len; + x += char_width; + glyph_len = next_glyph_len; + unicode = next; + } +} + +NK_API nk_flags +nk_convert(struct nk_context *ctx, struct nk_buffer *cmds, + struct nk_buffer *vertices, struct nk_buffer *elements, + const struct nk_convert_config *config) +{ + nk_flags res = NK_CONVERT_SUCCESS; + const struct nk_command *cmd; + NK_ASSERT(ctx); + NK_ASSERT(cmds); + NK_ASSERT(vertices); + NK_ASSERT(elements); + NK_ASSERT(config); + NK_ASSERT(config->vertex_layout); + NK_ASSERT(config->vertex_size); + if (!ctx || !cmds || !vertices || !elements || !config || !config->vertex_layout) + return NK_CONVERT_INVALID_PARAM; + + nk_draw_list_setup(&ctx->draw_list, config, cmds, vertices, elements, + config->line_AA, config->shape_AA); + nk_foreach(cmd, ctx) + { +#ifdef NK_INCLUDE_COMMAND_USERDATA + ctx->draw_list.userdata = cmd->userdata; +#endif + switch (cmd->type) { + case NK_COMMAND_NOP: break; + case NK_COMMAND_SCISSOR: { + const struct nk_command_scissor *s = (const struct nk_command_scissor*)cmd; + nk_draw_list_add_clip(&ctx->draw_list, nk_rect(s->x, s->y, s->w, s->h)); + } break; + case NK_COMMAND_LINE: { + const struct nk_command_line *l = (const struct nk_command_line*)cmd; + nk_draw_list_stroke_line(&ctx->draw_list, nk_vec2(l->begin.x, l->begin.y), + nk_vec2(l->end.x, l->end.y), l->color, l->line_thickness); + } break; + case NK_COMMAND_CURVE: { + const struct nk_command_curve *q = (const struct nk_command_curve*)cmd; + nk_draw_list_stroke_curve(&ctx->draw_list, nk_vec2(q->begin.x, q->begin.y), + nk_vec2(q->ctrl[0].x, q->ctrl[0].y), nk_vec2(q->ctrl[1].x, + q->ctrl[1].y), nk_vec2(q->end.x, q->end.y), q->color, + config->curve_segment_count, q->line_thickness); + } break; + case NK_COMMAND_RECT: { + const struct nk_command_rect *r = (const struct nk_command_rect*)cmd; + nk_draw_list_stroke_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), + r->color, (float)r->rounding, r->line_thickness); + } break; + case NK_COMMAND_RECT_FILLED: { + const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled*)cmd; + nk_draw_list_fill_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), + r->color, (float)r->rounding); + } break; + case NK_COMMAND_RECT_MULTI_COLOR: { + const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color*)cmd; + nk_draw_list_fill_rect_multi_color(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), + r->left, r->top, r->right, r->bottom); + } break; + case NK_COMMAND_CIRCLE: { + const struct nk_command_circle *c = (const struct nk_command_circle*)cmd; + nk_draw_list_stroke_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2, + (float)c->y + (float)c->h/2), (float)c->w/2, c->color, + config->circle_segment_count, c->line_thickness); + } break; + case NK_COMMAND_CIRCLE_FILLED: { + const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd; + nk_draw_list_fill_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2, + (float)c->y + (float)c->h/2), (float)c->w/2, c->color, + config->circle_segment_count); + } break; + case NK_COMMAND_ARC: { + const struct nk_command_arc *c = (const struct nk_command_arc*)cmd; + nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy)); + nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r, + c->a[0], c->a[1], config->arc_segment_count); + nk_draw_list_path_stroke(&ctx->draw_list, c->color, NK_STROKE_CLOSED, c->line_thickness); + } break; + case NK_COMMAND_ARC_FILLED: { + const struct nk_command_arc_filled *c = (const struct nk_command_arc_filled*)cmd; + nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy)); + nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r, + c->a[0], c->a[1], config->arc_segment_count); + nk_draw_list_path_fill(&ctx->draw_list, c->color); + } break; + case NK_COMMAND_TRIANGLE: { + const struct nk_command_triangle *t = (const struct nk_command_triangle*)cmd; + nk_draw_list_stroke_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y), + nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color, + t->line_thickness); + } break; + case NK_COMMAND_TRIANGLE_FILLED: { + const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled*)cmd; + nk_draw_list_fill_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y), + nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color); + } break; + case NK_COMMAND_POLYGON: { + int i; + const struct nk_command_polygon*p = (const struct nk_command_polygon*)cmd; + for (i = 0; i < p->point_count; ++i) { + struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); + nk_draw_list_path_line_to(&ctx->draw_list, pnt); + } + nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_CLOSED, p->line_thickness); + } break; + case NK_COMMAND_POLYGON_FILLED: { + int i; + const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled*)cmd; + for (i = 0; i < p->point_count; ++i) { + struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); + nk_draw_list_path_line_to(&ctx->draw_list, pnt); + } + nk_draw_list_path_fill(&ctx->draw_list, p->color); + } break; + case NK_COMMAND_POLYLINE: { + int i; + const struct nk_command_polyline *p = (const struct nk_command_polyline*)cmd; + for (i = 0; i < p->point_count; ++i) { + struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); + nk_draw_list_path_line_to(&ctx->draw_list, pnt); + } + nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_OPEN, p->line_thickness); + } break; + case NK_COMMAND_TEXT: { + const struct nk_command_text *t = (const struct nk_command_text*)cmd; + nk_draw_list_add_text(&ctx->draw_list, t->font, nk_rect(t->x, t->y, t->w, t->h), + t->string, t->length, t->height, t->foreground); + } break; + case NK_COMMAND_IMAGE: { + const struct nk_command_image *i = (const struct nk_command_image*)cmd; + nk_draw_list_add_image(&ctx->draw_list, i->img, nk_rect(i->x, i->y, i->w, i->h), i->col); + } break; + case NK_COMMAND_CUSTOM: { + const struct nk_command_custom *c = (const struct nk_command_custom*)cmd; + c->callback(&ctx->draw_list, c->x, c->y, c->w, c->h, c->callback_data); + } break; + default: break; + } + } + res |= (cmds->needed > cmds->allocated + (cmds->memory.size - cmds->size)) ? NK_CONVERT_COMMAND_BUFFER_FULL: 0; + res |= (vertices->needed > vertices->allocated) ? NK_CONVERT_VERTEX_BUFFER_FULL: 0; + res |= (elements->needed > elements->allocated) ? NK_CONVERT_ELEMENT_BUFFER_FULL: 0; + return res; +} +NK_API const struct nk_draw_command* +nk__draw_begin(const struct nk_context *ctx, + const struct nk_buffer *buffer) +{return nk__draw_list_begin(&ctx->draw_list, buffer);} + +NK_API const struct nk_draw_command* +nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buffer) +{return nk__draw_list_end(&ctx->draw_list, buffer);} + +NK_API const struct nk_draw_command* +nk__draw_next(const struct nk_draw_command *cmd, + const struct nk_buffer *buffer, const struct nk_context *ctx) +{return nk__draw_list_next(cmd, buffer, &ctx->draw_list);} + +#endif + +/* + * ============================================================== + * + * FONT HANDLING + * + * =============================================================== + */ +#ifdef NK_INCLUDE_FONT_BAKING +/* ------------------------------------------------------------- + * + * RECT PACK + * + * --------------------------------------------------------------*/ +/* stb_rect_pack.h - v0.05 - public domain - rectangle packing */ +/* Sean Barrett 2014 */ +#define NK_RP__MAXVAL 0xffff +typedef unsigned short nk_rp_coord; + +struct nk_rp_rect { + /* reserved for your use: */ + int id; + /* input: */ + nk_rp_coord w, h; + /* output: */ + nk_rp_coord x, y; + int was_packed; + /* non-zero if valid packing */ +}; /* 16 bytes, nominally */ + +struct nk_rp_node { + nk_rp_coord x,y; + struct nk_rp_node *next; +}; + +struct nk_rp_context { + int width; + int height; + int align; + int init_mode; + int heuristic; + int num_nodes; + struct nk_rp_node *active_head; + struct nk_rp_node *free_head; + struct nk_rp_node extra[2]; + /* we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' */ +}; + +struct nk_rp__findresult { + int x,y; + struct nk_rp_node **prev_link; +}; + +enum NK_RP_HEURISTIC { + NK_RP_HEURISTIC_Skyline_default=0, + NK_RP_HEURISTIC_Skyline_BL_sortHeight = NK_RP_HEURISTIC_Skyline_default, + NK_RP_HEURISTIC_Skyline_BF_sortHeight +}; +enum NK_RP_INIT_STATE{NK_RP__INIT_skyline = 1}; + +NK_INTERN void +nk_rp_setup_allow_out_of_mem(struct nk_rp_context *context, int allow_out_of_mem) +{ + if (allow_out_of_mem) + /* if it's ok to run out of memory, then don't bother aligning them; */ + /* this gives better packing, but may fail due to OOM (even though */ + /* the rectangles easily fit). @TODO a smarter approach would be to only */ + /* quantize once we've hit OOM, then we could get rid of this parameter. */ + context->align = 1; + else { + /* if it's not ok to run out of memory, then quantize the widths */ + /* so that num_nodes is always enough nodes. */ + /* */ + /* I.e. num_nodes * align >= width */ + /* align >= width / num_nodes */ + /* align = ceil(width/num_nodes) */ + context->align = (context->width + context->num_nodes-1) / context->num_nodes; + } +} + +NK_INTERN void +nk_rp_init_target(struct nk_rp_context *context, int width, int height, + struct nk_rp_node *nodes, int num_nodes) +{ + int i; +#ifndef STBRP_LARGE_RECTS + NK_ASSERT(width <= 0xffff && height <= 0xffff); +#endif + + for (i=0; i < num_nodes-1; ++i) + nodes[i].next = &nodes[i+1]; + nodes[i].next = 0; + context->init_mode = NK_RP__INIT_skyline; + context->heuristic = NK_RP_HEURISTIC_Skyline_default; + context->free_head = &nodes[0]; + context->active_head = &context->extra[0]; + context->width = width; + context->height = height; + context->num_nodes = num_nodes; + nk_rp_setup_allow_out_of_mem(context, 0); + + /* node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) */ + context->extra[0].x = 0; + context->extra[0].y = 0; + context->extra[0].next = &context->extra[1]; + context->extra[1].x = (nk_rp_coord) width; + context->extra[1].y = 65535; + context->extra[1].next = 0; +} + +/* find minimum y position if it starts at x1 */ +NK_INTERN int +nk_rp__skyline_find_min_y(struct nk_rp_context *c, struct nk_rp_node *first, + int x0, int width, int *pwaste) +{ + struct nk_rp_node *node = first; + int x1 = x0 + width; + int min_y, visited_width, waste_area; + NK_ASSERT(first->x <= x0); + NK_UNUSED(c); + + NK_ASSERT(node->next->x > x0); + /* we ended up handling this in the caller for efficiency */ + NK_ASSERT(node->x <= x0); + + min_y = 0; + waste_area = 0; + visited_width = 0; + while (node->x < x1) + { + if (node->y > min_y) { + /* raise min_y higher. */ + /* we've accounted for all waste up to min_y, */ + /* but we'll now add more waste for everything we've visited */ + waste_area += visited_width * (node->y - min_y); + min_y = node->y; + /* the first time through, visited_width might be reduced */ + if (node->x < x0) + visited_width += node->next->x - x0; + else + visited_width += node->next->x - node->x; + } else { + /* add waste area */ + int under_width = node->next->x - node->x; + if (under_width + visited_width > width) + under_width = width - visited_width; + waste_area += under_width * (min_y - node->y); + visited_width += under_width; + } + node = node->next; + } + *pwaste = waste_area; + return min_y; +} + +NK_INTERN struct nk_rp__findresult +nk_rp__skyline_find_best_pos(struct nk_rp_context *c, int width, int height) +{ + int best_waste = (1<<30), best_x, best_y = (1 << 30); + struct nk_rp__findresult fr; + struct nk_rp_node **prev, *node, *tail, **best = 0; + + /* align to multiple of c->align */ + width = (width + c->align - 1); + width -= width % c->align; + NK_ASSERT(width % c->align == 0); + + node = c->active_head; + prev = &c->active_head; + while (node->x + width <= c->width) { + int y,waste; + y = nk_rp__skyline_find_min_y(c, node, node->x, width, &waste); + /* actually just want to test BL */ + if (c->heuristic == NK_RP_HEURISTIC_Skyline_BL_sortHeight) { + /* bottom left */ + if (y < best_y) { + best_y = y; + best = prev; + } + } else { + /* best-fit */ + if (y + height <= c->height) { + /* can only use it if it first vertically */ + if (y < best_y || (y == best_y && waste < best_waste)) { + best_y = y; + best_waste = waste; + best = prev; + } + } + } + prev = &node->next; + node = node->next; + } + best_x = (best == 0) ? 0 : (*best)->x; + + /* if doing best-fit (BF), we also have to try aligning right edge to each node position */ + /* */ + /* e.g, if fitting */ + /* */ + /* ____________________ */ + /* |____________________| */ + /* */ + /* into */ + /* */ + /* | | */ + /* | ____________| */ + /* |____________| */ + /* */ + /* then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned */ + /* */ + /* This makes BF take about 2x the time */ + if (c->heuristic == NK_RP_HEURISTIC_Skyline_BF_sortHeight) + { + tail = c->active_head; + node = c->active_head; + prev = &c->active_head; + /* find first node that's admissible */ + while (tail->x < width) + tail = tail->next; + while (tail) + { + int xpos = tail->x - width; + int y,waste; + NK_ASSERT(xpos >= 0); + /* find the left position that matches this */ + while (node->next->x <= xpos) { + prev = &node->next; + node = node->next; + } + NK_ASSERT(node->next->x > xpos && node->x <= xpos); + y = nk_rp__skyline_find_min_y(c, node, xpos, width, &waste); + if (y + height < c->height) { + if (y <= best_y) { + if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { + best_x = xpos; + NK_ASSERT(y <= best_y); + best_y = y; + best_waste = waste; + best = prev; + } + } + } + tail = tail->next; + } + } + fr.prev_link = best; + fr.x = best_x; + fr.y = best_y; + return fr; +} + +NK_INTERN struct nk_rp__findresult +nk_rp__skyline_pack_rectangle(struct nk_rp_context *context, int width, int height) +{ + /* find best position according to heuristic */ + struct nk_rp__findresult res = nk_rp__skyline_find_best_pos(context, width, height); + struct nk_rp_node *node, *cur; + + /* bail if: */ + /* 1. it failed */ + /* 2. the best node doesn't fit (we don't always check this) */ + /* 3. we're out of memory */ + if (res.prev_link == 0 || res.y + height > context->height || context->free_head == 0) { + res.prev_link = 0; + return res; + } + + /* on success, create new node */ + node = context->free_head; + node->x = (nk_rp_coord) res.x; + node->y = (nk_rp_coord) (res.y + height); + + context->free_head = node->next; + + /* insert the new node into the right starting point, and */ + /* let 'cur' point to the remaining nodes needing to be */ + /* stitched back in */ + cur = *res.prev_link; + if (cur->x < res.x) { + /* preserve the existing one, so start testing with the next one */ + struct nk_rp_node *next = cur->next; + cur->next = node; + cur = next; + } else { + *res.prev_link = node; + } + + /* from here, traverse cur and free the nodes, until we get to one */ + /* that shouldn't be freed */ + while (cur->next && cur->next->x <= res.x + width) { + struct nk_rp_node *next = cur->next; + /* move the current node to the free list */ + cur->next = context->free_head; + context->free_head = cur; + cur = next; + } + /* stitch the list back in */ + node->next = cur; + + if (cur->x < res.x + width) + cur->x = (nk_rp_coord) (res.x + width); + return res; +} + +NK_INTERN int +nk_rect_height_compare(const void *a, const void *b) +{ + const struct nk_rp_rect *p = (const struct nk_rp_rect *) a; + const struct nk_rp_rect *q = (const struct nk_rp_rect *) b; + if (p->h > q->h) + return -1; + if (p->h < q->h) + return 1; + return (p->w > q->w) ? -1 : (p->w < q->w); +} + +NK_INTERN int +nk_rect_original_order(const void *a, const void *b) +{ + const struct nk_rp_rect *p = (const struct nk_rp_rect *) a; + const struct nk_rp_rect *q = (const struct nk_rp_rect *) b; + return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); +} + +NK_INTERN void +nk_rp_qsort(struct nk_rp_rect *array, unsigned int len, int(*cmp)(const void*,const void*)) +{ + /* iterative quick sort */ + #define NK_MAX_SORT_STACK 64 + unsigned right, left = 0, stack[NK_MAX_SORT_STACK], pos = 0; + unsigned seed = len/2 * 69069+1; + for (;;) { + for (; left+1 < len; len++) { + struct nk_rp_rect pivot, tmp; + if (pos == NK_MAX_SORT_STACK) len = stack[pos = 0]; + pivot = array[left+seed%(len-left)]; + seed = seed * 69069 + 1; + stack[pos++] = len; + for (right = left-1;;) { + while (cmp(&array[++right], &pivot) < 0); + while (cmp(&pivot, &array[--len]) < 0); + if (right >= len) break; + tmp = array[right]; + array[right] = array[len]; + array[len] = tmp; + } + } + if (pos == 0) break; + left = len; + len = stack[--pos]; + } + #undef NK_MAX_SORT_STACK +} + +NK_INTERN void +nk_rp_pack_rects(struct nk_rp_context *context, struct nk_rp_rect *rects, int num_rects) +{ + int i; + /* we use the 'was_packed' field internally to allow sorting/unsorting */ + for (i=0; i < num_rects; ++i) { + rects[i].was_packed = i; + } + + /* sort according to heuristic */ + nk_rp_qsort(rects, (unsigned)num_rects, nk_rect_height_compare); + + for (i=0; i < num_rects; ++i) { + struct nk_rp__findresult fr = nk_rp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); + if (fr.prev_link) { + rects[i].x = (nk_rp_coord) fr.x; + rects[i].y = (nk_rp_coord) fr.y; + } else { + rects[i].x = rects[i].y = NK_RP__MAXVAL; + } + } + + /* unsort */ + nk_rp_qsort(rects, (unsigned)num_rects, nk_rect_original_order); + + /* set was_packed flags */ + for (i=0; i < num_rects; ++i) + rects[i].was_packed = !(rects[i].x == NK_RP__MAXVAL && rects[i].y == NK_RP__MAXVAL); +} + +/* + * ============================================================== + * + * TRUETYPE + * + * =============================================================== + */ +/* stb_truetype.h - v1.07 - public domain */ +#define NK_TT_MAX_OVERSAMPLE 8 +#define NK_TT__OVER_MASK (NK_TT_MAX_OVERSAMPLE-1) + +struct nk_tt_bakedchar { + unsigned short x0,y0,x1,y1; + /* coordinates of bbox in bitmap */ + float xoff,yoff,xadvance; +}; + +struct nk_tt_aligned_quad{ + float x0,y0,s0,t0; /* top-left */ + float x1,y1,s1,t1; /* bottom-right */ +}; + +struct nk_tt_packedchar { + unsigned short x0,y0,x1,y1; + /* coordinates of bbox in bitmap */ + float xoff,yoff,xadvance; + float xoff2,yoff2; +}; + +struct nk_tt_pack_range { + float font_size; + int first_unicode_codepoint_in_range; + /* if non-zero, then the chars are continuous, and this is the first codepoint */ + int *array_of_unicode_codepoints; + /* if non-zero, then this is an array of unicode codepoints */ + int num_chars; + struct nk_tt_packedchar *chardata_for_range; /* output */ + unsigned char h_oversample, v_oversample; + /* don't set these, they're used internally */ +}; + +struct nk_tt_pack_context { + void *pack_info; + int width; + int height; + int stride_in_bytes; + int padding; + unsigned int h_oversample, v_oversample; + unsigned char *pixels; + void *nodes; +}; + +struct nk_tt_fontinfo { + const unsigned char* data; /* pointer to .ttf file */ + int fontstart;/* offset of start of font */ + int numGlyphs;/* number of glyphs, needed for range checking */ + int loca,head,glyf,hhea,hmtx,kern; /* table locations as offset from start of .ttf */ + int index_map; /* a cmap mapping for our chosen character encoding */ + int indexToLocFormat; /* format needed to map from glyph index to glyph */ +}; + +enum { + NK_TT_vmove=1, + NK_TT_vline, + NK_TT_vcurve +}; + +struct nk_tt_vertex { + short x,y,cx,cy; + unsigned char type,padding; +}; + +struct nk_tt__bitmap{ + int w,h,stride; + unsigned char *pixels; +}; + +struct nk_tt__hheap_chunk { + struct nk_tt__hheap_chunk *next; +}; +struct nk_tt__hheap { + struct nk_allocator alloc; + struct nk_tt__hheap_chunk *head; + void *first_free; + int num_remaining_in_head_chunk; +}; + +struct nk_tt__edge { + float x0,y0, x1,y1; + int invert; +}; + +struct nk_tt__active_edge { + struct nk_tt__active_edge *next; + float fx,fdx,fdy; + float direction; + float sy; + float ey; +}; +struct nk_tt__point {float x,y;}; + +#define NK_TT_MACSTYLE_DONTCARE 0 +#define NK_TT_MACSTYLE_BOLD 1 +#define NK_TT_MACSTYLE_ITALIC 2 +#define NK_TT_MACSTYLE_UNDERSCORE 4 +#define NK_TT_MACSTYLE_NONE 8 +/* <= not same as 0, this makes us check the bitfield is 0 */ + +enum { /* platformID */ + NK_TT_PLATFORM_ID_UNICODE =0, + NK_TT_PLATFORM_ID_MAC =1, + NK_TT_PLATFORM_ID_ISO =2, + NK_TT_PLATFORM_ID_MICROSOFT =3 +}; + +enum { /* encodingID for NK_TT_PLATFORM_ID_UNICODE */ + NK_TT_UNICODE_EID_UNICODE_1_0 =0, + NK_TT_UNICODE_EID_UNICODE_1_1 =1, + NK_TT_UNICODE_EID_ISO_10646 =2, + NK_TT_UNICODE_EID_UNICODE_2_0_BMP=3, + NK_TT_UNICODE_EID_UNICODE_2_0_FULL=4 +}; + +enum { /* encodingID for NK_TT_PLATFORM_ID_MICROSOFT */ + NK_TT_MS_EID_SYMBOL =0, + NK_TT_MS_EID_UNICODE_BMP =1, + NK_TT_MS_EID_SHIFTJIS =2, + NK_TT_MS_EID_UNICODE_FULL =10 +}; + +enum { /* encodingID for NK_TT_PLATFORM_ID_MAC; same as Script Manager codes */ + NK_TT_MAC_EID_ROMAN =0, NK_TT_MAC_EID_ARABIC =4, + NK_TT_MAC_EID_JAPANESE =1, NK_TT_MAC_EID_HEBREW =5, + NK_TT_MAC_EID_CHINESE_TRAD =2, NK_TT_MAC_EID_GREEK =6, + NK_TT_MAC_EID_KOREAN =3, NK_TT_MAC_EID_RUSSIAN =7 +}; + +enum { /* languageID for NK_TT_PLATFORM_ID_MICROSOFT; same as LCID... */ + /* problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs */ + NK_TT_MS_LANG_ENGLISH =0x0409, NK_TT_MS_LANG_ITALIAN =0x0410, + NK_TT_MS_LANG_CHINESE =0x0804, NK_TT_MS_LANG_JAPANESE =0x0411, + NK_TT_MS_LANG_DUTCH =0x0413, NK_TT_MS_LANG_KOREAN =0x0412, + NK_TT_MS_LANG_FRENCH =0x040c, NK_TT_MS_LANG_RUSSIAN =0x0419, + NK_TT_MS_LANG_GERMAN =0x0407, NK_TT_MS_LANG_SPANISH =0x0409, + NK_TT_MS_LANG_HEBREW =0x040d, NK_TT_MS_LANG_SWEDISH =0x041D +}; + +enum { /* languageID for NK_TT_PLATFORM_ID_MAC */ + NK_TT_MAC_LANG_ENGLISH =0 , NK_TT_MAC_LANG_JAPANESE =11, + NK_TT_MAC_LANG_ARABIC =12, NK_TT_MAC_LANG_KOREAN =23, + NK_TT_MAC_LANG_DUTCH =4 , NK_TT_MAC_LANG_RUSSIAN =32, + NK_TT_MAC_LANG_FRENCH =1 , NK_TT_MAC_LANG_SPANISH =6 , + NK_TT_MAC_LANG_GERMAN =2 , NK_TT_MAC_LANG_SWEDISH =5 , + NK_TT_MAC_LANG_HEBREW =10, NK_TT_MAC_LANG_CHINESE_SIMPLIFIED =33, + NK_TT_MAC_LANG_ITALIAN =3 , NK_TT_MAC_LANG_CHINESE_TRAD =19 +}; + +#define nk_ttBYTE(p) (* (const nk_byte *) (p)) +#define nk_ttCHAR(p) (* (const char *) (p)) + +#if defined(NK_BIGENDIAN) && !defined(NK_ALLOW_UNALIGNED_TRUETYPE) + #define nk_ttUSHORT(p) (* (nk_ushort *) (p)) + #define nk_ttSHORT(p) (* (nk_short *) (p)) + #define nk_ttULONG(p) (* (nk_uint *) (p)) + #define nk_ttLONG(p) (* (nk_int *) (p)) +#else + static nk_ushort nk_ttUSHORT(const nk_byte *p) { return (nk_ushort)(p[0]*256 + p[1]); } + static nk_short nk_ttSHORT(const nk_byte *p) { return (nk_short)(p[0]*256 + p[1]); } + static nk_uint nk_ttULONG(const nk_byte *p) { return (nk_uint)((p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]); } +#endif + +#define nk_tt_tag4(p,c0,c1,c2,c3)\ + ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) +#define nk_tt_tag(p,str) nk_tt_tag4(p,str[0],str[1],str[2],str[3]) + +NK_INTERN int nk_tt_GetGlyphShape(const struct nk_tt_fontinfo *info, struct nk_allocator *alloc, + int glyph_index, struct nk_tt_vertex **pvertices); + +NK_INTERN nk_uint +nk_tt__find_table(const nk_byte *data, nk_uint fontstart, const char *tag) +{ + /* @OPTIMIZE: binary search */ + nk_int num_tables = nk_ttUSHORT(data+fontstart+4); + nk_uint tabledir = fontstart + 12; + nk_int i; + for (i = 0; i < num_tables; ++i) { + nk_uint loc = tabledir + (nk_uint)(16*i); + if (nk_tt_tag(data+loc+0, tag)) + return nk_ttULONG(data+loc+8); + } + return 0; +} + +NK_INTERN int +nk_tt_InitFont(struct nk_tt_fontinfo *info, const unsigned char *data2, int fontstart) +{ + nk_uint cmap, t; + nk_int i,numTables; + const nk_byte *data = (const nk_byte *) data2; + + info->data = data; + info->fontstart = fontstart; + + cmap = nk_tt__find_table(data, (nk_uint)fontstart, "cmap"); /* required */ + info->loca = (int)nk_tt__find_table(data, (nk_uint)fontstart, "loca"); /* required */ + info->head = (int)nk_tt__find_table(data, (nk_uint)fontstart, "head"); /* required */ + info->glyf = (int)nk_tt__find_table(data, (nk_uint)fontstart, "glyf"); /* required */ + info->hhea = (int)nk_tt__find_table(data, (nk_uint)fontstart, "hhea"); /* required */ + info->hmtx = (int)nk_tt__find_table(data, (nk_uint)fontstart, "hmtx"); /* required */ + info->kern = (int)nk_tt__find_table(data, (nk_uint)fontstart, "kern"); /* not required */ + if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx) + return 0; + + t = nk_tt__find_table(data, (nk_uint)fontstart, "maxp"); + if (t) info->numGlyphs = nk_ttUSHORT(data+t+4); + else info->numGlyphs = 0xffff; + + /* find a cmap encoding table we understand *now* to avoid searching */ + /* later. (todo: could make this installable) */ + /* the same regardless of glyph. */ + numTables = nk_ttUSHORT(data + cmap + 2); + info->index_map = 0; + for (i=0; i < numTables; ++i) + { + nk_uint encoding_record = cmap + 4 + 8 * (nk_uint)i; + /* find an encoding we understand: */ + switch(nk_ttUSHORT(data+encoding_record)) { + case NK_TT_PLATFORM_ID_MICROSOFT: + switch (nk_ttUSHORT(data+encoding_record+2)) { + case NK_TT_MS_EID_UNICODE_BMP: + case NK_TT_MS_EID_UNICODE_FULL: + /* MS/Unicode */ + info->index_map = (int)(cmap + nk_ttULONG(data+encoding_record+4)); + break; + default: break; + } break; + case NK_TT_PLATFORM_ID_UNICODE: + /* Mac/iOS has these */ + /* all the encodingIDs are unicode, so we don't bother to check it */ + info->index_map = (int)(cmap + nk_ttULONG(data+encoding_record+4)); + break; + default: break; + } + } + if (info->index_map == 0) + return 0; + info->indexToLocFormat = nk_ttUSHORT(data+info->head + 50); + return 1; +} + +NK_INTERN int +nk_tt_FindGlyphIndex(const struct nk_tt_fontinfo *info, int unicode_codepoint) +{ + const nk_byte *data = info->data; + nk_uint index_map = (nk_uint)info->index_map; + + nk_ushort format = nk_ttUSHORT(data + index_map + 0); + if (format == 0) { /* apple byte encoding */ + nk_int bytes = nk_ttUSHORT(data + index_map + 2); + if (unicode_codepoint < bytes-6) + return nk_ttBYTE(data + index_map + 6 + unicode_codepoint); + return 0; + } else if (format == 6) { + nk_uint first = nk_ttUSHORT(data + index_map + 6); + nk_uint count = nk_ttUSHORT(data + index_map + 8); + if ((nk_uint) unicode_codepoint >= first && (nk_uint) unicode_codepoint < first+count) + return nk_ttUSHORT(data + index_map + 10 + (unicode_codepoint - (int)first)*2); + return 0; + } else if (format == 2) { + NK_ASSERT(0); /* @TODO: high-byte mapping for japanese/chinese/korean */ + return 0; + } else if (format == 4) { /* standard mapping for windows fonts: binary search collection of ranges */ + nk_ushort segcount = nk_ttUSHORT(data+index_map+6) >> 1; + nk_ushort searchRange = nk_ttUSHORT(data+index_map+8) >> 1; + nk_ushort entrySelector = nk_ttUSHORT(data+index_map+10); + nk_ushort rangeShift = nk_ttUSHORT(data+index_map+12) >> 1; + + /* do a binary search of the segments */ + nk_uint endCount = index_map + 14; + nk_uint search = endCount; + + if (unicode_codepoint > 0xffff) + return 0; + + /* they lie from endCount .. endCount + segCount */ + /* but searchRange is the nearest power of two, so... */ + if (unicode_codepoint >= nk_ttUSHORT(data + search + rangeShift*2)) + search += (nk_uint)(rangeShift*2); + + /* now decrement to bias correctly to find smallest */ + search -= 2; + while (entrySelector) { + nk_ushort end; + searchRange >>= 1; + end = nk_ttUSHORT(data + search + searchRange*2); + if (unicode_codepoint > end) + search += (nk_uint)(searchRange*2); + --entrySelector; + } + search += 2; + + { + nk_ushort offset, start; + nk_ushort item = (nk_ushort) ((search - endCount) >> 1); + + NK_ASSERT(unicode_codepoint <= nk_ttUSHORT(data + endCount + 2*item)); + start = nk_ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); + if (unicode_codepoint < start) + return 0; + + offset = nk_ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); + if (offset == 0) + return (nk_ushort) (unicode_codepoint + nk_ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); + + return nk_ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); + } + } else if (format == 12 || format == 13) { + nk_uint ngroups = nk_ttULONG(data+index_map+12); + nk_int low,high; + low = 0; high = (nk_int)ngroups; + /* Binary search the right group. */ + while (low < high) { + nk_int mid = low + ((high-low) >> 1); /* rounds down, so low <= mid < high */ + nk_uint start_char = nk_ttULONG(data+index_map+16+mid*12); + nk_uint end_char = nk_ttULONG(data+index_map+16+mid*12+4); + if ((nk_uint) unicode_codepoint < start_char) + high = mid; + else if ((nk_uint) unicode_codepoint > end_char) + low = mid+1; + else { + nk_uint start_glyph = nk_ttULONG(data+index_map+16+mid*12+8); + if (format == 12) + return (int)start_glyph + (int)unicode_codepoint - (int)start_char; + else /* format == 13 */ + return (int)start_glyph; + } + } + return 0; /* not found */ + } + /* @TODO */ + NK_ASSERT(0); + return 0; +} + +NK_INTERN void +nk_tt_setvertex(struct nk_tt_vertex *v, nk_byte type, nk_int x, nk_int y, nk_int cx, nk_int cy) +{ + v->type = type; + v->x = (nk_short) x; + v->y = (nk_short) y; + v->cx = (nk_short) cx; + v->cy = (nk_short) cy; +} + +NK_INTERN int +nk_tt__GetGlyfOffset(const struct nk_tt_fontinfo *info, int glyph_index) +{ + int g1,g2; + if (glyph_index >= info->numGlyphs) return -1; /* glyph index out of range */ + if (info->indexToLocFormat >= 2) return -1; /* unknown index->glyph map format */ + + if (info->indexToLocFormat == 0) { + g1 = info->glyf + nk_ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; + g2 = info->glyf + nk_ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; + } else { + g1 = info->glyf + (int)nk_ttULONG (info->data + info->loca + glyph_index * 4); + g2 = info->glyf + (int)nk_ttULONG (info->data + info->loca + glyph_index * 4 + 4); + } + return g1==g2 ? -1 : g1; /* if length is 0, return -1 */ +} + +NK_INTERN int +nk_tt_GetGlyphBox(const struct nk_tt_fontinfo *info, int glyph_index, + int *x0, int *y0, int *x1, int *y1) +{ + int g = nk_tt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 0; + + if (x0) *x0 = nk_ttSHORT(info->data + g + 2); + if (y0) *y0 = nk_ttSHORT(info->data + g + 4); + if (x1) *x1 = nk_ttSHORT(info->data + g + 6); + if (y1) *y1 = nk_ttSHORT(info->data + g + 8); + return 1; +} + +NK_INTERN int +stbtt__close_shape(struct nk_tt_vertex *vertices, int num_vertices, int was_off, + int start_off, nk_int sx, nk_int sy, nk_int scx, nk_int scy, nk_int cx, nk_int cy) +{ + if (start_off) { + if (was_off) + nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); + nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, sx,sy,scx,scy); + } else { + if (was_off) + nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve,sx,sy,cx,cy); + else + nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vline,sx,sy,0,0); + } + return num_vertices; +} + +NK_INTERN int +nk_tt_GetGlyphShape(const struct nk_tt_fontinfo *info, struct nk_allocator *alloc, + int glyph_index, struct nk_tt_vertex **pvertices) +{ + nk_short numberOfContours; + const nk_byte *endPtsOfContours; + const nk_byte *data = info->data; + struct nk_tt_vertex *vertices=0; + int num_vertices=0; + int g = nk_tt__GetGlyfOffset(info, glyph_index); + *pvertices = 0; + + if (g < 0) return 0; + numberOfContours = nk_ttSHORT(data + g); + if (numberOfContours > 0) { + nk_byte flags=0,flagcount; + nk_int ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; + nk_int x,y,cx,cy,sx,sy, scx,scy; + const nk_byte *points; + endPtsOfContours = (data + g + 10); + ins = nk_ttUSHORT(data + g + 10 + numberOfContours * 2); + points = data + g + 10 + numberOfContours * 2 + 2 + ins; + + n = 1+nk_ttUSHORT(endPtsOfContours + numberOfContours*2-2); + m = n + 2*numberOfContours; /* a loose bound on how many vertices we might need */ + vertices = (struct nk_tt_vertex *)alloc->alloc(alloc->userdata, 0, (nk_size)m * sizeof(vertices[0])); + if (vertices == 0) + return 0; + + next_move = 0; + flagcount=0; + + /* in first pass, we load uninterpreted data into the allocated array */ + /* above, shifted to the end of the array so we won't overwrite it when */ + /* we create our final data starting from the front */ + off = m - n; /* starting offset for uninterpreted data, regardless of how m ends up being calculated */ + + /* first load flags */ + for (i=0; i < n; ++i) { + if (flagcount == 0) { + flags = *points++; + if (flags & 8) + flagcount = *points++; + } else --flagcount; + vertices[off+i].type = flags; + } + + /* now load x coordinates */ + x=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 2) { + nk_short dx = *points++; + x += (flags & 16) ? dx : -dx; /* ??? */ + } else { + if (!(flags & 16)) { + x = x + (nk_short) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].x = (nk_short) x; + } + + /* now load y coordinates */ + y=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 4) { + nk_short dy = *points++; + y += (flags & 32) ? dy : -dy; /* ??? */ + } else { + if (!(flags & 32)) { + y = y + (nk_short) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].y = (nk_short) y; + } + + /* now convert them to our format */ + num_vertices=0; + sx = sy = cx = cy = scx = scy = 0; + for (i=0; i < n; ++i) + { + flags = vertices[off+i].type; + x = (nk_short) vertices[off+i].x; + y = (nk_short) vertices[off+i].y; + + if (next_move == i) { + if (i != 0) + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + + /* now start the new one */ + start_off = !(flags & 1); + if (start_off) { + /* if we start off with an off-curve point, then when we need to find a point on the curve */ + /* where we can start, and we need to save some state for when we wraparound. */ + scx = x; + scy = y; + if (!(vertices[off+i+1].type & 1)) { + /* next point is also a curve point, so interpolate an on-point curve */ + sx = (x + (nk_int) vertices[off+i+1].x) >> 1; + sy = (y + (nk_int) vertices[off+i+1].y) >> 1; + } else { + /* otherwise just use the next point as our start point */ + sx = (nk_int) vertices[off+i+1].x; + sy = (nk_int) vertices[off+i+1].y; + ++i; /* we're using point i+1 as the starting point, so skip it */ + } + } else { + sx = x; + sy = y; + } + nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vmove,sx,sy,0,0); + was_off = 0; + next_move = 1 + nk_ttUSHORT(endPtsOfContours+j*2); + ++j; + } else { + if (!(flags & 1)) + { /* if it's a curve */ + if (was_off) /* two off-curve control points in a row means interpolate an on-curve midpoint */ + nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); + cx = x; + cy = y; + was_off = 1; + } else { + if (was_off) + nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, x,y, cx, cy); + else nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vline, x,y,0,0); + was_off = 0; + } + } + } + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + } else if (numberOfContours == -1) { + /* Compound shapes. */ + int more = 1; + const nk_byte *comp = data + g + 10; + num_vertices = 0; + vertices = 0; + + while (more) + { + nk_ushort flags, gidx; + int comp_num_verts = 0, i; + struct nk_tt_vertex *comp_verts = 0, *tmp = 0; + float mtx[6] = {1,0,0,1,0,0}, m, n; + + flags = (nk_ushort)nk_ttSHORT(comp); comp+=2; + gidx = (nk_ushort)nk_ttSHORT(comp); comp+=2; + + if (flags & 2) { /* XY values */ + if (flags & 1) { /* shorts */ + mtx[4] = nk_ttSHORT(comp); comp+=2; + mtx[5] = nk_ttSHORT(comp); comp+=2; + } else { + mtx[4] = nk_ttCHAR(comp); comp+=1; + mtx[5] = nk_ttCHAR(comp); comp+=1; + } + } else { + /* @TODO handle matching point */ + NK_ASSERT(0); + } + if (flags & (1<<3)) { /* WE_HAVE_A_SCALE */ + mtx[0] = mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + } else if (flags & (1<<6)) { /* WE_HAVE_AN_X_AND_YSCALE */ + mtx[0] = nk_ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2; + } else if (flags & (1<<7)) { /* WE_HAVE_A_TWO_BY_TWO */ + mtx[0] = nk_ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = nk_ttSHORT(comp)/16384.0f; comp+=2; + mtx[2] = nk_ttSHORT(comp)/16384.0f; comp+=2; + mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2; + } + + /* Find transformation scales. */ + m = (float) NK_SQRT(mtx[0]*mtx[0] + mtx[1]*mtx[1]); + n = (float) NK_SQRT(mtx[2]*mtx[2] + mtx[3]*mtx[3]); + + /* Get indexed glyph. */ + comp_num_verts = nk_tt_GetGlyphShape(info, alloc, gidx, &comp_verts); + if (comp_num_verts > 0) + { + /* Transform vertices. */ + for (i = 0; i < comp_num_verts; ++i) { + struct nk_tt_vertex* v = &comp_verts[i]; + short x,y; + x=v->x; y=v->y; + v->x = (short)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->y = (short)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + x=v->cx; y=v->cy; + v->cx = (short)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->cy = (short)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + } + /* Append vertices. */ + tmp = (struct nk_tt_vertex*)alloc->alloc(alloc->userdata, 0, + (nk_size)(num_vertices+comp_num_verts)*sizeof(struct nk_tt_vertex)); + if (!tmp) { + if (vertices) alloc->free(alloc->userdata, vertices); + if (comp_verts) alloc->free(alloc->userdata, comp_verts); + return 0; + } + if (num_vertices > 0) NK_MEMCPY(tmp, vertices, (nk_size)num_vertices*sizeof(struct nk_tt_vertex)); + NK_MEMCPY(tmp+num_vertices, comp_verts, (nk_size)comp_num_verts*sizeof(struct nk_tt_vertex)); + if (vertices) alloc->free(alloc->userdata,vertices); + vertices = tmp; + alloc->free(alloc->userdata,comp_verts); + num_vertices += comp_num_verts; + } + /* More components ? */ + more = flags & (1<<5); + } + } else if (numberOfContours < 0) { + /* @TODO other compound variations? */ + NK_ASSERT(0); + } else { + /* numberOfCounters == 0, do nothing */ + } + *pvertices = vertices; + return num_vertices; +} + +NK_INTERN void +nk_tt_GetGlyphHMetrics(const struct nk_tt_fontinfo *info, int glyph_index, + int *advanceWidth, int *leftSideBearing) +{ + nk_ushort numOfLongHorMetrics = nk_ttUSHORT(info->data+info->hhea + 34); + if (glyph_index < numOfLongHorMetrics) { + if (advanceWidth) + *advanceWidth = nk_ttSHORT(info->data + info->hmtx + 4*glyph_index); + if (leftSideBearing) + *leftSideBearing = nk_ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); + } else { + if (advanceWidth) + *advanceWidth = nk_ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); + if (leftSideBearing) + *leftSideBearing = nk_ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); + } +} + +NK_INTERN void +nk_tt_GetFontVMetrics(const struct nk_tt_fontinfo *info, + int *ascent, int *descent, int *lineGap) +{ + if (ascent ) *ascent = nk_ttSHORT(info->data+info->hhea + 4); + if (descent) *descent = nk_ttSHORT(info->data+info->hhea + 6); + if (lineGap) *lineGap = nk_ttSHORT(info->data+info->hhea + 8); +} + +NK_INTERN float +nk_tt_ScaleForPixelHeight(const struct nk_tt_fontinfo *info, float height) +{ + int fheight = nk_ttSHORT(info->data + info->hhea + 4) - nk_ttSHORT(info->data + info->hhea + 6); + return (float) height / (float)fheight; +} + +NK_INTERN float +nk_tt_ScaleForMappingEmToPixels(const struct nk_tt_fontinfo *info, float pixels) +{ + int unitsPerEm = nk_ttUSHORT(info->data + info->head + 18); + return pixels / (float)unitsPerEm; +} + +/*------------------------------------------------------------- + * antialiasing software rasterizer + * --------------------------------------------------------------*/ +NK_INTERN void +nk_tt_GetGlyphBitmapBoxSubpixel(const struct nk_tt_fontinfo *font, + int glyph, float scale_x, float scale_y,float shift_x, float shift_y, + int *ix0, int *iy0, int *ix1, int *iy1) +{ + int x0,y0,x1,y1; + if (!nk_tt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { + /* e.g. space character */ + if (ix0) *ix0 = 0; + if (iy0) *iy0 = 0; + if (ix1) *ix1 = 0; + if (iy1) *iy1 = 0; + } else { + /* move to integral bboxes (treating pixels as little squares, what pixels get touched)? */ + if (ix0) *ix0 = nk_ifloorf((float)x0 * scale_x + shift_x); + if (iy0) *iy0 = nk_ifloorf((float)-y1 * scale_y + shift_y); + if (ix1) *ix1 = nk_iceilf ((float)x1 * scale_x + shift_x); + if (iy1) *iy1 = nk_iceilf ((float)-y0 * scale_y + shift_y); + } +} + +NK_INTERN void +nk_tt_GetGlyphBitmapBox(const struct nk_tt_fontinfo *font, int glyph, + float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + nk_tt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); +} + +/*------------------------------------------------------------- + * Rasterizer + * --------------------------------------------------------------*/ +NK_INTERN void* +nk_tt__hheap_alloc(struct nk_tt__hheap *hh, nk_size size) +{ + if (hh->first_free) { + void *p = hh->first_free; + hh->first_free = * (void **) p; + return p; + } else { + if (hh->num_remaining_in_head_chunk == 0) { + int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); + struct nk_tt__hheap_chunk *c = (struct nk_tt__hheap_chunk *) + hh->alloc.alloc(hh->alloc.userdata, 0, + sizeof(struct nk_tt__hheap_chunk) + size * (nk_size)count); + if (c == 0) return 0; + c->next = hh->head; + hh->head = c; + hh->num_remaining_in_head_chunk = count; + } + --hh->num_remaining_in_head_chunk; + return (char *) (hh->head) + size * (nk_size)hh->num_remaining_in_head_chunk; + } +} + +NK_INTERN void +nk_tt__hheap_free(struct nk_tt__hheap *hh, void *p) +{ + *(void **) p = hh->first_free; + hh->first_free = p; +} + +NK_INTERN void +nk_tt__hheap_cleanup(struct nk_tt__hheap *hh) +{ + struct nk_tt__hheap_chunk *c = hh->head; + while (c) { + struct nk_tt__hheap_chunk *n = c->next; + hh->alloc.free(hh->alloc.userdata, c); + c = n; + } +} + +NK_INTERN struct nk_tt__active_edge* +nk_tt__new_active(struct nk_tt__hheap *hh, struct nk_tt__edge *e, + int off_x, float start_point) +{ + struct nk_tt__active_edge *z = (struct nk_tt__active_edge *) + nk_tt__hheap_alloc(hh, sizeof(*z)); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + /*STBTT_assert(e->y0 <= start_point); */ + if (!z) return z; + z->fdx = dxdy; + z->fdy = (dxdy != 0) ? (1/dxdy): 0; + z->fx = e->x0 + dxdy * (start_point - e->y0); + z->fx -= (float)off_x; + z->direction = e->invert ? 1.0f : -1.0f; + z->sy = e->y0; + z->ey = e->y1; + z->next = 0; + return z; +} + +NK_INTERN void +nk_tt__handle_clipped_edge(float *scanline, int x, struct nk_tt__active_edge *e, + float x0, float y0, float x1, float y1) +{ + if (y0 == y1) return; + NK_ASSERT(y0 < y1); + NK_ASSERT(e->sy <= e->ey); + if (y0 > e->ey) return; + if (y1 < e->sy) return; + if (y0 < e->sy) { + x0 += (x1-x0) * (e->sy - y0) / (y1-y0); + y0 = e->sy; + } + if (y1 > e->ey) { + x1 += (x1-x0) * (e->ey - y1) / (y1-y0); + y1 = e->ey; + } + + if (x0 == x) NK_ASSERT(x1 <= x+1); + else if (x0 == x+1) NK_ASSERT(x1 >= x); + else if (x0 <= x) NK_ASSERT(x1 <= x); + else if (x0 >= x+1) NK_ASSERT(x1 >= x+1); + else NK_ASSERT(x1 >= x && x1 <= x+1); + + if (x0 <= x && x1 <= x) + scanline[x] += e->direction * (y1-y0); + else if (x0 >= x+1 && x1 >= x+1); + else { + NK_ASSERT(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); + /* coverage = 1 - average x position */ + scanline[x] += (float)e->direction * (float)(y1-y0) * (1.0f-((x0-(float)x)+(x1-(float)x))/2.0f); + } +} + +NK_INTERN void +nk_tt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, + struct nk_tt__active_edge *e, float y_top) +{ + float y_bottom = y_top+1; + while (e) + { + /* brute force every pixel */ + /* compute intersection points with top & bottom */ + NK_ASSERT(e->ey >= y_top); + if (e->fdx == 0) { + float x0 = e->fx; + if (x0 < len) { + if (x0 >= 0) { + nk_tt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); + nk_tt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); + } else { + nk_tt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); + } + } + } else { + float x0 = e->fx; + float dx = e->fdx; + float xb = x0 + dx; + float x_top, x_bottom; + float y0,y1; + float dy = e->fdy; + NK_ASSERT(e->sy <= y_bottom && e->ey >= y_top); + + /* compute endpoints of line segment clipped to this scanline (if the */ + /* line segment starts on this scanline. x0 is the intersection of the */ + /* line with y_top, but that may be off the line segment. */ + if (e->sy > y_top) { + x_top = x0 + dx * (e->sy - y_top); + y0 = e->sy; + } else { + x_top = x0; + y0 = y_top; + } + + if (e->ey < y_bottom) { + x_bottom = x0 + dx * (e->ey - y_top); + y1 = e->ey; + } else { + x_bottom = xb; + y1 = y_bottom; + } + + if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) + { + /* from here on, we don't have to range check x values */ + if ((int) x_top == (int) x_bottom) { + float height; + /* simple case, only spans one pixel */ + int x = (int) x_top; + height = y1 - y0; + NK_ASSERT(x >= 0 && x < len); + scanline[x] += e->direction * (1.0f-(((float)x_top - (float)x) + ((float)x_bottom-(float)x))/2.0f) * (float)height; + scanline_fill[x] += e->direction * (float)height; /* everything right of this pixel is filled */ + } else { + int x,x1,x2; + float y_crossing, step, sign, area; + /* covers 2+ pixels */ + if (x_top > x_bottom) + { + /* flip scanline vertically; signed area is the same */ + float t; + y0 = y_bottom - (y0 - y_top); + y1 = y_bottom - (y1 - y_top); + t = y0; y0 = y1; y1 = t; + t = x_bottom; x_bottom = x_top; x_top = t; + dx = -dx; + dy = -dy; + t = x0; x0 = xb; xb = t; + } + + x1 = (int) x_top; + x2 = (int) x_bottom; + /* compute intersection with y axis at x1+1 */ + y_crossing = ((float)x1+1 - (float)x0) * (float)dy + (float)y_top; + + sign = e->direction; + /* area of the rectangle covered from y0..y_crossing */ + area = sign * (y_crossing-y0); + /* area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) */ + scanline[x1] += area * (1.0f-((float)((float)x_top - (float)x1)+(float)(x1+1-x1))/2.0f); + + step = sign * dy; + for (x = x1+1; x < x2; ++x) { + scanline[x] += area + step/2; + area += step; + } + y_crossing += (float)dy * (float)(x2 - (x1+1)); + + scanline[x2] += area + sign * (1.0f-((float)(x2-x2)+((float)x_bottom-(float)x2))/2.0f) * (y1-y_crossing); + scanline_fill[x2] += sign * (y1-y0); + } + } + else + { + /* if edge goes outside of box we're drawing, we require */ + /* clipping logic. since this does not match the intended use */ + /* of this library, we use a different, very slow brute */ + /* force implementation */ + int x; + for (x=0; x < len; ++x) + { + /* cases: */ + /* */ + /* there can be up to two intersections with the pixel. any intersection */ + /* with left or right edges can be handled by splitting into two (or three) */ + /* regions. intersections with top & bottom do not necessitate case-wise logic. */ + /* */ + /* the old way of doing this found the intersections with the left & right edges, */ + /* then used some simple logic to produce up to three segments in sorted order */ + /* from top-to-bottom. however, this had a problem: if an x edge was epsilon */ + /* across the x border, then the corresponding y position might not be distinct */ + /* from the other y segment, and it might ignored as an empty segment. to avoid */ + /* that, we need to explicitly produce segments based on x positions. */ + + /* rename variables to clear pairs */ + float ya = y_top; + float x1 = (float) (x); + float x2 = (float) (x+1); + float x3 = xb; + float y3 = y_bottom; + float yb,y2; + + yb = ((float)x - x0) / dx + y_top; + y2 = ((float)x+1 - x0) / dx + y_top; + + if (x0 < x1 && x3 > x2) { /* three segments descending down-right */ + nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb); + nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x2,y2); + nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x1 && x0 > x2) { /* three segments descending down-left */ + nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2); + nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x1,yb); + nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3); + } else if (x0 < x1 && x3 > x1) { /* two segments across x, down-right */ + nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb); + nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3); + } else if (x3 < x1 && x0 > x1) { /* two segments across x, down-left */ + nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb); + nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3); + } else if (x0 < x2 && x3 > x2) { /* two segments across x+1, down-right */ + nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2); + nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x2 && x0 > x2) { /* two segments across x+1, down-left */ + nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2); + nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else { /* one segment */ + nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x3,y3); + } + } + } + } + e = e->next; + } +} + +/* directly AA rasterize edges w/o supersampling */ +NK_INTERN void +nk_tt__rasterize_sorted_edges(struct nk_tt__bitmap *result, struct nk_tt__edge *e, + int n, int vsubsample, int off_x, int off_y, struct nk_allocator *alloc) +{ + struct nk_tt__hheap hh; + struct nk_tt__active_edge *active = 0; + int y,j=0, i; + float scanline_data[129], *scanline, *scanline2; + + NK_UNUSED(vsubsample); + nk_zero_struct(hh); + hh.alloc = *alloc; + + if (result->w > 64) + scanline = (float *) alloc->alloc(alloc->userdata,0, (nk_size)(result->w*2+1) * sizeof(float)); + else scanline = scanline_data; + + scanline2 = scanline + result->w; + y = off_y; + e[n].y0 = (float) (off_y + result->h) + 1; + + while (j < result->h) + { + /* find center of pixel for this scanline */ + float scan_y_top = (float)y + 0.0f; + float scan_y_bottom = (float)y + 1.0f; + struct nk_tt__active_edge **step = &active; + + NK_MEMSET(scanline , 0, (nk_size)result->w*sizeof(scanline[0])); + NK_MEMSET(scanline2, 0, (nk_size)(result->w+1)*sizeof(scanline[0])); + + /* update all active edges; */ + /* remove all active edges that terminate before the top of this scanline */ + while (*step) { + struct nk_tt__active_edge * z = *step; + if (z->ey <= scan_y_top) { + *step = z->next; /* delete from list */ + NK_ASSERT(z->direction); + z->direction = 0; + nk_tt__hheap_free(&hh, z); + } else { + step = &((*step)->next); /* advance through list */ + } + } + + /* insert all edges that start before the bottom of this scanline */ + while (e->y0 <= scan_y_bottom) { + if (e->y0 != e->y1) { + struct nk_tt__active_edge *z = nk_tt__new_active(&hh, e, off_x, scan_y_top); + if (z != 0) { + NK_ASSERT(z->ey >= scan_y_top); + /* insert at front */ + z->next = active; + active = z; + } + } + ++e; + } + + /* now process all active edges */ + if (active) + nk_tt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); + + { + float sum = 0; + for (i=0; i < result->w; ++i) { + float k; + int m; + sum += scanline2[i]; + k = scanline[i] + sum; + k = (float) NK_ABS(k) * 255.0f + 0.5f; + m = (int) k; + if (m > 255) m = 255; + result->pixels[j*result->stride + i] = (unsigned char) m; + } + } + /* advance all the edges */ + step = &active; + while (*step) { + struct nk_tt__active_edge *z = *step; + z->fx += z->fdx; /* advance to position for current scanline */ + step = &((*step)->next); /* advance through list */ + } + ++y; + ++j; + } + nk_tt__hheap_cleanup(&hh); + if (scanline != scanline_data) + alloc->free(alloc->userdata, scanline); +} + +#define NK_TT__COMPARE(a,b) ((a)->y0 < (b)->y0) +NK_INTERN void +nk_tt__sort_edges_ins_sort(struct nk_tt__edge *p, int n) +{ + int i,j; + for (i=1; i < n; ++i) { + struct nk_tt__edge t = p[i], *a = &t; + j = i; + while (j > 0) { + struct nk_tt__edge *b = &p[j-1]; + int c = NK_TT__COMPARE(a,b); + if (!c) break; + p[j] = p[j-1]; + --j; + } + if (i != j) + p[j] = t; + } +} + +NK_INTERN void +nk_tt__sort_edges_quicksort(struct nk_tt__edge *p, int n) +{ + /* threshold for transitioning to insertion sort */ + while (n > 12) { + struct nk_tt__edge t; + int c01,c12,c,m,i,j; + + /* compute median of three */ + m = n >> 1; + c01 = NK_TT__COMPARE(&p[0],&p[m]); + c12 = NK_TT__COMPARE(&p[m],&p[n-1]); + + /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ + if (c01 != c12) { + /* otherwise, we'll need to swap something else to middle */ + int z; + c = NK_TT__COMPARE(&p[0],&p[n-1]); + /* 0>mid && midn => n; 0 0 */ + /* 0n: 0>n => 0; 0 n */ + z = (c == c12) ? 0 : n-1; + t = p[z]; + p[z] = p[m]; + p[m] = t; + } + + /* now p[m] is the median-of-three */ + /* swap it to the beginning so it won't move around */ + t = p[0]; + p[0] = p[m]; + p[m] = t; + + /* partition loop */ + i=1; + j=n-1; + for(;;) { + /* handling of equality is crucial here */ + /* for sentinels & efficiency with duplicates */ + for (;;++i) { + if (!NK_TT__COMPARE(&p[i], &p[0])) break; + } + for (;;--j) { + if (!NK_TT__COMPARE(&p[0], &p[j])) break; + } + + /* make sure we haven't crossed */ + if (i >= j) break; + t = p[i]; + p[i] = p[j]; + p[j] = t; + + ++i; + --j; + + } + + /* recurse on smaller side, iterate on larger */ + if (j < (n-i)) { + nk_tt__sort_edges_quicksort(p,j); + p = p+i; + n = n-i; + } else { + nk_tt__sort_edges_quicksort(p+i, n-i); + n = j; + } + } +} + +NK_INTERN void +nk_tt__sort_edges(struct nk_tt__edge *p, int n) +{ + nk_tt__sort_edges_quicksort(p, n); + nk_tt__sort_edges_ins_sort(p, n); +} + +NK_INTERN void +nk_tt__rasterize(struct nk_tt__bitmap *result, struct nk_tt__point *pts, + int *wcount, int windings, float scale_x, float scale_y, + float shift_x, float shift_y, int off_x, int off_y, int invert, + struct nk_allocator *alloc) +{ + float y_scale_inv = invert ? -scale_y : scale_y; + struct nk_tt__edge *e; + int n,i,j,k,m; + int vsubsample = 1; + /* vsubsample should divide 255 evenly; otherwise we won't reach full opacity */ + + /* now we have to blow out the windings into explicit edge lists */ + n = 0; + for (i=0; i < windings; ++i) + n += wcount[i]; + + e = (struct nk_tt__edge*) + alloc->alloc(alloc->userdata, 0,(sizeof(*e) * (nk_size)(n+1))); + if (e == 0) return; + n = 0; + + m=0; + for (i=0; i < windings; ++i) + { + struct nk_tt__point *p = pts + m; + m += wcount[i]; + j = wcount[i]-1; + for (k=0; k < wcount[i]; j=k++) { + int a=k,b=j; + /* skip the edge if horizontal */ + if (p[j].y == p[k].y) + continue; + + /* add edge from j to k to the list */ + e[n].invert = 0; + if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { + e[n].invert = 1; + a=j,b=k; + } + e[n].x0 = p[a].x * scale_x + shift_x; + e[n].y0 = (p[a].y * y_scale_inv + shift_y) * (float)vsubsample; + e[n].x1 = p[b].x * scale_x + shift_x; + e[n].y1 = (p[b].y * y_scale_inv + shift_y) * (float)vsubsample; + ++n; + } + } + + /* now sort the edges by their highest point (should snap to integer, and then by x) */ + /*STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); */ + nk_tt__sort_edges(e, n); + /* now, traverse the scanlines and find the intersections on each scanline, use xor winding rule */ + nk_tt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, alloc); + alloc->free(alloc->userdata, e); +} + +NK_INTERN void +nk_tt__add_point(struct nk_tt__point *points, int n, float x, float y) +{ + if (!points) return; /* during first pass, it's unallocated */ + points[n].x = x; + points[n].y = y; +} + +NK_INTERN int +nk_tt__tesselate_curve(struct nk_tt__point *points, int *num_points, + float x0, float y0, float x1, float y1, float x2, float y2, + float objspace_flatness_squared, int n) +{ + /* tesselate until threshold p is happy... + * @TODO warped to compensate for non-linear stretching */ + /* midpoint */ + float mx = (x0 + 2*x1 + x2)/4; + float my = (y0 + 2*y1 + y2)/4; + /* versus directly drawn line */ + float dx = (x0+x2)/2 - mx; + float dy = (y0+y2)/2 - my; + if (n > 16) /* 65536 segments on one curve better be enough! */ + return 1; + + /* half-pixel error allowed... need to be smaller if AA */ + if (dx*dx+dy*dy > objspace_flatness_squared) { + nk_tt__tesselate_curve(points, num_points, x0,y0, + (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); + nk_tt__tesselate_curve(points, num_points, mx,my, + (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); + } else { + nk_tt__add_point(points, *num_points,x2,y2); + *num_points = *num_points+1; + } + return 1; +} + +/* returns number of contours */ +NK_INTERN struct nk_tt__point* +nk_tt_FlattenCurves(struct nk_tt_vertex *vertices, int num_verts, + float objspace_flatness, int **contour_lengths, int *num_contours, + struct nk_allocator *alloc) +{ + struct nk_tt__point *points=0; + int num_points=0; + float objspace_flatness_squared = objspace_flatness * objspace_flatness; + int i; + int n=0; + int start=0; + int pass; + + /* count how many "moves" there are to get the contour count */ + for (i=0; i < num_verts; ++i) + if (vertices[i].type == NK_TT_vmove) ++n; + + *num_contours = n; + if (n == 0) return 0; + + *contour_lengths = (int *) + alloc->alloc(alloc->userdata,0, (sizeof(**contour_lengths) * (nk_size)n)); + if (*contour_lengths == 0) { + *num_contours = 0; + return 0; + } + + /* make two passes through the points so we don't need to realloc */ + for (pass=0; pass < 2; ++pass) + { + float x=0,y=0; + if (pass == 1) { + points = (struct nk_tt__point *) + alloc->alloc(alloc->userdata,0, (nk_size)num_points * sizeof(points[0])); + if (points == 0) goto error; + } + num_points = 0; + n= -1; + + for (i=0; i < num_verts; ++i) + { + switch (vertices[i].type) { + case NK_TT_vmove: + /* start the next contour */ + if (n >= 0) + (*contour_lengths)[n] = num_points - start; + ++n; + start = num_points; + + x = vertices[i].x, y = vertices[i].y; + nk_tt__add_point(points, num_points++, x,y); + break; + case NK_TT_vline: + x = vertices[i].x, y = vertices[i].y; + nk_tt__add_point(points, num_points++, x, y); + break; + case NK_TT_vcurve: + nk_tt__tesselate_curve(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + default: break; + } + } + (*contour_lengths)[n] = num_points - start; + } + return points; + +error: + alloc->free(alloc->userdata, points); + alloc->free(alloc->userdata, *contour_lengths); + *contour_lengths = 0; + *num_contours = 0; + return 0; +} + +NK_INTERN void +nk_tt_Rasterize(struct nk_tt__bitmap *result, float flatness_in_pixels, + struct nk_tt_vertex *vertices, int num_verts, + float scale_x, float scale_y, float shift_x, float shift_y, + int x_off, int y_off, int invert, struct nk_allocator *alloc) +{ + float scale = scale_x > scale_y ? scale_y : scale_x; + int winding_count, *winding_lengths; + struct nk_tt__point *windings = nk_tt_FlattenCurves(vertices, num_verts, + flatness_in_pixels / scale, &winding_lengths, &winding_count, alloc); + + NK_ASSERT(alloc); + if (windings) { + nk_tt__rasterize(result, windings, winding_lengths, winding_count, + scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, alloc); + alloc->free(alloc->userdata, winding_lengths); + alloc->free(alloc->userdata, windings); + } +} + +NK_INTERN void +nk_tt_MakeGlyphBitmapSubpixel(const struct nk_tt_fontinfo *info, unsigned char *output, + int out_w, int out_h, int out_stride, float scale_x, float scale_y, + float shift_x, float shift_y, int glyph, struct nk_allocator *alloc) +{ + int ix0,iy0; + struct nk_tt_vertex *vertices; + int num_verts = nk_tt_GetGlyphShape(info, alloc, glyph, &vertices); + struct nk_tt__bitmap gbm; + + nk_tt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, + shift_y, &ix0,&iy0,0,0); + gbm.pixels = output; + gbm.w = out_w; + gbm.h = out_h; + gbm.stride = out_stride; + + if (gbm.w && gbm.h) + nk_tt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, + shift_x, shift_y, ix0,iy0, 1, alloc); + alloc->free(alloc->userdata, vertices); +} + +/*------------------------------------------------------------- + * Bitmap baking + * --------------------------------------------------------------*/ +NK_INTERN int +nk_tt_PackBegin(struct nk_tt_pack_context *spc, unsigned char *pixels, + int pw, int ph, int stride_in_bytes, int padding, struct nk_allocator *alloc) +{ + int num_nodes = pw - padding; + struct nk_rp_context *context = (struct nk_rp_context *) + alloc->alloc(alloc->userdata,0, sizeof(*context)); + struct nk_rp_node *nodes = (struct nk_rp_node*) + alloc->alloc(alloc->userdata,0, (sizeof(*nodes ) * (nk_size)num_nodes)); + + if (context == 0 || nodes == 0) { + if (context != 0) alloc->free(alloc->userdata, context); + if (nodes != 0) alloc->free(alloc->userdata, nodes); + return 0; + } + + spc->width = pw; + spc->height = ph; + spc->pixels = pixels; + spc->pack_info = context; + spc->nodes = nodes; + spc->padding = padding; + spc->stride_in_bytes = (stride_in_bytes != 0) ? stride_in_bytes : pw; + spc->h_oversample = 1; + spc->v_oversample = 1; + + nk_rp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); + if (pixels) + NK_MEMSET(pixels, 0, (nk_size)(pw*ph)); /* background of 0 around pixels */ + return 1; +} + +NK_INTERN void +nk_tt_PackEnd(struct nk_tt_pack_context *spc, struct nk_allocator *alloc) +{ + alloc->free(alloc->userdata, spc->nodes); + alloc->free(alloc->userdata, spc->pack_info); +} + +NK_INTERN void +nk_tt_PackSetOversampling(struct nk_tt_pack_context *spc, + unsigned int h_oversample, unsigned int v_oversample) +{ + NK_ASSERT(h_oversample <= NK_TT_MAX_OVERSAMPLE); + NK_ASSERT(v_oversample <= NK_TT_MAX_OVERSAMPLE); + if (h_oversample <= NK_TT_MAX_OVERSAMPLE) + spc->h_oversample = h_oversample; + if (v_oversample <= NK_TT_MAX_OVERSAMPLE) + spc->v_oversample = v_oversample; +} + +NK_INTERN void +nk_tt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, + int kernel_width) +{ + unsigned char buffer[NK_TT_MAX_OVERSAMPLE]; + int safe_w = w - kernel_width; + int j; + + for (j=0; j < h; ++j) + { + int i; + unsigned int total; + NK_MEMSET(buffer, 0, (nk_size)kernel_width); + + total = 0; + + /* make kernel_width a constant in common cases so compiler can optimize out the divide */ + switch (kernel_width) { + case 2: + for (i=0; i <= safe_w; ++i) { + total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); + buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_w; ++i) { + total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); + buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_w; ++i) { + total += (unsigned int)pixels[i] - buffer[i & NK_TT__OVER_MASK]; + buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_w; ++i) { + total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); + buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_w; ++i) { + total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); + buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / (unsigned int)kernel_width); + } + break; + } + + for (; i < w; ++i) { + NK_ASSERT(pixels[i] == 0); + total -= (unsigned int)(buffer[i & NK_TT__OVER_MASK]); + pixels[i] = (unsigned char) (total / (unsigned int)kernel_width); + } + pixels += stride_in_bytes; + } +} + +NK_INTERN void +nk_tt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, + int kernel_width) +{ + unsigned char buffer[NK_TT_MAX_OVERSAMPLE]; + int safe_h = h - kernel_width; + int j; + + for (j=0; j < w; ++j) + { + int i; + unsigned int total; + NK_MEMSET(buffer, 0, (nk_size)kernel_width); + + total = 0; + + /* make kernel_width a constant in common cases so compiler can optimize out the divide */ + switch (kernel_width) { + case 2: + for (i=0; i <= safe_h; ++i) { + total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); + buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_h; ++i) { + total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); + buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_h; ++i) { + total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); + buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_h; ++i) { + total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); + buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_h; ++i) { + total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); + buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / (unsigned int)kernel_width); + } + break; + } + + for (; i < h; ++i) { + NK_ASSERT(pixels[i*stride_in_bytes] == 0); + total -= (unsigned int)(buffer[i & NK_TT__OVER_MASK]); + pixels[i*stride_in_bytes] = (unsigned char) (total / (unsigned int)kernel_width); + } + pixels += 1; + } +} + +NK_INTERN float +nk_tt__oversample_shift(int oversample) +{ + if (!oversample) + return 0.0f; + + /* The prefilter is a box filter of width "oversample", */ + /* which shifts phase by (oversample - 1)/2 pixels in */ + /* oversampled space. We want to shift in the opposite */ + /* direction to counter this. */ + return (float)-(oversample - 1) / (2.0f * (float)oversample); +} + +/* rects array must be big enough to accommodate all characters in the given ranges */ +NK_INTERN int +nk_tt_PackFontRangesGatherRects(struct nk_tt_pack_context *spc, + struct nk_tt_fontinfo *info, struct nk_tt_pack_range *ranges, + int num_ranges, struct nk_rp_rect *rects) +{ + int i,j,k; + k = 0; + + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = (fh > 0) ? nk_tt_ScaleForPixelHeight(info, fh): + nk_tt_ScaleForMappingEmToPixels(info, -fh); + ranges[i].h_oversample = (unsigned char) spc->h_oversample; + ranges[i].v_oversample = (unsigned char) spc->v_oversample; + for (j=0; j < ranges[i].num_chars; ++j) { + int x0,y0,x1,y1; + int codepoint = ranges[i].first_unicode_codepoint_in_range ? + ranges[i].first_unicode_codepoint_in_range + j : + ranges[i].array_of_unicode_codepoints[j]; + + int glyph = nk_tt_FindGlyphIndex(info, codepoint); + nk_tt_GetGlyphBitmapBoxSubpixel(info,glyph, scale * (float)spc->h_oversample, + scale * (float)spc->v_oversample, 0,0, &x0,&y0,&x1,&y1); + rects[k].w = (nk_rp_coord) (x1-x0 + spc->padding + (int)spc->h_oversample-1); + rects[k].h = (nk_rp_coord) (y1-y0 + spc->padding + (int)spc->v_oversample-1); + ++k; + } + } + return k; +} + +NK_INTERN int +nk_tt_PackFontRangesRenderIntoRects(struct nk_tt_pack_context *spc, + struct nk_tt_fontinfo *info, struct nk_tt_pack_range *ranges, + int num_ranges, struct nk_rp_rect *rects, struct nk_allocator *alloc) +{ + int i,j,k, return_value = 1; + /* save current values */ + int old_h_over = (int)spc->h_oversample; + int old_v_over = (int)spc->v_oversample; + /* rects array must be big enough to accommodate all characters in the given ranges */ + + k = 0; + for (i=0; i < num_ranges; ++i) + { + float fh = ranges[i].font_size; + float recip_h,recip_v,sub_x,sub_y; + float scale = fh > 0 ? nk_tt_ScaleForPixelHeight(info, fh): + nk_tt_ScaleForMappingEmToPixels(info, -fh); + + spc->h_oversample = ranges[i].h_oversample; + spc->v_oversample = ranges[i].v_oversample; + + recip_h = 1.0f / (float)spc->h_oversample; + recip_v = 1.0f / (float)spc->v_oversample; + + sub_x = nk_tt__oversample_shift((int)spc->h_oversample); + sub_y = nk_tt__oversample_shift((int)spc->v_oversample); + + for (j=0; j < ranges[i].num_chars; ++j) + { + struct nk_rp_rect *r = &rects[k]; + if (r->was_packed) + { + struct nk_tt_packedchar *bc = &ranges[i].chardata_for_range[j]; + int advance, lsb, x0,y0,x1,y1; + int codepoint = ranges[i].first_unicode_codepoint_in_range ? + ranges[i].first_unicode_codepoint_in_range + j : + ranges[i].array_of_unicode_codepoints[j]; + int glyph = nk_tt_FindGlyphIndex(info, codepoint); + nk_rp_coord pad = (nk_rp_coord) spc->padding; + + /* pad on left and top */ + r->x = (nk_rp_coord)((int)r->x + (int)pad); + r->y = (nk_rp_coord)((int)r->y + (int)pad); + r->w = (nk_rp_coord)((int)r->w - (int)pad); + r->h = (nk_rp_coord)((int)r->h - (int)pad); + + nk_tt_GetGlyphHMetrics(info, glyph, &advance, &lsb); + nk_tt_GetGlyphBitmapBox(info, glyph, scale * (float)spc->h_oversample, + (scale * (float)spc->v_oversample), &x0,&y0,&x1,&y1); + nk_tt_MakeGlyphBitmapSubpixel(info, spc->pixels + r->x + r->y*spc->stride_in_bytes, + (int)(r->w - spc->h_oversample+1), (int)(r->h - spc->v_oversample+1), + spc->stride_in_bytes, scale * (float)spc->h_oversample, + scale * (float)spc->v_oversample, 0,0, glyph, alloc); + + if (spc->h_oversample > 1) + nk_tt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, (int)spc->h_oversample); + + if (spc->v_oversample > 1) + nk_tt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, (int)spc->v_oversample); + + bc->x0 = (nk_ushort) r->x; + bc->y0 = (nk_ushort) r->y; + bc->x1 = (nk_ushort) (r->x + r->w); + bc->y1 = (nk_ushort) (r->y + r->h); + bc->xadvance = scale * (float)advance; + bc->xoff = (float) x0 * recip_h + sub_x; + bc->yoff = (float) y0 * recip_v + sub_y; + bc->xoff2 = ((float)x0 + r->w) * recip_h + sub_x; + bc->yoff2 = ((float)y0 + r->h) * recip_v + sub_y; + } else { + return_value = 0; /* if any fail, report failure */ + } + ++k; + } + } + /* restore original values */ + spc->h_oversample = (unsigned int)old_h_over; + spc->v_oversample = (unsigned int)old_v_over; + return return_value; +} + +NK_INTERN void +nk_tt_GetPackedQuad(struct nk_tt_packedchar *chardata, int pw, int ph, + int char_index, float *xpos, float *ypos, struct nk_tt_aligned_quad *q, + int align_to_integer) +{ + float ipw = 1.0f / (float)pw, iph = 1.0f / (float)ph; + struct nk_tt_packedchar *b = (struct nk_tt_packedchar*)(chardata + char_index); + if (align_to_integer) { + int tx = nk_ifloorf((*xpos + b->xoff) + 0.5f); + int ty = nk_ifloorf((*ypos + b->yoff) + 0.5f); + + float x = (float)tx; + float y = (float)ty; + + q->x0 = x; + q->y0 = y; + q->x1 = x + b->xoff2 - b->xoff; + q->y1 = y + b->yoff2 - b->yoff; + } else { + q->x0 = *xpos + b->xoff; + q->y0 = *ypos + b->yoff; + q->x1 = *xpos + b->xoff2; + q->y1 = *ypos + b->yoff2; + } + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + *xpos += b->xadvance; +} + +/* ------------------------------------------------------------- + * + * FONT BAKING + * + * --------------------------------------------------------------*/ +struct nk_font_bake_data { + struct nk_tt_fontinfo info; + struct nk_rp_rect *rects; + struct nk_tt_pack_range *ranges; + nk_rune range_count; +}; + +struct nk_font_baker { + struct nk_allocator alloc; + struct nk_tt_pack_context spc; + struct nk_font_bake_data *build; + struct nk_tt_packedchar *packed_chars; + struct nk_rp_rect *rects; + struct nk_tt_pack_range *ranges; +}; + +NK_GLOBAL const nk_size nk_rect_align = NK_ALIGNOF(struct nk_rp_rect); +NK_GLOBAL const nk_size nk_range_align = NK_ALIGNOF(struct nk_tt_pack_range); +NK_GLOBAL const nk_size nk_char_align = NK_ALIGNOF(struct nk_tt_packedchar); +NK_GLOBAL const nk_size nk_build_align = NK_ALIGNOF(struct nk_font_bake_data); +NK_GLOBAL const nk_size nk_baker_align = NK_ALIGNOF(struct nk_font_baker); + +NK_INTERN int +nk_range_count(const nk_rune *range) +{ + const nk_rune *iter = range; + NK_ASSERT(range); + if (!range) return 0; + while (*(iter++) != 0); + return (iter == range) ? 0 : (int)((iter - range)/2); +} + +NK_INTERN int +nk_range_glyph_count(const nk_rune *range, int count) +{ + int i = 0; + int total_glyphs = 0; + for (i = 0; i < count; ++i) { + int diff; + nk_rune f = range[(i*2)+0]; + nk_rune t = range[(i*2)+1]; + NK_ASSERT(t >= f); + diff = (int)((t - f) + 1); + total_glyphs += diff; + } + return total_glyphs; +} + +NK_API const nk_rune* +nk_font_default_glyph_ranges(void) +{ + NK_STORAGE const nk_rune ranges[] = {0x0020, 0x00FF, 0}; + return ranges; +} + +NK_API const nk_rune* +nk_font_chinese_glyph_ranges(void) +{ + NK_STORAGE const nk_rune ranges[] = { + 0x0020, 0x00FF, + 0x3000, 0x30FF, + 0x31F0, 0x31FF, + 0xFF00, 0xFFEF, + 0x4e00, 0x9FAF, + 0 + }; + return ranges; +} + +NK_API const nk_rune* +nk_font_cyrillic_glyph_ranges(void) +{ + NK_STORAGE const nk_rune ranges[] = { + 0x0020, 0x00FF, + 0x0400, 0x052F, + 0x2DE0, 0x2DFF, + 0xA640, 0xA69F, + 0 + }; + return ranges; +} + +NK_API const nk_rune* +nk_font_korean_glyph_ranges(void) +{ + NK_STORAGE const nk_rune ranges[] = { + 0x0020, 0x00FF, + 0x3131, 0x3163, + 0xAC00, 0xD79D, + 0 + }; + return ranges; +} + +NK_INTERN void +nk_font_baker_memory(nk_size *temp, int *glyph_count, + struct nk_font_config *config_list, int count) +{ + int range_count = 0; + int total_range_count = 0; + struct nk_font_config *iter; + + NK_ASSERT(config_list); + NK_ASSERT(glyph_count); + if (!config_list) { + *temp = 0; + *glyph_count = 0; + return; + } + + *glyph_count = 0; + if (!config_list->range) + config_list->range = nk_font_default_glyph_ranges(); + for (iter = config_list; iter; iter = iter->next) { + range_count = nk_range_count(iter->range); + total_range_count += range_count; + *glyph_count += nk_range_glyph_count(iter->range, range_count); + } + + *temp = (nk_size)*glyph_count * sizeof(struct nk_rp_rect); + *temp += (nk_size)total_range_count * sizeof(struct nk_tt_pack_range); + *temp += (nk_size)*glyph_count * sizeof(struct nk_tt_packedchar); + *temp += (nk_size)count * sizeof(struct nk_font_bake_data); + *temp += sizeof(struct nk_font_baker); + *temp += nk_rect_align + nk_range_align + nk_char_align; + *temp += nk_build_align + nk_baker_align; +} + +NK_INTERN struct nk_font_baker* +nk_font_baker(void *memory, int glyph_count, int count, struct nk_allocator *alloc) +{ + struct nk_font_baker *baker; + if (!memory) return 0; + /* setup baker inside a memory block */ + baker = (struct nk_font_baker*)NK_ALIGN_PTR(memory, nk_baker_align); + baker->build = (struct nk_font_bake_data*)NK_ALIGN_PTR((baker + 1), nk_build_align); + baker->packed_chars = (struct nk_tt_packedchar*)NK_ALIGN_PTR((baker->build + count), nk_char_align); + baker->rects = (struct nk_rp_rect*)NK_ALIGN_PTR((baker->packed_chars + glyph_count), nk_rect_align); + baker->ranges = (struct nk_tt_pack_range*)NK_ALIGN_PTR((baker->rects + glyph_count), nk_range_align); + baker->alloc = *alloc; + return baker; +} + +NK_INTERN int +nk_font_bake_pack(struct nk_font_baker *baker, + nk_size *image_memory, int *width, int *height, struct nk_recti *custom, + const struct nk_font_config *config_list, int count, + struct nk_allocator *alloc) +{ + NK_STORAGE const nk_size max_height = 1024 * 32; + const struct nk_font_config *config_iter; + int total_glyph_count = 0; + int total_range_count = 0; + int range_count = 0; + int i = 0; + + NK_ASSERT(image_memory); + NK_ASSERT(width); + NK_ASSERT(height); + NK_ASSERT(config_list); + NK_ASSERT(count); + NK_ASSERT(alloc); + + if (!image_memory || !width || !height || !config_list || !count) return nk_false; + for (config_iter = config_list; config_iter; config_iter = config_iter->next) { + range_count = nk_range_count(config_iter->range); + total_range_count += range_count; + total_glyph_count += nk_range_glyph_count(config_iter->range, range_count); + } + + /* setup font baker from temporary memory */ + for (config_iter = config_list; config_iter; config_iter = config_iter->next) { + const struct nk_font_config *cfg = config_iter; + if (!nk_tt_InitFont(&baker->build[i++].info, (const unsigned char*)cfg->ttf_blob, 0)) + return nk_false; + } + + *height = 0; + *width = (total_glyph_count > 1000) ? 1024 : 512; + nk_tt_PackBegin(&baker->spc, 0, (int)*width, (int)max_height, 0, 1, alloc); + { + int input_i = 0; + int range_n = 0; + int rect_n = 0; + int char_n = 0; + + if (custom) { + /* pack custom user data first so it will be in the upper left corner*/ + struct nk_rp_rect custom_space; + nk_zero(&custom_space, sizeof(custom_space)); + custom_space.w = (nk_rp_coord)((custom->w * 2) + 1); + custom_space.h = (nk_rp_coord)(custom->h + 1); + + nk_tt_PackSetOversampling(&baker->spc, 1, 1); + nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, &custom_space, 1); + *height = NK_MAX(*height, (int)(custom_space.y + custom_space.h)); + + custom->x = (short)custom_space.x; + custom->y = (short)custom_space.y; + custom->w = (short)custom_space.w; + custom->h = (short)custom_space.h; + } + + /* first font pass: pack all glyphs */ + for (input_i = 0, config_iter = config_list; input_i < count && config_iter; + input_i++, config_iter = config_iter->next) + { + int n = 0; + int glyph_count; + const nk_rune *in_range; + const struct nk_font_config *cfg = config_iter; + struct nk_font_bake_data *tmp = &baker->build[input_i]; + + /* count glyphs + ranges in current font */ + glyph_count = 0; range_count = 0; + for (in_range = cfg->range; in_range[0] && in_range[1]; in_range += 2) { + glyph_count += (int)(in_range[1] - in_range[0]) + 1; + range_count++; + } + + /* setup ranges */ + tmp->ranges = baker->ranges + range_n; + tmp->range_count = (nk_rune)range_count; + range_n += range_count; + for (i = 0; i < range_count; ++i) { + in_range = &cfg->range[i * 2]; + tmp->ranges[i].font_size = cfg->size; + tmp->ranges[i].first_unicode_codepoint_in_range = (int)in_range[0]; + tmp->ranges[i].num_chars = (int)(in_range[1]- in_range[0]) + 1; + tmp->ranges[i].chardata_for_range = baker->packed_chars + char_n; + char_n += tmp->ranges[i].num_chars; + } + + /* pack */ + tmp->rects = baker->rects + rect_n; + rect_n += glyph_count; + nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); + n = nk_tt_PackFontRangesGatherRects(&baker->spc, &tmp->info, + tmp->ranges, (int)tmp->range_count, tmp->rects); + nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, tmp->rects, (int)n); + + /* texture height */ + for (i = 0; i < n; ++i) { + if (tmp->rects[i].was_packed) + *height = NK_MAX(*height, tmp->rects[i].y + tmp->rects[i].h); + } + } + NK_ASSERT(rect_n == total_glyph_count); + NK_ASSERT(char_n == total_glyph_count); + NK_ASSERT(range_n == total_range_count); + } + *height = (int)nk_round_up_pow2((nk_uint)*height); + *image_memory = (nk_size)(*width) * (nk_size)(*height); + return nk_true; +} + +NK_INTERN void +nk_font_bake(struct nk_font_baker *baker, void *image_memory, int width, int height, + struct nk_font_glyph *glyphs, int glyphs_count, + const struct nk_font_config *config_list, int font_count) +{ + int input_i = 0; + nk_rune glyph_n = 0; + const struct nk_font_config *config_iter; + + NK_ASSERT(image_memory); + NK_ASSERT(width); + NK_ASSERT(height); + NK_ASSERT(config_list); + NK_ASSERT(baker); + NK_ASSERT(font_count); + NK_ASSERT(glyphs_count); + if (!image_memory || !width || !height || !config_list || + !font_count || !glyphs || !glyphs_count) + return; + + /* second font pass: render glyphs */ + nk_zero(image_memory, (nk_size)((nk_size)width * (nk_size)height)); + baker->spc.pixels = (unsigned char*)image_memory; + baker->spc.height = (int)height; + for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter; + ++input_i, config_iter = config_iter->next) + { + const struct nk_font_config *cfg = config_iter; + struct nk_font_bake_data *tmp = &baker->build[input_i]; + nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); + nk_tt_PackFontRangesRenderIntoRects(&baker->spc, &tmp->info, tmp->ranges, + (int)tmp->range_count, tmp->rects, &baker->alloc); + } + nk_tt_PackEnd(&baker->spc, &baker->alloc); + + /* third pass: setup font and glyphs */ + for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter; + ++input_i, config_iter = config_iter->next) + { + nk_size i = 0; + int char_idx = 0; + nk_rune glyph_count = 0; + const struct nk_font_config *cfg = config_iter; + struct nk_font_bake_data *tmp = &baker->build[input_i]; + struct nk_baked_font *dst_font = cfg->font; + + float font_scale = nk_tt_ScaleForPixelHeight(&tmp->info, cfg->size); + int unscaled_ascent, unscaled_descent, unscaled_line_gap; + nk_tt_GetFontVMetrics(&tmp->info, &unscaled_ascent, &unscaled_descent, + &unscaled_line_gap); + + /* fill baked font */ + if (!cfg->merge_mode) { + dst_font->ranges = cfg->range; + dst_font->height = cfg->size; + dst_font->ascent = ((float)unscaled_ascent * font_scale); + dst_font->descent = ((float)unscaled_descent * font_scale); + dst_font->glyph_offset = glyph_n; + } + + /* fill own baked font glyph array */ + for (i = 0; i < tmp->range_count; ++i) + { + struct nk_tt_pack_range *range = &tmp->ranges[i]; + for (char_idx = 0; char_idx < range->num_chars; char_idx++) + { + nk_rune codepoint = 0; + float dummy_x = 0, dummy_y = 0; + struct nk_tt_aligned_quad q; + struct nk_font_glyph *glyph; + + /* query glyph bounds from stb_truetype */ + const struct nk_tt_packedchar *pc = &range->chardata_for_range[char_idx]; + if (!pc->x0 && !pc->x1 && !pc->y0 && !pc->y1) continue; + codepoint = (nk_rune)(range->first_unicode_codepoint_in_range + char_idx); + nk_tt_GetPackedQuad(range->chardata_for_range, (int)width, + (int)height, char_idx, &dummy_x, &dummy_y, &q, 0); + + /* fill own glyph type with data */ + glyph = &glyphs[dst_font->glyph_offset + (unsigned int)glyph_count]; + glyph->codepoint = codepoint; + glyph->x0 = q.x0; glyph->y0 = q.y0; + glyph->x1 = q.x1; glyph->y1 = q.y1; + glyph->y0 += (dst_font->ascent + 0.5f); + glyph->y1 += (dst_font->ascent + 0.5f); + glyph->w = glyph->x1 - glyph->x0 + 0.5f; + glyph->h = glyph->y1 - glyph->y0; + + if (cfg->coord_type == NK_COORD_PIXEL) { + glyph->u0 = q.s0 * (float)width; + glyph->v0 = q.t0 * (float)height; + glyph->u1 = q.s1 * (float)width; + glyph->v1 = q.t1 * (float)height; + } else { + glyph->u0 = q.s0; + glyph->v0 = q.t0; + glyph->u1 = q.s1; + glyph->v1 = q.t1; + } + glyph->xadvance = (pc->xadvance + cfg->spacing.x); + if (cfg->pixel_snap) + glyph->xadvance = (float)(int)(glyph->xadvance + 0.5f); + glyph_count++; + } + } + dst_font->glyph_count = glyph_count; + glyph_n += dst_font->glyph_count; + } +} + +NK_INTERN void +nk_font_bake_custom_data(void *img_memory, int img_width, int img_height, + struct nk_recti img_dst, const char *texture_data_mask, int tex_width, + int tex_height, char white, char black) +{ + nk_byte *pixels; + int y = 0; + int x = 0; + int n = 0; + + NK_ASSERT(img_memory); + NK_ASSERT(img_width); + NK_ASSERT(img_height); + NK_ASSERT(texture_data_mask); + NK_UNUSED(tex_height); + if (!img_memory || !img_width || !img_height || !texture_data_mask) + return; + + pixels = (nk_byte*)img_memory; + for (y = 0, n = 0; y < tex_height; ++y) { + for (x = 0; x < tex_width; ++x, ++n) { + const int off0 = ((img_dst.x + x) + (img_dst.y + y) * img_width); + const int off1 = off0 + 1 + tex_width; + pixels[off0] = (texture_data_mask[n] == white) ? 0xFF : 0x00; + pixels[off1] = (texture_data_mask[n] == black) ? 0xFF : 0x00; + } + } +} + +NK_INTERN void +nk_font_bake_convert(void *out_memory, int img_width, int img_height, + const void *in_memory) +{ + int n = 0; + nk_rune *dst; + const nk_byte *src; + + NK_ASSERT(out_memory); + NK_ASSERT(in_memory); + NK_ASSERT(img_width); + NK_ASSERT(img_height); + if (!out_memory || !in_memory || !img_height || !img_width) return; + + dst = (nk_rune*)out_memory; + src = (const nk_byte*)in_memory; + for (n = (int)(img_width * img_height); n > 0; n--) + *dst++ = ((nk_rune)(*src++) << 24) | 0x00FFFFFF; +} + +/* ------------------------------------------------------------- + * + * FONT + * + * --------------------------------------------------------------*/ +NK_INTERN float +nk_font_text_width(nk_handle handle, float height, const char *text, int len) +{ + nk_rune unicode; + int text_len = 0; + float text_width = 0; + int glyph_len = 0; + float scale = 0; + + struct nk_font *font = (struct nk_font*)handle.ptr; + NK_ASSERT(font); + NK_ASSERT(font->glyphs); + if (!font || !text || !len) + return 0; + + scale = height/font->info.height; + glyph_len = text_len = nk_utf_decode(text, &unicode, (int)len); + if (!glyph_len) return 0; + while (text_len <= (int)len && glyph_len) { + const struct nk_font_glyph *g; + if (unicode == NK_UTF_INVALID) break; + + /* query currently drawn glyph information */ + g = nk_font_find_glyph(font, unicode); + text_width += g->xadvance * scale; + + /* offset next glyph */ + glyph_len = nk_utf_decode(text + text_len, &unicode, (int)len - text_len); + text_len += glyph_len; + } + return text_width; +} + +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT +NK_INTERN void +nk_font_query_font_glyph(nk_handle handle, float height, + struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint) +{ + float scale; + const struct nk_font_glyph *g; + struct nk_font *font; + + NK_ASSERT(glyph); + NK_UNUSED(next_codepoint); + + font = (struct nk_font*)handle.ptr; + NK_ASSERT(font); + NK_ASSERT(font->glyphs); + if (!font || !glyph) + return; + + scale = height/font->info.height; + g = nk_font_find_glyph(font, codepoint); + glyph->width = (g->x1 - g->x0) * scale; + glyph->height = (g->y1 - g->y0) * scale; + glyph->offset = nk_vec2(g->x0 * scale, g->y0 * scale); + glyph->xadvance = (g->xadvance * scale); + glyph->uv[0] = nk_vec2(g->u0, g->v0); + glyph->uv[1] = nk_vec2(g->u1, g->v1); +} +#endif + +NK_API const struct nk_font_glyph* +nk_font_find_glyph(struct nk_font *font, nk_rune unicode) +{ + int i = 0; + int count; + int total_glyphs = 0; + const struct nk_font_glyph *glyph = 0; + + NK_ASSERT(font); + NK_ASSERT(font->glyphs); + NK_ASSERT(font->info.ranges); + if (!font || !font->glyphs) return 0; + + glyph = font->fallback; + count = nk_range_count(font->info.ranges); + for (i = 0; i < count; ++i) { + nk_rune f = font->info.ranges[(i*2)+0]; + nk_rune t = font->info.ranges[(i*2)+1]; + int diff = (int)((t - f) + 1); + if (unicode >= f && unicode <= t) + return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))]; + total_glyphs += diff; + } + return glyph; +} + +NK_INTERN void +nk_font_init(struct nk_font *font, float pixel_height, + nk_rune fallback_codepoint, struct nk_font_glyph *glyphs, + const struct nk_baked_font *baked_font, nk_handle atlas) +{ + struct nk_baked_font baked; + NK_ASSERT(font); + NK_ASSERT(glyphs); + NK_ASSERT(baked_font); + if (!font || !glyphs || !baked_font) + return; + + baked = *baked_font; + font->fallback = 0; + font->info = baked; + font->scale = (float)pixel_height / (float)font->info.height; + font->glyphs = &glyphs[baked_font->glyph_offset]; + font->texture = atlas; + font->fallback_codepoint = fallback_codepoint; + font->fallback = nk_font_find_glyph(font, fallback_codepoint); + + font->handle.height = font->info.height * font->scale; + font->handle.width = nk_font_text_width; + font->handle.userdata.ptr = font; +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT + font->handle.query = nk_font_query_font_glyph; + font->handle.texture = font->texture; +#endif +} + +/* --------------------------------------------------------------------------- + * + * DEFAULT FONT + * + * ProggyClean.ttf + * Copyright (c) 2004, 2005 Tristan Grimmer + * MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip) + * Download and more information at http://upperbounds.net + *-----------------------------------------------------------------------------*/ +#ifdef NK_INCLUDE_DEFAULT_FONT + + #ifdef __clang__ +#pragma clang diagnostic push + +#pragma clang diagnostic ignored "-Woverlength-strings" +#elif defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Woverlength-strings" +#endif + +NK_GLOBAL const char nk_proggy_clean_ttf_compressed_data_base85[11980+1] = + "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" + "2*>]b(MC;$jPfY.;h^`IWM9Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1=Ke$$'5F%)]0^#0X@U.a$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;--VsM.M0rJfLH2eTM`*oJMHRC`N" + "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa&VZ>1i%h1S9u5o@YaaW$e+bROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc." + "x]Ip.PH^'/aqUO/$1WxLoW0[iLAw=4h(9.`G" + "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?Ggv:[7MI2k).'2($5FNP&EQ(,)" + "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#" + "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM" + "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu" + "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/" + "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[Ket`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO" + "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%" + "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$MhLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]" + "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" + "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" + "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VBpqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<-+k?'(^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" + "D?@f&1'BW-)Ju#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(" + "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs" + "bIu)'Z,*[>br5fX^:FPAWr-m2KgLQ_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q" + "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aege0jT6'N#(q%.O=?2S]u*(m<-" + "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i" + "sZ88+dKQ)W6>J%CL`.d*(B`-n8D9oK-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P r+$%CE=68>K8r0=dSC%%(@p7" + ".m7jilQ02'0-VWAgTlGW'b)Tq7VT9q^*^$$.:&N@@" + "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*" + "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u" + "@-W$U%VEQ/,,>>#)D#%8cY#YZ?=,`Wdxu/ae&#" + "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$so8lKN%5/$(vdfq7+ebA#" + "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8" + "6e%B/:=>)N4xeW.*wft-;$'58-ESqr#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#" + "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjLV#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#SfD07&6D@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5" + "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%" + "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;" + "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmLq9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:" + "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3$U4O]GKx'm9)b@p7YsvK3w^YR-" + "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*" + "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdFTi1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IXSsDiWP,##P`%/L-" + "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdFl*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj" + "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#$(>.Z-I&J(Q0Hd5Q%7Co-b`-cP)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8WlA2);Sa" + ">gXm8YB`1d@K#n]76-a$U,mF%Ul:#/'xoFM9QX-$.QN'>" + "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I" + "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-uW%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)" + "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo" + "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P" + "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*'IAO" + "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#" + ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T" + "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4" + "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#" + "/QHC#3^ZC#7jmC#;v)D#?,)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP" + "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp" + "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#"; +#endif /* NK_INCLUDE_DEFAULT_FONT */ + +#define NK_CURSOR_DATA_W 90 +#define NK_CURSOR_DATA_H 27 +NK_GLOBAL const char nk_custom_cursor_data[NK_CURSOR_DATA_W * NK_CURSOR_DATA_H + 1] = +{ + "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX" + "..- -X.....X- X.X - X.X -X.....X - X.....X" + "--- -XXX.XXX- X...X - X...X -X....X - X....X" + "X - X.X - X.....X - X.....X -X...X - X...X" + "XX - X.X -X.......X- X.......X -X..X.X - X.X..X" + "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X" + "X..X - X.X - X.X - X.X -XX X.X - X.X XX" + "X...X - X.X - X.X - XX X.X XX - X.X - X.X " + "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X " + "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X " + "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X " + "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X " + "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X " + "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X " + "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X " + "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X " + "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX " + "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------" + "X.X X..X - -X.......X- X.......X - XX XX - " + "XX X..X - - X.....X - X.....X - X.X X.X - " + " X..X - X...X - X...X - X..X X..X - " + " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - " + "------------ - X - X -X.....................X- " + " ----------------------------------- X...XXXXXXXXXXXXX...X - " + " - X..X X..X - " + " - X.X X.X - " + " - XX XX - " +}; + +#ifdef __clang__ +#pragma clang diagnostic pop +#elif defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic pop +#endif + +NK_INTERN unsigned int +nk_decompress_length(unsigned char *input) +{ + return (unsigned int)((input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]); +} + +NK_GLOBAL unsigned char *nk__barrier; +NK_GLOBAL unsigned char *nk__barrier2; +NK_GLOBAL unsigned char *nk__barrier3; +NK_GLOBAL unsigned char *nk__barrier4; +NK_GLOBAL unsigned char *nk__dout; + +NK_INTERN void +nk__match(unsigned char *data, unsigned int length) +{ + /* INVERSE of memmove... write each byte before copying the next...*/ + NK_ASSERT (nk__dout + length <= nk__barrier); + if (nk__dout + length > nk__barrier) { nk__dout += length; return; } + if (data < nk__barrier4) { nk__dout = nk__barrier+1; return; } + while (length--) *nk__dout++ = *data++; +} + +NK_INTERN void +nk__lit(unsigned char *data, unsigned int length) +{ + NK_ASSERT (nk__dout + length <= nk__barrier); + if (nk__dout + length > nk__barrier) { nk__dout += length; return; } + if (data < nk__barrier2) { nk__dout = nk__barrier+1; return; } + NK_MEMCPY(nk__dout, data, length); + nk__dout += length; +} + +#define nk__in2(x) ((i[x] << 8) + i[(x)+1]) +#define nk__in3(x) ((i[x] << 16) + nk__in2((x)+1)) +#define nk__in4(x) ((i[x] << 24) + nk__in3((x)+1)) + +NK_INTERN unsigned char* +nk_decompress_token(unsigned char *i) +{ + if (*i >= 0x20) { /* use fewer if's for cases that expand small */ + if (*i >= 0x80) nk__match(nk__dout-i[1]-1, (unsigned int)i[0] - 0x80 + 1), i += 2; + else if (*i >= 0x40) nk__match(nk__dout-(nk__in2(0) - 0x4000 + 1), (unsigned int)i[2]+1), i += 3; + else /* *i >= 0x20 */ nk__lit(i+1, (unsigned int)i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); + } else { /* more ifs for cases that expand large, since overhead is amortized */ + if (*i >= 0x18) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x180000 + 1), (unsigned int)i[3]+1), i += 4; + else if (*i >= 0x10) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x100000 + 1), (unsigned int)nk__in2(3)+1), i += 5; + else if (*i >= 0x08) nk__lit(i+2, (unsigned int)nk__in2(0) - 0x0800 + 1), i += 2 + (nk__in2(0) - 0x0800 + 1); + else if (*i == 0x07) nk__lit(i+3, (unsigned int)nk__in2(1) + 1), i += 3 + (nk__in2(1) + 1); + else if (*i == 0x06) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), i[4]+1u), i += 5; + else if (*i == 0x04) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), (unsigned int)nk__in2(4)+1u), i += 6; + } + return i; +} + +NK_INTERN unsigned int +nk_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen) +{ + const unsigned long ADLER_MOD = 65521; + unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; + unsigned long blocklen, i; + + blocklen = buflen % 5552; + while (buflen) { + for (i=0; i + 7 < blocklen; i += 8) { + s1 += buffer[0]; s2 += s1; + s1 += buffer[1]; s2 += s1; + s1 += buffer[2]; s2 += s1; + s1 += buffer[3]; s2 += s1; + s1 += buffer[4]; s2 += s1; + s1 += buffer[5]; s2 += s1; + s1 += buffer[6]; s2 += s1; + s1 += buffer[7]; s2 += s1; + buffer += 8; + } + for (; i < blocklen; ++i) { + s1 += *buffer++; s2 += s1; + } + + s1 %= ADLER_MOD; s2 %= ADLER_MOD; + buflen -= (unsigned int)blocklen; + blocklen = 5552; + } + return (unsigned int)(s2 << 16) + (unsigned int)s1; +} + +NK_INTERN unsigned int +nk_decompress(unsigned char *output, unsigned char *i, unsigned int length) +{ + unsigned int olen; + if (nk__in4(0) != 0x57bC0000) return 0; + if (nk__in4(4) != 0) return 0; /* error! stream is > 4GB */ + olen = nk_decompress_length(i); + nk__barrier2 = i; + nk__barrier3 = i+length; + nk__barrier = output + olen; + nk__barrier4 = output; + i += 16; + + nk__dout = output; + for (;;) { + unsigned char *old_i = i; + i = nk_decompress_token(i); + if (i == old_i) { + if (*i == 0x05 && i[1] == 0xfa) { + NK_ASSERT(nk__dout == output + olen); + if (nk__dout != output + olen) return 0; + if (nk_adler32(1, output, olen) != (unsigned int) nk__in4(2)) + return 0; + return olen; + } else { + NK_ASSERT(0); /* NOTREACHED */ + return 0; + } + } + NK_ASSERT(nk__dout <= output + olen); + if (nk__dout > output + olen) + return 0; + } +} + +NK_INTERN unsigned int +nk_decode_85_byte(char c) +{ return (unsigned int)((c >= '\\') ? c-36 : c-35); } + +NK_INTERN void +nk_decode_85(unsigned char* dst, const unsigned char* src) +{ + while (*src) + { + unsigned int tmp = + nk_decode_85_byte((char)src[0]) + + 85 * (nk_decode_85_byte((char)src[1]) + + 85 * (nk_decode_85_byte((char)src[2]) + + 85 * (nk_decode_85_byte((char)src[3]) + + 85 * nk_decode_85_byte((char)src[4])))); + + /* we can't assume little-endianess. */ + dst[0] = (unsigned char)((tmp >> 0) & 0xFF); + dst[1] = (unsigned char)((tmp >> 8) & 0xFF); + dst[2] = (unsigned char)((tmp >> 16) & 0xFF); + dst[3] = (unsigned char)((tmp >> 24) & 0xFF); + + src += 5; + dst += 4; + } +} + +/* ------------------------------------------------------------- + * + * FONT ATLAS + * + * --------------------------------------------------------------*/ +NK_API struct nk_font_config +nk_font_config(float pixel_height) +{ + struct nk_font_config cfg; + nk_zero_struct(cfg); + cfg.ttf_blob = 0; + cfg.ttf_size = 0; + cfg.ttf_data_owned_by_atlas = 0; + cfg.size = pixel_height; + cfg.oversample_h = 3; + cfg.oversample_v = 1; + cfg.pixel_snap = 0; + cfg.coord_type = NK_COORD_UV; + cfg.spacing = nk_vec2(0,0); + cfg.range = nk_font_default_glyph_ranges(); + cfg.merge_mode = 0; + cfg.fallback_glyph = '?'; + cfg.font = 0; + return cfg; +} + +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +NK_API void +nk_font_atlas_init_default(struct nk_font_atlas *atlas) +{ + NK_ASSERT(atlas); + if (!atlas) return; + nk_zero_struct(*atlas); + atlas->temporary.userdata.ptr = 0; + atlas->temporary.alloc = nk_malloc; + atlas->temporary.free = nk_mfree; + atlas->permanent.userdata.ptr = 0; + atlas->permanent.alloc = nk_malloc; + atlas->permanent.free = nk_mfree; +} +#endif + +NK_API void +nk_font_atlas_init(struct nk_font_atlas *atlas, struct nk_allocator *alloc) +{ + NK_ASSERT(atlas); + NK_ASSERT(alloc); + if (!atlas || !alloc) return; + nk_zero_struct(*atlas); + atlas->permanent = *alloc; + atlas->temporary = *alloc; +} + +NK_API void +nk_font_atlas_init_custom(struct nk_font_atlas *atlas, + struct nk_allocator *permanent, struct nk_allocator *temporary) +{ + NK_ASSERT(atlas); + NK_ASSERT(permanent); + NK_ASSERT(temporary); + if (!atlas || !permanent || !temporary) return; + nk_zero_struct(*atlas); + atlas->permanent = *permanent; + atlas->temporary = *temporary; +} + +NK_API void +nk_font_atlas_begin(struct nk_font_atlas *atlas) +{ + NK_ASSERT(atlas); + NK_ASSERT(atlas->temporary.alloc && atlas->temporary.free); + NK_ASSERT(atlas->permanent.alloc && atlas->permanent.free); + if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free || + !atlas->temporary.alloc || !atlas->temporary.free) return; + if (atlas->glyphs) { + atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); + atlas->glyphs = 0; + } + if (atlas->pixel) { + atlas->permanent.free(atlas->permanent.userdata, atlas->pixel); + atlas->pixel = 0; + } +} + +NK_API struct nk_font* +nk_font_atlas_add(struct nk_font_atlas *atlas, const struct nk_font_config *config) +{ + struct nk_font *font = 0; + struct nk_font_config *cfg; + + NK_ASSERT(atlas); + NK_ASSERT(atlas->permanent.alloc); + NK_ASSERT(atlas->permanent.free); + NK_ASSERT(atlas->temporary.alloc); + NK_ASSERT(atlas->temporary.free); + + NK_ASSERT(config); + NK_ASSERT(config->ttf_blob); + NK_ASSERT(config->ttf_size); + NK_ASSERT(config->size > 0.0f); + + if (!atlas || !config || !config->ttf_blob || !config->ttf_size || config->size <= 0.0f|| + !atlas->permanent.alloc || !atlas->permanent.free || + !atlas->temporary.alloc || !atlas->temporary.free) + return 0; + + /* allocate and insert font config into list */ + cfg = (struct nk_font_config*) + atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font_config)); + NK_MEMCPY(cfg, config, sizeof(*config)); + if (!atlas->config) { + atlas->config = cfg; + cfg->next = 0; + } else { + cfg->next = atlas->config; + atlas->config = cfg; + } + + /* allocate new font */ + if (!config->merge_mode) { + font = (struct nk_font*) + atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font)); + NK_ASSERT(font); + if (!font) return 0; + font->config = cfg; + } else { + NK_ASSERT(atlas->font_num); + font = atlas->fonts; + font->config = cfg; + } + + /* insert font into list */ + if (!config->merge_mode) { + if (!atlas->fonts) { + atlas->fonts = font; + font->next = 0; + } else { + font->next = atlas->fonts; + atlas->fonts = font; + } + cfg->font = &font->info; + } + + /* create own copy of .TTF font blob */ + if (!config->ttf_data_owned_by_atlas) { + cfg->ttf_blob = atlas->permanent.alloc(atlas->permanent.userdata,0, cfg->ttf_size); + NK_ASSERT(cfg->ttf_blob); + if (!cfg->ttf_blob) { + atlas->font_num++; + return 0; + } + NK_MEMCPY(cfg->ttf_blob, config->ttf_blob, cfg->ttf_size); + cfg->ttf_data_owned_by_atlas = 1; + } + atlas->font_num++; + return font; +} + +NK_API struct nk_font* +nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, + nk_size size, float height, const struct nk_font_config *config) +{ + struct nk_font_config cfg; + NK_ASSERT(memory); + NK_ASSERT(size); + + NK_ASSERT(atlas); + NK_ASSERT(atlas->temporary.alloc); + NK_ASSERT(atlas->temporary.free); + NK_ASSERT(atlas->permanent.alloc); + NK_ASSERT(atlas->permanent.free); + if (!atlas || !atlas->temporary.alloc || !atlas->temporary.free || !memory || !size || + !atlas->permanent.alloc || !atlas->permanent.free) + return 0; + + cfg = (config) ? *config: nk_font_config(height); + cfg.ttf_blob = memory; + cfg.ttf_size = size; + cfg.size = height; + cfg.ttf_data_owned_by_atlas = 0; + return nk_font_atlas_add(atlas, &cfg); +} + +#ifdef NK_INCLUDE_STANDARD_IO +NK_API struct nk_font* +nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, + float height, const struct nk_font_config *config) +{ + nk_size size; + char *memory; + struct nk_font_config cfg; + + NK_ASSERT(atlas); + NK_ASSERT(atlas->temporary.alloc); + NK_ASSERT(atlas->temporary.free); + NK_ASSERT(atlas->permanent.alloc); + NK_ASSERT(atlas->permanent.free); + + if (!atlas || !file_path) return 0; + memory = nk_file_load(file_path, &size, &atlas->permanent); + if (!memory) return 0; + + cfg = (config) ? *config: nk_font_config(height); + cfg.ttf_blob = memory; + cfg.ttf_size = size; + cfg.size = height; + cfg.ttf_data_owned_by_atlas = 1; + return nk_font_atlas_add(atlas, &cfg); +} +#endif + +NK_API struct nk_font* +nk_font_atlas_add_compressed(struct nk_font_atlas *atlas, + void *compressed_data, nk_size compressed_size, float height, + const struct nk_font_config *config) +{ + unsigned int decompressed_size; + void *decompressed_data; + struct nk_font_config cfg; + + NK_ASSERT(atlas); + NK_ASSERT(atlas->temporary.alloc); + NK_ASSERT(atlas->temporary.free); + NK_ASSERT(atlas->permanent.alloc); + NK_ASSERT(atlas->permanent.free); + + NK_ASSERT(compressed_data); + NK_ASSERT(compressed_size); + if (!atlas || !compressed_data || !atlas->temporary.alloc || !atlas->temporary.free || + !atlas->permanent.alloc || !atlas->permanent.free) + return 0; + + decompressed_size = nk_decompress_length((unsigned char*)compressed_data); + decompressed_data = atlas->permanent.alloc(atlas->permanent.userdata,0,decompressed_size); + NK_ASSERT(decompressed_data); + if (!decompressed_data) return 0; + nk_decompress((unsigned char*)decompressed_data, (unsigned char*)compressed_data, + (unsigned int)compressed_size); + + cfg = (config) ? *config: nk_font_config(height); + cfg.ttf_blob = decompressed_data; + cfg.ttf_size = decompressed_size; + cfg.size = height; + cfg.ttf_data_owned_by_atlas = 1; + return nk_font_atlas_add(atlas, &cfg); +} + +NK_API struct nk_font* +nk_font_atlas_add_compressed_base85(struct nk_font_atlas *atlas, + const char *data_base85, float height, const struct nk_font_config *config) +{ + int compressed_size; + void *compressed_data; + struct nk_font *font; + + NK_ASSERT(atlas); + NK_ASSERT(atlas->temporary.alloc); + NK_ASSERT(atlas->temporary.free); + NK_ASSERT(atlas->permanent.alloc); + NK_ASSERT(atlas->permanent.free); + + NK_ASSERT(data_base85); + if (!atlas || !data_base85 || !atlas->temporary.alloc || !atlas->temporary.free || + !atlas->permanent.alloc || !atlas->permanent.free) + return 0; + + compressed_size = (((int)nk_strlen(data_base85) + 4) / 5) * 4; + compressed_data = atlas->temporary.alloc(atlas->temporary.userdata,0, (nk_size)compressed_size); + NK_ASSERT(compressed_data); + if (!compressed_data) return 0; + nk_decode_85((unsigned char*)compressed_data, (const unsigned char*)data_base85); + font = nk_font_atlas_add_compressed(atlas, compressed_data, + (nk_size)compressed_size, height, config); + atlas->temporary.free(atlas->temporary.userdata, compressed_data); + return font; +} + +#ifdef NK_INCLUDE_DEFAULT_FONT +NK_API struct nk_font* +nk_font_atlas_add_default(struct nk_font_atlas *atlas, + float pixel_height, const struct nk_font_config *config) +{ + NK_ASSERT(atlas); + NK_ASSERT(atlas->temporary.alloc); + NK_ASSERT(atlas->temporary.free); + NK_ASSERT(atlas->permanent.alloc); + NK_ASSERT(atlas->permanent.free); + return nk_font_atlas_add_compressed_base85(atlas, + nk_proggy_clean_ttf_compressed_data_base85, pixel_height, config); +} +#endif + +NK_API const void* +nk_font_atlas_bake(struct nk_font_atlas *atlas, int *width, int *height, + enum nk_font_atlas_format fmt) +{ + int i = 0; + void *tmp = 0; + nk_size tmp_size, img_size; + struct nk_font *font_iter; + struct nk_font_baker *baker; + + NK_ASSERT(atlas); + NK_ASSERT(atlas->temporary.alloc); + NK_ASSERT(atlas->temporary.free); + NK_ASSERT(atlas->permanent.alloc); + NK_ASSERT(atlas->permanent.free); + + NK_ASSERT(width); + NK_ASSERT(height); + if (!atlas || !width || !height || + !atlas->temporary.alloc || !atlas->temporary.free || + !atlas->permanent.alloc || !atlas->permanent.free) + return 0; + +#ifdef NK_INCLUDE_DEFAULT_FONT + /* no font added so just use default font */ + if (!atlas->font_num) + atlas->default_font = nk_font_atlas_add_default(atlas, 13.0f, 0); +#endif + NK_ASSERT(atlas->font_num); + if (!atlas->font_num) return 0; + + /* allocate temporary baker memory required for the baking process */ + nk_font_baker_memory(&tmp_size, &atlas->glyph_count, atlas->config, atlas->font_num); + tmp = atlas->temporary.alloc(atlas->temporary.userdata,0, tmp_size); + NK_ASSERT(tmp); + if (!tmp) goto failed; + + /* allocate glyph memory for all fonts */ + baker = nk_font_baker(tmp, atlas->glyph_count, atlas->font_num, &atlas->temporary); + atlas->glyphs = (struct nk_font_glyph*)atlas->permanent.alloc( + atlas->permanent.userdata,0, sizeof(struct nk_font_glyph)*(nk_size)atlas->glyph_count); + NK_ASSERT(atlas->glyphs); + if (!atlas->glyphs) + goto failed; + + /* pack all glyphs into a tight fit space */ + atlas->custom.w = (NK_CURSOR_DATA_W*2)+1; + atlas->custom.h = NK_CURSOR_DATA_H + 1; + if (!nk_font_bake_pack(baker, &img_size, width, height, &atlas->custom, + atlas->config, atlas->font_num, &atlas->temporary)) + goto failed; + + /* allocate memory for the baked image font atlas */ + atlas->pixel = atlas->temporary.alloc(atlas->temporary.userdata,0, img_size); + NK_ASSERT(atlas->pixel); + if (!atlas->pixel) + goto failed; + + /* bake glyphs and custom white pixel into image */ + nk_font_bake(baker, atlas->pixel, *width, *height, + atlas->glyphs, atlas->glyph_count, atlas->config, atlas->font_num); + nk_font_bake_custom_data(atlas->pixel, *width, *height, atlas->custom, + nk_custom_cursor_data, NK_CURSOR_DATA_W, NK_CURSOR_DATA_H, '.', 'X'); + + if (fmt == NK_FONT_ATLAS_RGBA32) { + /* convert alpha8 image into rgba32 image */ + void *img_rgba = atlas->temporary.alloc(atlas->temporary.userdata,0, + (nk_size)(*width * *height * 4)); + NK_ASSERT(img_rgba); + if (!img_rgba) goto failed; + nk_font_bake_convert(img_rgba, *width, *height, atlas->pixel); + atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); + atlas->pixel = img_rgba; + } + atlas->tex_width = *width; + atlas->tex_height = *height; + + /* initialize each font */ + for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) { + struct nk_font *font = font_iter; + struct nk_font_config *config = font->config; + nk_font_init(font, config->size, config->fallback_glyph, atlas->glyphs, + config->font, nk_handle_ptr(0)); + } + + /* initialize each cursor */ + {NK_STORAGE const struct nk_vec2 nk_cursor_data[NK_CURSOR_COUNT][3] = { + /* Pos ----- Size ------- Offset --*/ + {{ 0, 3}, {12,19}, { 0, 0}}, + {{13, 0}, { 7,16}, { 4, 8}}, + {{31, 0}, {23,23}, {11,11}}, + {{21, 0}, { 9, 23}, { 5,11}}, + {{55,18}, {23, 9}, {11, 5}}, + {{73, 0}, {17,17}, { 9, 9}}, + {{55, 0}, {17,17}, { 9, 9}} + }; + for (i = 0; i < NK_CURSOR_COUNT; ++i) { + struct nk_cursor *cursor = &atlas->cursors[i]; + cursor->img.w = (unsigned short)*width; + cursor->img.h = (unsigned short)*height; + cursor->img.region[0] = (unsigned short)(atlas->custom.x + nk_cursor_data[i][0].x); + cursor->img.region[1] = (unsigned short)(atlas->custom.y + nk_cursor_data[i][0].y); + cursor->img.region[2] = (unsigned short)nk_cursor_data[i][1].x; + cursor->img.region[3] = (unsigned short)nk_cursor_data[i][1].y; + cursor->size = nk_cursor_data[i][1]; + cursor->offset = nk_cursor_data[i][2]; + }} + /* free temporary memory */ + atlas->temporary.free(atlas->temporary.userdata, tmp); + return atlas->pixel; + +failed: + /* error so cleanup all memory */ + if (tmp) atlas->temporary.free(atlas->temporary.userdata, tmp); + if (atlas->glyphs) { + atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); + atlas->glyphs = 0; + } + if (atlas->pixel) { + atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); + atlas->pixel = 0; + } + return 0; +} + +NK_API void +nk_font_atlas_end(struct nk_font_atlas *atlas, nk_handle texture, + struct nk_draw_null_texture *null) +{ + int i = 0; + struct nk_font *font_iter; + NK_ASSERT(atlas); + if (!atlas) { + if (!null) return; + null->texture = texture; + null->uv = nk_vec2(0.5f,0.5f); + } + if (null) { + null->texture = texture; + null->uv.x = (atlas->custom.x + 0.5f)/(float)atlas->tex_width; + null->uv.y = (atlas->custom.y + 0.5f)/(float)atlas->tex_height; + } + for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) { + font_iter->texture = texture; +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT + font_iter->handle.texture = texture; +#endif + } + for (i = 0; i < NK_CURSOR_COUNT; ++i) + atlas->cursors[i].img.handle = texture; + + atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); + atlas->pixel = 0; + atlas->tex_width = 0; + atlas->tex_height = 0; + atlas->custom.x = 0; + atlas->custom.y = 0; + atlas->custom.w = 0; + atlas->custom.h = 0; +} + +NK_API void +nk_font_atlas_cleanup(struct nk_font_atlas *atlas) +{ + NK_ASSERT(atlas); + NK_ASSERT(atlas->temporary.alloc); + NK_ASSERT(atlas->temporary.free); + NK_ASSERT(atlas->permanent.alloc); + NK_ASSERT(atlas->permanent.free); + + if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return; + if (atlas->config) { + struct nk_font_config *iter, *next; + for (iter = atlas->config; iter; iter = next) { + next = iter->next; + atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob); + atlas->permanent.free(atlas->permanent.userdata, iter); + } + atlas->config = 0; + } +} + +NK_API void +nk_font_atlas_clear(struct nk_font_atlas *atlas) +{ + NK_ASSERT(atlas); + NK_ASSERT(atlas->temporary.alloc); + NK_ASSERT(atlas->temporary.free); + NK_ASSERT(atlas->permanent.alloc); + NK_ASSERT(atlas->permanent.free); + if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return; + + nk_font_atlas_cleanup(atlas); + if (atlas->fonts) { + struct nk_font *iter, *next; + for (iter = atlas->fonts; iter; iter = next) { + next = iter->next; + atlas->permanent.free(atlas->permanent.userdata, iter); + } + atlas->fonts = 0; + } + if (atlas->glyphs) + atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); + nk_zero_struct(*atlas); +} +#endif +/* ============================================================== + * + * INPUT + * + * ===============================================================*/ +NK_API void +nk_input_begin(struct nk_context *ctx) +{ + int i; + struct nk_input *in; + NK_ASSERT(ctx); + if (!ctx) return; + in = &ctx->input; + for (i = 0; i < NK_BUTTON_MAX; ++i) + in->mouse.buttons[i].clicked = 0; + + in->keyboard.text_len = 0; + in->mouse.scroll_delta = nk_vec2(0,0); + in->mouse.prev.x = in->mouse.pos.x; + in->mouse.prev.y = in->mouse.pos.y; + in->mouse.delta.x = 0; + in->mouse.delta.y = 0; + for (i = 0; i < NK_KEY_MAX; i++) + in->keyboard.keys[i].clicked = 0; +} + +NK_API void +nk_input_end(struct nk_context *ctx) +{ + struct nk_input *in; + NK_ASSERT(ctx); + if (!ctx) return; + in = &ctx->input; + if (in->mouse.grab) + in->mouse.grab = 0; + if (in->mouse.ungrab) { + in->mouse.grabbed = 0; + in->mouse.ungrab = 0; + in->mouse.grab = 0; + } +} + +NK_API void +nk_input_motion(struct nk_context *ctx, int x, int y) +{ + struct nk_input *in; + NK_ASSERT(ctx); + if (!ctx) return; + in = &ctx->input; + in->mouse.pos.x = (float)x; + in->mouse.pos.y = (float)y; + in->mouse.delta.x = in->mouse.pos.x - in->mouse.prev.x; + in->mouse.delta.y = in->mouse.pos.y - in->mouse.prev.y; +} + +NK_API void +nk_input_key(struct nk_context *ctx, enum nk_keys key, int down) +{ + struct nk_input *in; + NK_ASSERT(ctx); + if (!ctx) return; + in = &ctx->input; + if (in->keyboard.keys[key].down != down) + in->keyboard.keys[key].clicked++; + in->keyboard.keys[key].down = down; +} + +NK_API void +nk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, int down) +{ + struct nk_mouse_button *btn; + struct nk_input *in; + NK_ASSERT(ctx); + if (!ctx) return; + in = &ctx->input; + if (in->mouse.buttons[id].down == down) return; + + btn = &in->mouse.buttons[id]; + btn->clicked_pos.x = (float)x; + btn->clicked_pos.y = (float)y; + btn->down = down; + btn->clicked++; +} + +NK_API void +nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val) +{ + NK_ASSERT(ctx); + if (!ctx) return; + ctx->input.mouse.scroll_delta.x += val.x; + ctx->input.mouse.scroll_delta.y += val.y; +} + +NK_API void +nk_input_glyph(struct nk_context *ctx, const nk_glyph glyph) +{ + int len = 0; + nk_rune unicode; + struct nk_input *in; + + NK_ASSERT(ctx); + if (!ctx) return; + in = &ctx->input; + + len = nk_utf_decode(glyph, &unicode, NK_UTF_SIZE); + if (len && ((in->keyboard.text_len + len) < NK_INPUT_MAX)) { + nk_utf_encode(unicode, &in->keyboard.text[in->keyboard.text_len], + NK_INPUT_MAX - in->keyboard.text_len); + in->keyboard.text_len += len; + } +} + +NK_API void +nk_input_char(struct nk_context *ctx, char c) +{ + nk_glyph glyph; + NK_ASSERT(ctx); + if (!ctx) return; + glyph[0] = c; + nk_input_glyph(ctx, glyph); +} + +NK_API void +nk_input_unicode(struct nk_context *ctx, nk_rune unicode) +{ + nk_glyph rune; + NK_ASSERT(ctx); + if (!ctx) return; + nk_utf_encode(unicode, rune, NK_UTF_SIZE); + nk_input_glyph(ctx, rune); +} + +NK_API int +nk_input_has_mouse_click(const struct nk_input *i, enum nk_buttons id) +{ + const struct nk_mouse_button *btn; + if (!i) return nk_false; + btn = &i->mouse.buttons[id]; + return (btn->clicked && btn->down == nk_false) ? nk_true : nk_false; +} + +NK_API int +nk_input_has_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id, + struct nk_rect b) +{ + const struct nk_mouse_button *btn; + if (!i) return nk_false; + btn = &i->mouse.buttons[id]; + if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h)) + return nk_false; + return nk_true; +} + +NK_API int +nk_input_has_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, + struct nk_rect b, int down) +{ + const struct nk_mouse_button *btn; + if (!i) return nk_false; + btn = &i->mouse.buttons[id]; + return nk_input_has_mouse_click_in_rect(i, id, b) && (btn->down == down); +} + +NK_API int +nk_input_is_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id, + struct nk_rect b) +{ + const struct nk_mouse_button *btn; + if (!i) return nk_false; + btn = &i->mouse.buttons[id]; + return (nk_input_has_mouse_click_down_in_rect(i, id, b, nk_false) && + btn->clicked) ? nk_true : nk_false; +} + +NK_API int +nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, + struct nk_rect b, int down) +{ + const struct nk_mouse_button *btn; + if (!i) return nk_false; + btn = &i->mouse.buttons[id]; + return (nk_input_has_mouse_click_down_in_rect(i, id, b, down) && + btn->clicked) ? nk_true : nk_false; +} + +NK_API int +nk_input_any_mouse_click_in_rect(const struct nk_input *in, struct nk_rect b) +{ + int i, down = 0; + for (i = 0; i < NK_BUTTON_MAX; ++i) + down = down || nk_input_is_mouse_click_in_rect(in, (enum nk_buttons)i, b); + return down; +} + +NK_API int +nk_input_is_mouse_hovering_rect(const struct nk_input *i, struct nk_rect rect) +{ + if (!i) return nk_false; + return NK_INBOX(i->mouse.pos.x, i->mouse.pos.y, rect.x, rect.y, rect.w, rect.h); +} + +NK_API int +nk_input_is_mouse_prev_hovering_rect(const struct nk_input *i, struct nk_rect rect) +{ + if (!i) return nk_false; + return NK_INBOX(i->mouse.prev.x, i->mouse.prev.y, rect.x, rect.y, rect.w, rect.h); +} + +NK_API int +nk_input_mouse_clicked(const struct nk_input *i, enum nk_buttons id, struct nk_rect rect) +{ + if (!i) return nk_false; + if (!nk_input_is_mouse_hovering_rect(i, rect)) return nk_false; + return nk_input_is_mouse_click_in_rect(i, id, rect); +} + +NK_API int +nk_input_is_mouse_down(const struct nk_input *i, enum nk_buttons id) +{ + if (!i) return nk_false; + return i->mouse.buttons[id].down; +} + +NK_API int +nk_input_is_mouse_pressed(const struct nk_input *i, enum nk_buttons id) +{ + const struct nk_mouse_button *b; + if (!i) return nk_false; + b = &i->mouse.buttons[id]; + if (b->down && b->clicked) + return nk_true; + return nk_false; +} + +NK_API int +nk_input_is_mouse_released(const struct nk_input *i, enum nk_buttons id) +{ + if (!i) return nk_false; + return (!i->mouse.buttons[id].down && i->mouse.buttons[id].clicked); +} + +NK_API int +nk_input_is_key_pressed(const struct nk_input *i, enum nk_keys key) +{ + const struct nk_key *k; + if (!i) return nk_false; + k = &i->keyboard.keys[key]; + if ((k->down && k->clicked) || (!k->down && k->clicked >= 2)) + return nk_true; + return nk_false; +} + +NK_API int +nk_input_is_key_released(const struct nk_input *i, enum nk_keys key) +{ + const struct nk_key *k; + if (!i) return nk_false; + k = &i->keyboard.keys[key]; + if ((!k->down && k->clicked) || (k->down && k->clicked >= 2)) + return nk_true; + return nk_false; +} + +NK_API int +nk_input_is_key_down(const struct nk_input *i, enum nk_keys key) +{ + const struct nk_key *k; + if (!i) return nk_false; + k = &i->keyboard.keys[key]; + if (k->down) return nk_true; + return nk_false; +} + +/* + * ============================================================== + * + * TEXT EDITOR + * + * =============================================================== + */ +/* stb_textedit.h - v1.8 - public domain - Sean Barrett */ +struct nk_text_find { + float x,y; /* position of n'th character */ + float height; /* height of line */ + int first_char, length; /* first char of row, and length */ + int prev_first; /*_ first char of previous row */ +}; + +struct nk_text_edit_row { + float x0,x1; + /* starting x location, end x location (allows for align=right, etc) */ + float baseline_y_delta; + /* position of baseline relative to previous row's baseline*/ + float ymin,ymax; + /* height of row above and below baseline */ + int num_chars; +}; + +/* forward declarations */ +NK_INTERN void nk_textedit_makeundo_delete(struct nk_text_edit*, int, int); +NK_INTERN void nk_textedit_makeundo_insert(struct nk_text_edit*, int, int); +NK_INTERN void nk_textedit_makeundo_replace(struct nk_text_edit*, int, int, int); +#define NK_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) + +NK_INTERN float +nk_textedit_get_width(const struct nk_text_edit *edit, int line_start, int char_id, + const struct nk_user_font *font) +{ + int len = 0; + nk_rune unicode = 0; + const char *str = nk_str_at_const(&edit->string, line_start + char_id, &unicode, &len); + return font->width(font->userdata, font->height, str, len); +} + +NK_INTERN void +nk_textedit_layout_row(struct nk_text_edit_row *r, struct nk_text_edit *edit, + int line_start_id, float row_height, const struct nk_user_font *font) +{ + int l; + int glyphs = 0; + nk_rune unicode; + const char *remaining; + int len = nk_str_len_char(&edit->string); + const char *end = nk_str_get_const(&edit->string) + len; + const char *text = nk_str_at_const(&edit->string, line_start_id, &unicode, &l); + const struct nk_vec2 size = nk_text_calculate_text_bounds(font, + text, (int)(end - text), row_height, &remaining, 0, &glyphs, NK_STOP_ON_NEW_LINE); + + r->x0 = 0.0f; + r->x1 = size.x; + r->baseline_y_delta = size.y; + r->ymin = 0.0f; + r->ymax = size.y; + r->num_chars = glyphs; +} + +NK_INTERN int +nk_textedit_locate_coord(struct nk_text_edit *edit, float x, float y, + const struct nk_user_font *font, float row_height) +{ + struct nk_text_edit_row r; + int n = edit->string.len; + float base_y = 0, prev_x; + int i=0, k; + + r.x0 = r.x1 = 0; + r.ymin = r.ymax = 0; + r.num_chars = 0; + + /* search rows to find one that straddles 'y' */ + while (i < n) { + nk_textedit_layout_row(&r, edit, i, row_height, font); + if (r.num_chars <= 0) + return n; + + if (i==0 && y < base_y + r.ymin) + return 0; + + if (y < base_y + r.ymax) + break; + + i += r.num_chars; + base_y += r.baseline_y_delta; + } + + /* below all text, return 'after' last character */ + if (i >= n) + return n; + + /* check if it's before the beginning of the line */ + if (x < r.x0) + return i; + + /* check if it's before the end of the line */ + if (x < r.x1) { + /* search characters in row for one that straddles 'x' */ + k = i; + prev_x = r.x0; + for (i=0; i < r.num_chars; ++i) { + float w = nk_textedit_get_width(edit, k, i, font); + if (x < prev_x+w) { + if (x < prev_x+w/2) + return k+i; + else return k+i+1; + } + prev_x += w; + } + /* shouldn't happen, but if it does, fall through to end-of-line case */ + } + + /* if the last character is a newline, return that. + * otherwise return 'after' the last character */ + if (nk_str_rune_at(&edit->string, i+r.num_chars-1) == '\n') + return i+r.num_chars-1; + else return i+r.num_chars; +} + +NK_INTERN void +nk_textedit_click(struct nk_text_edit *state, float x, float y, + const struct nk_user_font *font, float row_height) +{ + /* API click: on mouse down, move the cursor to the clicked location, + * and reset the selection */ + state->cursor = nk_textedit_locate_coord(state, x, y, font, row_height); + state->select_start = state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; +} + +NK_INTERN void +nk_textedit_drag(struct nk_text_edit *state, float x, float y, + const struct nk_user_font *font, float row_height) +{ + /* API drag: on mouse drag, move the cursor and selection endpoint + * to the clicked location */ + int p = nk_textedit_locate_coord(state, x, y, font, row_height); + if (state->select_start == state->select_end) + state->select_start = state->cursor; + state->cursor = state->select_end = p; +} + +NK_INTERN void +nk_textedit_find_charpos(struct nk_text_find *find, struct nk_text_edit *state, + int n, int single_line, const struct nk_user_font *font, float row_height) +{ + /* find the x/y location of a character, and remember info about the previous + * row in case we get a move-up event (for page up, we'll have to rescan) */ + struct nk_text_edit_row r; + int prev_start = 0; + int z = state->string.len; + int i=0, first; + + nk_zero_struct(r); + if (n == z) { + /* if it's at the end, then find the last line -- simpler than trying to + explicitly handle this case in the regular code */ + nk_textedit_layout_row(&r, state, 0, row_height, font); + if (single_line) { + find->first_char = 0; + find->length = z; + } else { + while (i < z) { + prev_start = i; + i += r.num_chars; + nk_textedit_layout_row(&r, state, i, row_height, font); + } + + find->first_char = i; + find->length = r.num_chars; + } + find->x = r.x1; + find->y = r.ymin; + find->height = r.ymax - r.ymin; + find->prev_first = prev_start; + return; + } + + /* search rows to find the one that straddles character n */ + find->y = 0; + + for(;;) { + nk_textedit_layout_row(&r, state, i, row_height, font); + if (n < i + r.num_chars) break; + prev_start = i; + i += r.num_chars; + find->y += r.baseline_y_delta; + } + + find->first_char = first = i; + find->length = r.num_chars; + find->height = r.ymax - r.ymin; + find->prev_first = prev_start; + + /* now scan to find xpos */ + find->x = r.x0; + for (i=0; first+i < n; ++i) + find->x += nk_textedit_get_width(state, first, i, font); +} + +NK_INTERN void +nk_textedit_clamp(struct nk_text_edit *state) +{ + /* make the selection/cursor state valid if client altered the string */ + int n = state->string.len; + if (NK_TEXT_HAS_SELECTION(state)) { + if (state->select_start > n) state->select_start = n; + if (state->select_end > n) state->select_end = n; + /* if clamping forced them to be equal, move the cursor to match */ + if (state->select_start == state->select_end) + state->cursor = state->select_start; + } + if (state->cursor > n) state->cursor = n; +} + +NK_API void +nk_textedit_delete(struct nk_text_edit *state, int where, int len) +{ + /* delete characters while updating undo */ + nk_textedit_makeundo_delete(state, where, len); + nk_str_delete_runes(&state->string, where, len); + state->has_preferred_x = 0; +} + +NK_API void +nk_textedit_delete_selection(struct nk_text_edit *state) +{ + /* delete the section */ + nk_textedit_clamp(state); + if (NK_TEXT_HAS_SELECTION(state)) { + if (state->select_start < state->select_end) { + nk_textedit_delete(state, state->select_start, + state->select_end - state->select_start); + state->select_end = state->cursor = state->select_start; + } else { + nk_textedit_delete(state, state->select_end, + state->select_start - state->select_end); + state->select_start = state->cursor = state->select_end; + } + state->has_preferred_x = 0; + } +} + +NK_INTERN void +nk_textedit_sortselection(struct nk_text_edit *state) +{ + /* canonicalize the selection so start <= end */ + if (state->select_end < state->select_start) { + int temp = state->select_end; + state->select_end = state->select_start; + state->select_start = temp; + } +} + +NK_INTERN void +nk_textedit_move_to_first(struct nk_text_edit *state) +{ + /* move cursor to first character of selection */ + if (NK_TEXT_HAS_SELECTION(state)) { + nk_textedit_sortselection(state); + state->cursor = state->select_start; + state->select_end = state->select_start; + state->has_preferred_x = 0; + } +} + +NK_INTERN void +nk_textedit_move_to_last(struct nk_text_edit *state) +{ + /* move cursor to last character of selection */ + if (NK_TEXT_HAS_SELECTION(state)) { + nk_textedit_sortselection(state); + nk_textedit_clamp(state); + state->cursor = state->select_end; + state->select_start = state->select_end; + state->has_preferred_x = 0; + } +} + +NK_INTERN int +nk_is_word_boundary( struct nk_text_edit *state, int idx) +{ + int len; + nk_rune c; + if (idx <= 0) return 1; + if (!nk_str_at_rune(&state->string, idx, &c, &len)) return 1; + return (c == ' ' || c == '\t' ||c == 0x3000 || c == ',' || c == ';' || + c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' || + c == '|'); +} + +NK_INTERN int +nk_textedit_move_to_word_previous(struct nk_text_edit *state) +{ + int c = state->cursor - 1; + while( c >= 0 && !nk_is_word_boundary(state, c)) + --c; + + if( c < 0 ) + c = 0; + + return c; +} + +NK_INTERN int +nk_textedit_move_to_word_next(struct nk_text_edit *state) +{ + const int len = state->string.len; + int c = state->cursor+1; + while( c < len && !nk_is_word_boundary(state, c)) + ++c; + + if( c > len ) + c = len; + + return c; +} + +NK_INTERN void +nk_textedit_prep_selection_at_cursor(struct nk_text_edit *state) +{ + /* update selection and cursor to match each other */ + if (!NK_TEXT_HAS_SELECTION(state)) + state->select_start = state->select_end = state->cursor; + else state->cursor = state->select_end; +} + +NK_API int +nk_textedit_cut(struct nk_text_edit *state) +{ + /* API cut: delete selection */ + if (state->mode == NK_TEXT_EDIT_MODE_VIEW) + return 0; + if (NK_TEXT_HAS_SELECTION(state)) { + nk_textedit_delete_selection(state); /* implicitly clamps */ + state->has_preferred_x = 0; + return 1; + } + return 0; +} + +NK_API int +nk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len) +{ + /* API paste: replace existing selection with passed-in text */ + int glyphs; + const char *text = (const char *) ctext; + if (state->mode == NK_TEXT_EDIT_MODE_VIEW) return 0; + + /* if there's a selection, the paste should delete it */ + nk_textedit_clamp(state); + nk_textedit_delete_selection(state); + + /* try to insert the characters */ + glyphs = nk_utf_len(ctext, len); + if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) { + nk_textedit_makeundo_insert(state, state->cursor, glyphs); + state->cursor += len; + state->has_preferred_x = 0; + return 1; + } + /* remove the undo since we didn't actually insert the characters */ + if (state->undo.undo_point) + --state->undo.undo_point; + return 0; +} + +NK_API void +nk_textedit_text(struct nk_text_edit *state, const char *text, int total_len) +{ + nk_rune unicode; + int glyph_len; + int text_len = 0; + + NK_ASSERT(state); + NK_ASSERT(text); + if (!text || !total_len || state->mode == NK_TEXT_EDIT_MODE_VIEW) return; + + glyph_len = nk_utf_decode(text, &unicode, total_len); + while ((text_len < total_len) && glyph_len) + { + /* don't insert a backward delete, just process the event */ + if (unicode == 127) goto next; + /* can't add newline in single-line mode */ + if (unicode == '\n' && state->single_line) goto next; + /* filter incoming text */ + if (state->filter && !state->filter(state, unicode)) goto next; + + if (!NK_TEXT_HAS_SELECTION(state) && + state->cursor < state->string.len) + { + if (state->mode == NK_TEXT_EDIT_MODE_REPLACE) { + nk_textedit_makeundo_replace(state, state->cursor, 1, 1); + nk_str_delete_runes(&state->string, state->cursor, 1); + } + if (nk_str_insert_text_utf8(&state->string, state->cursor, + text+text_len, 1)) + { + ++state->cursor; + state->has_preferred_x = 0; + } + } else { + nk_textedit_delete_selection(state); /* implicitly clamps */ + if (nk_str_insert_text_utf8(&state->string, state->cursor, + text+text_len, 1)) + { + nk_textedit_makeundo_insert(state, state->cursor, 1); + ++state->cursor; + state->has_preferred_x = 0; + } + } + next: + text_len += glyph_len; + glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len); + } +} + +NK_INTERN void +nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod, + const struct nk_user_font *font, float row_height) +{ +retry: + switch (key) + { + case NK_KEY_NONE: + case NK_KEY_CTRL: + case NK_KEY_ENTER: + case NK_KEY_SHIFT: + case NK_KEY_TAB: + case NK_KEY_COPY: + case NK_KEY_CUT: + case NK_KEY_PASTE: + case NK_KEY_MAX: + default: break; + case NK_KEY_TEXT_UNDO: + nk_textedit_undo(state); + state->has_preferred_x = 0; + break; + + case NK_KEY_TEXT_REDO: + nk_textedit_redo(state); + state->has_preferred_x = 0; + break; + + case NK_KEY_TEXT_SELECT_ALL: + nk_textedit_select_all(state); + state->has_preferred_x = 0; + break; + + case NK_KEY_TEXT_INSERT_MODE: + if (state->mode == NK_TEXT_EDIT_MODE_VIEW) + state->mode = NK_TEXT_EDIT_MODE_INSERT; + break; + case NK_KEY_TEXT_REPLACE_MODE: + if (state->mode == NK_TEXT_EDIT_MODE_VIEW) + state->mode = NK_TEXT_EDIT_MODE_REPLACE; + break; + case NK_KEY_TEXT_RESET_MODE: + if (state->mode == NK_TEXT_EDIT_MODE_INSERT || + state->mode == NK_TEXT_EDIT_MODE_REPLACE) + state->mode = NK_TEXT_EDIT_MODE_VIEW; + break; + + case NK_KEY_LEFT: + if (shift_mod) { + nk_textedit_clamp(state); + nk_textedit_prep_selection_at_cursor(state); + /* move selection left */ + if (state->select_end > 0) + --state->select_end; + state->cursor = state->select_end; + state->has_preferred_x = 0; + } else { + /* if currently there's a selection, + * move cursor to start of selection */ + if (NK_TEXT_HAS_SELECTION(state)) + nk_textedit_move_to_first(state); + else if (state->cursor > 0) + --state->cursor; + state->has_preferred_x = 0; + } break; + + case NK_KEY_RIGHT: + if (shift_mod) { + nk_textedit_prep_selection_at_cursor(state); + /* move selection right */ + ++state->select_end; + nk_textedit_clamp(state); + state->cursor = state->select_end; + state->has_preferred_x = 0; + } else { + /* if currently there's a selection, + * move cursor to end of selection */ + if (NK_TEXT_HAS_SELECTION(state)) + nk_textedit_move_to_last(state); + else ++state->cursor; + nk_textedit_clamp(state); + state->has_preferred_x = 0; + } break; + + case NK_KEY_TEXT_WORD_LEFT: + if (shift_mod) { + if( !NK_TEXT_HAS_SELECTION( state ) ) + nk_textedit_prep_selection_at_cursor(state); + state->cursor = nk_textedit_move_to_word_previous(state); + state->select_end = state->cursor; + nk_textedit_clamp(state ); + } else { + if (NK_TEXT_HAS_SELECTION(state)) + nk_textedit_move_to_first(state); + else { + state->cursor = nk_textedit_move_to_word_previous(state); + nk_textedit_clamp(state ); + } + } break; + + case NK_KEY_TEXT_WORD_RIGHT: + if (shift_mod) { + if( !NK_TEXT_HAS_SELECTION( state ) ) + nk_textedit_prep_selection_at_cursor(state); + state->cursor = nk_textedit_move_to_word_next(state); + state->select_end = state->cursor; + nk_textedit_clamp(state); + } else { + if (NK_TEXT_HAS_SELECTION(state)) + nk_textedit_move_to_last(state); + else { + state->cursor = nk_textedit_move_to_word_next(state); + nk_textedit_clamp(state ); + } + } break; + + case NK_KEY_DOWN: { + struct nk_text_find find; + struct nk_text_edit_row row; + int i, sel = shift_mod; + + if (state->single_line) { + /* on windows, up&down in single-line behave like left&right */ + key = NK_KEY_RIGHT; + goto retry; + } + + if (sel) + nk_textedit_prep_selection_at_cursor(state); + else if (NK_TEXT_HAS_SELECTION(state)) + nk_textedit_move_to_last(state); + + /* compute current position of cursor point */ + nk_textedit_clamp(state); + nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, + font, row_height); + + /* now find character position down a row */ + if (find.length) + { + float x; + float goal_x = state->has_preferred_x ? state->preferred_x : find.x; + int start = find.first_char + find.length; + + state->cursor = start; + nk_textedit_layout_row(&row, state, state->cursor, row_height, font); + x = row.x0; + + for (i=0; i < row.num_chars && x < row.x1; ++i) { + float dx = nk_textedit_get_width(state, start, i, font); + x += dx; + if (x > goal_x) + break; + ++state->cursor; + } + nk_textedit_clamp(state); + + state->has_preferred_x = 1; + state->preferred_x = goal_x; + if (sel) + state->select_end = state->cursor; + } + } break; + + case NK_KEY_UP: { + struct nk_text_find find; + struct nk_text_edit_row row; + int i, sel = shift_mod; + + if (state->single_line) { + /* on windows, up&down become left&right */ + key = NK_KEY_LEFT; + goto retry; + } + + if (sel) + nk_textedit_prep_selection_at_cursor(state); + else if (NK_TEXT_HAS_SELECTION(state)) + nk_textedit_move_to_first(state); + + /* compute current position of cursor point */ + nk_textedit_clamp(state); + nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, + font, row_height); + + /* can only go up if there's a previous row */ + if (find.prev_first != find.first_char) { + /* now find character position up a row */ + float x; + float goal_x = state->has_preferred_x ? state->preferred_x : find.x; + + state->cursor = find.prev_first; + nk_textedit_layout_row(&row, state, state->cursor, row_height, font); + x = row.x0; + + for (i=0; i < row.num_chars && x < row.x1; ++i) { + float dx = nk_textedit_get_width(state, find.prev_first, i, font); + x += dx; + if (x > goal_x) + break; + ++state->cursor; + } + nk_textedit_clamp(state); + + state->has_preferred_x = 1; + state->preferred_x = goal_x; + if (sel) state->select_end = state->cursor; + } + } break; + + case NK_KEY_DEL: + if (state->mode == NK_TEXT_EDIT_MODE_VIEW) + break; + if (NK_TEXT_HAS_SELECTION(state)) + nk_textedit_delete_selection(state); + else { + int n = state->string.len; + if (state->cursor < n) + nk_textedit_delete(state, state->cursor, 1); + } + state->has_preferred_x = 0; + break; + + case NK_KEY_BACKSPACE: + if (state->mode == NK_TEXT_EDIT_MODE_VIEW) + break; + if (NK_TEXT_HAS_SELECTION(state)) + nk_textedit_delete_selection(state); + else { + nk_textedit_clamp(state); + if (state->cursor > 0) { + nk_textedit_delete(state, state->cursor-1, 1); + --state->cursor; + } + } + state->has_preferred_x = 0; + break; + + case NK_KEY_TEXT_START: + if (shift_mod) { + nk_textedit_prep_selection_at_cursor(state); + state->cursor = state->select_end = 0; + state->has_preferred_x = 0; + } else { + state->cursor = state->select_start = state->select_end = 0; + state->has_preferred_x = 0; + } + break; + + case NK_KEY_TEXT_END: + if (shift_mod) { + nk_textedit_prep_selection_at_cursor(state); + state->cursor = state->select_end = state->string.len; + state->has_preferred_x = 0; + } else { + state->cursor = state->string.len; + state->select_start = state->select_end = 0; + state->has_preferred_x = 0; + } + break; + + case NK_KEY_TEXT_LINE_START: { + if (shift_mod) { + struct nk_text_find find; + nk_textedit_clamp(state); + nk_textedit_prep_selection_at_cursor(state); + if (state->string.len && state->cursor == state->string.len) + --state->cursor; + nk_textedit_find_charpos(&find, state,state->cursor, state->single_line, + font, row_height); + state->cursor = state->select_end = find.first_char; + state->has_preferred_x = 0; + } else { + struct nk_text_find find; + if (state->string.len && state->cursor == state->string.len) + --state->cursor; + nk_textedit_clamp(state); + nk_textedit_move_to_first(state); + nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, + font, row_height); + state->cursor = find.first_char; + state->has_preferred_x = 0; + } + } break; + + case NK_KEY_TEXT_LINE_END: { + if (shift_mod) { + struct nk_text_find find; + nk_textedit_clamp(state); + nk_textedit_prep_selection_at_cursor(state); + nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, + font, row_height); + state->has_preferred_x = 0; + state->cursor = find.first_char + find.length; + if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n') + --state->cursor; + state->select_end = state->cursor; + } else { + struct nk_text_find find; + nk_textedit_clamp(state); + nk_textedit_move_to_first(state); + nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, + font, row_height); + + state->has_preferred_x = 0; + state->cursor = find.first_char + find.length; + if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n') + --state->cursor; + }} break; + } +} + +NK_INTERN void +nk_textedit_flush_redo(struct nk_text_undo_state *state) +{ + state->redo_point = NK_TEXTEDIT_UNDOSTATECOUNT; + state->redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT; +} + +NK_INTERN void +nk_textedit_discard_undo(struct nk_text_undo_state *state) +{ + /* discard the oldest entry in the undo list */ + if (state->undo_point > 0) { + /* if the 0th undo state has characters, clean those up */ + if (state->undo_rec[0].char_storage >= 0) { + int n = state->undo_rec[0].insert_length, i; + /* delete n characters from all other records */ + state->undo_char_point = (short)(state->undo_char_point - n); + NK_MEMCPY(state->undo_char, state->undo_char + n, + (nk_size)state->undo_char_point*sizeof(nk_rune)); + for (i=0; i < state->undo_point; ++i) { + if (state->undo_rec[i].char_storage >= 0) + state->undo_rec[i].char_storage = (short) + (state->undo_rec[i].char_storage - n); + } + } + --state->undo_point; + NK_MEMCPY(state->undo_rec, state->undo_rec+1, + (nk_size)((nk_size)state->undo_point * sizeof(state->undo_rec[0]))); + } +} + +NK_INTERN void +nk_textedit_discard_redo(struct nk_text_undo_state *state) +{ +/* discard the oldest entry in the redo list--it's bad if this + ever happens, but because undo & redo have to store the actual + characters in different cases, the redo character buffer can + fill up even though the undo buffer didn't */ + nk_size num; + int k = NK_TEXTEDIT_UNDOSTATECOUNT-1; + if (state->redo_point <= k) { + /* if the k'th undo state has characters, clean those up */ + if (state->undo_rec[k].char_storage >= 0) { + int n = state->undo_rec[k].insert_length, i; + /* delete n characters from all other records */ + state->redo_char_point = (short)(state->redo_char_point + n); + num = (nk_size)(NK_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point); + NK_MEMCPY(state->undo_char + state->redo_char_point, + state->undo_char + state->redo_char_point-n, num * sizeof(char)); + for (i = state->redo_point; i < k; ++i) { + if (state->undo_rec[i].char_storage >= 0) { + state->undo_rec[i].char_storage = (short) + (state->undo_rec[i].char_storage + n); + } + } + } + ++state->redo_point; + num = (nk_size)(NK_TEXTEDIT_UNDOSTATECOUNT - state->redo_point); + if (num) NK_MEMCPY(state->undo_rec + state->redo_point-1, + state->undo_rec + state->redo_point, num * sizeof(state->undo_rec[0])); + } +} + +NK_INTERN struct nk_text_undo_record* +nk_textedit_create_undo_record(struct nk_text_undo_state *state, int numchars) +{ + /* any time we create a new undo record, we discard redo*/ + nk_textedit_flush_redo(state); + + /* if we have no free records, we have to make room, + * by sliding the existing records down */ + if (state->undo_point == NK_TEXTEDIT_UNDOSTATECOUNT) + nk_textedit_discard_undo(state); + + /* if the characters to store won't possibly fit in the buffer, + * we can't undo */ + if (numchars > NK_TEXTEDIT_UNDOCHARCOUNT) { + state->undo_point = 0; + state->undo_char_point = 0; + return 0; + } + + /* if we don't have enough free characters in the buffer, + * we have to make room */ + while (state->undo_char_point + numchars > NK_TEXTEDIT_UNDOCHARCOUNT) + nk_textedit_discard_undo(state); + return &state->undo_rec[state->undo_point++]; +} + +NK_INTERN nk_rune* +nk_textedit_createundo(struct nk_text_undo_state *state, int pos, + int insert_len, int delete_len) +{ + struct nk_text_undo_record *r = nk_textedit_create_undo_record(state, insert_len); + if (r == 0) + return 0; + + r->where = pos; + r->insert_length = (short) insert_len; + r->delete_length = (short) delete_len; + + if (insert_len == 0) { + r->char_storage = -1; + return 0; + } else { + r->char_storage = state->undo_char_point; + state->undo_char_point = (short)(state->undo_char_point + insert_len); + return &state->undo_char[r->char_storage]; + } +} + +NK_API void +nk_textedit_undo(struct nk_text_edit *state) +{ + struct nk_text_undo_state *s = &state->undo; + struct nk_text_undo_record u, *r; + if (s->undo_point == 0) + return; + + /* we need to do two things: apply the undo record, and create a redo record */ + u = s->undo_rec[s->undo_point-1]; + r = &s->undo_rec[s->redo_point-1]; + r->char_storage = -1; + + r->insert_length = u.delete_length; + r->delete_length = u.insert_length; + r->where = u.where; + + if (u.delete_length) + { + /* if the undo record says to delete characters, then the redo record will + need to re-insert the characters that get deleted, so we need to store + them. + there are three cases: + - there's enough room to store the characters + - characters stored for *redoing* don't leave room for redo + - characters stored for *undoing* don't leave room for redo + if the last is true, we have to bail */ + if (s->undo_char_point + u.delete_length >= NK_TEXTEDIT_UNDOCHARCOUNT) { + /* the undo records take up too much character space; there's no space + * to store the redo characters */ + r->insert_length = 0; + } else { + int i; + /* there's definitely room to store the characters eventually */ + while (s->undo_char_point + u.delete_length > s->redo_char_point) { + /* there's currently not enough room, so discard a redo record */ + nk_textedit_discard_redo(s); + /* should never happen: */ + if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT) + return; + } + + r = &s->undo_rec[s->redo_point-1]; + r->char_storage = (short)(s->redo_char_point - u.delete_length); + s->redo_char_point = (short)(s->redo_char_point - u.delete_length); + + /* now save the characters */ + for (i=0; i < u.delete_length; ++i) + s->undo_char[r->char_storage + i] = + nk_str_rune_at(&state->string, u.where + i); + } + /* now we can carry out the deletion */ + nk_str_delete_runes(&state->string, u.where, u.delete_length); + } + + /* check type of recorded action: */ + if (u.insert_length) { + /* easy case: was a deletion, so we need to insert n characters */ + nk_str_insert_text_runes(&state->string, u.where, + &s->undo_char[u.char_storage], u.insert_length); + s->undo_char_point = (short)(s->undo_char_point - u.insert_length); + } + state->cursor = (short)(u.where + u.insert_length); + + s->undo_point--; + s->redo_point--; +} + +NK_API void +nk_textedit_redo(struct nk_text_edit *state) +{ + struct nk_text_undo_state *s = &state->undo; + struct nk_text_undo_record *u, r; + if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT) + return; + + /* we need to do two things: apply the redo record, and create an undo record */ + u = &s->undo_rec[s->undo_point]; + r = s->undo_rec[s->redo_point]; + + /* we KNOW there must be room for the undo record, because the redo record + was derived from an undo record */ + u->delete_length = r.insert_length; + u->insert_length = r.delete_length; + u->where = r.where; + u->char_storage = -1; + + if (r.delete_length) { + /* the redo record requires us to delete characters, so the undo record + needs to store the characters */ + if (s->undo_char_point + u->insert_length > s->redo_char_point) { + u->insert_length = 0; + u->delete_length = 0; + } else { + int i; + u->char_storage = s->undo_char_point; + s->undo_char_point = (short)(s->undo_char_point + u->insert_length); + + /* now save the characters */ + for (i=0; i < u->insert_length; ++i) { + s->undo_char[u->char_storage + i] = + nk_str_rune_at(&state->string, u->where + i); + } + } + nk_str_delete_runes(&state->string, r.where, r.delete_length); + } + + if (r.insert_length) { + /* easy case: need to insert n characters */ + nk_str_insert_text_runes(&state->string, r.where, + &s->undo_char[r.char_storage], r.insert_length); + } + state->cursor = r.where + r.insert_length; + + s->undo_point++; + s->redo_point++; +} + +NK_INTERN void +nk_textedit_makeundo_insert(struct nk_text_edit *state, int where, int length) +{ + nk_textedit_createundo(&state->undo, where, 0, length); +} + +NK_INTERN void +nk_textedit_makeundo_delete(struct nk_text_edit *state, int where, int length) +{ + int i; + nk_rune *p = nk_textedit_createundo(&state->undo, where, length, 0); + if (p) { + for (i=0; i < length; ++i) + p[i] = nk_str_rune_at(&state->string, where+i); + } +} + +NK_INTERN void +nk_textedit_makeundo_replace(struct nk_text_edit *state, int where, + int old_length, int new_length) +{ + int i; + nk_rune *p = nk_textedit_createundo(&state->undo, where, old_length, new_length); + if (p) { + for (i=0; i < old_length; ++i) + p[i] = nk_str_rune_at(&state->string, where+i); + } +} + +NK_INTERN void +nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type, + nk_plugin_filter filter) +{ + /* reset the state to default */ + state->undo.undo_point = 0; + state->undo.undo_char_point = 0; + state->undo.redo_point = NK_TEXTEDIT_UNDOSTATECOUNT; + state->undo.redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT; + state->select_end = state->select_start = 0; + state->cursor = 0; + state->has_preferred_x = 0; + state->preferred_x = 0; + state->cursor_at_end_of_line = 0; + state->initialized = 1; + state->single_line = (unsigned char)(type == NK_TEXT_EDIT_SINGLE_LINE); + state->mode = NK_TEXT_EDIT_MODE_VIEW; + state->filter = filter; + state->scrollbar = nk_vec2(0,0); +} + +NK_API void +nk_textedit_init_fixed(struct nk_text_edit *state, void *memory, nk_size size) +{ + NK_ASSERT(state); + NK_ASSERT(memory); + if (!state || !memory || !size) return; + NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); + nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); + nk_str_init_fixed(&state->string, memory, size); +} + +NK_API void +nk_textedit_init(struct nk_text_edit *state, struct nk_allocator *alloc, nk_size size) +{ + NK_ASSERT(state); + NK_ASSERT(alloc); + if (!state || !alloc) return; + NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); + nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); + nk_str_init(&state->string, alloc, size); +} + +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +NK_API void +nk_textedit_init_default(struct nk_text_edit *state) +{ + NK_ASSERT(state); + if (!state) return; + NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); + nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); + nk_str_init_default(&state->string); +} +#endif + +NK_API void +nk_textedit_select_all(struct nk_text_edit *state) +{ + NK_ASSERT(state); + state->select_start = 0; + state->select_end = state->string.len; +} + +NK_API void +nk_textedit_free(struct nk_text_edit *state) +{ + NK_ASSERT(state); + if (!state) return; + nk_str_free(&state->string); +} + +/* =============================================================== + * + * TEXT WIDGET + * + * ===============================================================*/ +#define nk_widget_state_reset(s)\ + if ((*(s)) & NK_WIDGET_STATE_MODIFIED)\ + (*(s)) = NK_WIDGET_STATE_INACTIVE|NK_WIDGET_STATE_MODIFIED;\ + else (*(s)) = NK_WIDGET_STATE_INACTIVE; + +struct nk_text { + struct nk_vec2 padding; + struct nk_color background; + struct nk_color text; +}; + +NK_INTERN void +nk_widget_text(struct nk_command_buffer *o, struct nk_rect b, + const char *string, int len, const struct nk_text *t, + nk_flags a, const struct nk_user_font *f) +{ + struct nk_rect label; + float text_width; + + NK_ASSERT(o); + NK_ASSERT(t); + if (!o || !t) return; + + b.h = NK_MAX(b.h, 2 * t->padding.y); + label.x = 0; label.w = 0; + label.y = b.y + t->padding.y; + label.h = NK_MIN(f->height, b.h - 2 * t->padding.y); + + text_width = f->width(f->userdata, f->height, (const char*)string, len); + text_width += (2.0f * t->padding.x); + + /* align in x-axis */ + if (a & NK_TEXT_ALIGN_LEFT) { + label.x = b.x + t->padding.x; + label.w = NK_MAX(0, b.w - 2 * t->padding.x); + } else if (a & NK_TEXT_ALIGN_CENTERED) { + label.w = NK_MAX(1, 2 * t->padding.x + (float)text_width); + label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x) - label.w) / 2); + label.x = NK_MAX(b.x + t->padding.x, label.x); + label.w = NK_MIN(b.x + b.w, label.x + label.w); + if (label.w >= label.x) label.w -= label.x; + } else if (a & NK_TEXT_ALIGN_RIGHT) { + label.x = NK_MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width)); + label.w = (float)text_width + 2 * t->padding.x; + } else return; + + /* align in y-axis */ + if (a & NK_TEXT_ALIGN_MIDDLE) { + label.y = b.y + b.h/2.0f - (float)f->height/2.0f; + label.h = NK_MAX(b.h/2.0f, b.h - (b.h/2.0f + f->height/2.0f)); + } else if (a & NK_TEXT_ALIGN_BOTTOM) { + label.y = b.y + b.h - f->height; + label.h = f->height; + } + nk_draw_text(o, label, (const char*)string, + len, f, t->background, t->text); +} + +NK_INTERN void +nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b, + const char *string, int len, const struct nk_text *t, + const struct nk_user_font *f) +{ + float width; + int glyphs = 0; + int fitting = 0; + int done = 0; + struct nk_rect line; + struct nk_text text; + NK_INTERN nk_rune seperator[] = {' '}; + + NK_ASSERT(o); + NK_ASSERT(t); + if (!o || !t) return; + + text.padding = nk_vec2(0,0); + text.background = t->background; + text.text = t->text; + + b.w = NK_MAX(b.w, 2 * t->padding.x); + b.h = NK_MAX(b.h, 2 * t->padding.y); + b.h = b.h - 2 * t->padding.y; + + line.x = b.x + t->padding.x; + line.y = b.y + t->padding.y; + line.w = b.w - 2 * t->padding.x; + line.h = 2 * t->padding.y + f->height; + + fitting = nk_text_clamp(f, string, len, line.w, &glyphs, &width, seperator,NK_LEN(seperator)); + while (done < len) { + if (!fitting || line.y + line.h >= (b.y + b.h)) break; + nk_widget_text(o, line, &string[done], fitting, &text, NK_TEXT_LEFT, f); + done += fitting; + line.y += f->height + 2 * t->padding.y; + fitting = nk_text_clamp(f, &string[done], len - done, line.w, &glyphs, &width, seperator,NK_LEN(seperator)); + } +} + +/* =============================================================== + * + * BUTTON + * + * ===============================================================*/ +NK_INTERN void +nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type, + struct nk_rect content, struct nk_color background, struct nk_color foreground, + float border_width, const struct nk_user_font *font) +{ + switch (type) { + case NK_SYMBOL_X: + case NK_SYMBOL_UNDERSCORE: + case NK_SYMBOL_PLUS: + case NK_SYMBOL_MINUS: { + /* single character text symbol */ + const char *X = (type == NK_SYMBOL_X) ? "x": + (type == NK_SYMBOL_UNDERSCORE) ? "_": + (type == NK_SYMBOL_PLUS) ? "+": "-"; + struct nk_text text; + text.padding = nk_vec2(0,0); + text.background = background; + text.text = foreground; + nk_widget_text(out, content, X, 1, &text, NK_TEXT_CENTERED, font); + } break; + case NK_SYMBOL_CIRCLE_SOLID: + case NK_SYMBOL_CIRCLE_OUTLINE: + case NK_SYMBOL_RECT_SOLID: + case NK_SYMBOL_RECT_OUTLINE: { + /* simple empty/filled shapes */ + if (type == NK_SYMBOL_RECT_SOLID || type == NK_SYMBOL_RECT_OUTLINE) { + nk_fill_rect(out, content, 0, foreground); + if (type == NK_SYMBOL_RECT_OUTLINE) + nk_fill_rect(out, nk_shrink_rect(content, border_width), 0, background); + } else { + nk_fill_circle(out, content, foreground); + if (type == NK_SYMBOL_CIRCLE_OUTLINE) + nk_fill_circle(out, nk_shrink_rect(content, 1), background); + } + } break; + case NK_SYMBOL_TRIANGLE_UP: + case NK_SYMBOL_TRIANGLE_DOWN: + case NK_SYMBOL_TRIANGLE_LEFT: + case NK_SYMBOL_TRIANGLE_RIGHT: { + enum nk_heading heading; + struct nk_vec2 points[3]; + heading = (type == NK_SYMBOL_TRIANGLE_RIGHT) ? NK_RIGHT : + (type == NK_SYMBOL_TRIANGLE_LEFT) ? NK_LEFT: + (type == NK_SYMBOL_TRIANGLE_UP) ? NK_UP: NK_DOWN; + nk_triangle_from_direction(points, content, 0, 0, heading); + nk_fill_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y, + points[2].x, points[2].y, foreground); + } break; + default: + case NK_SYMBOL_NONE: + case NK_SYMBOL_MAX: break; + } +} + +NK_INTERN int +nk_button_behavior(nk_flags *state, struct nk_rect r, + const struct nk_input *i, enum nk_button_behavior behavior) +{ + int ret = 0; + nk_widget_state_reset(state); + if (!i) return 0; + if (nk_input_is_mouse_hovering_rect(i, r)) { + *state = NK_WIDGET_STATE_HOVERED; + if (nk_input_is_mouse_down(i, NK_BUTTON_LEFT)) + *state = NK_WIDGET_STATE_ACTIVE; + if (nk_input_has_mouse_click_in_rect(i, NK_BUTTON_LEFT, r)) { + ret = (behavior != NK_BUTTON_DEFAULT) ? + nk_input_is_mouse_down(i, NK_BUTTON_LEFT): +#ifdef NK_BUTTON_TRIGGER_ON_RELEASE + nk_input_is_mouse_released(i, NK_BUTTON_LEFT); +#else + nk_input_is_mouse_pressed(i, NK_BUTTON_LEFT); +#endif + } + } + if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(i, r)) + *state |= NK_WIDGET_STATE_ENTERED; + else if (nk_input_is_mouse_prev_hovering_rect(i, r)) + *state |= NK_WIDGET_STATE_LEFT; + return ret; +} + +NK_INTERN const struct nk_style_item* +nk_draw_button(struct nk_command_buffer *out, + const struct nk_rect *bounds, nk_flags state, + const struct nk_style_button *style) +{ + const struct nk_style_item *background; + if (state & NK_WIDGET_STATE_HOVER) + background = &style->hover; + else if (state & NK_WIDGET_STATE_ACTIVED) + background = &style->active; + else background = &style->normal; + + if (background->type == NK_STYLE_ITEM_IMAGE) { + nk_draw_image(out, *bounds, &background->data.image, nk_white); + } else { + nk_fill_rect(out, *bounds, style->rounding, background->data.color); + nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); + } + return background; +} + +NK_INTERN int +nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, + const struct nk_style_button *style, const struct nk_input *in, + enum nk_button_behavior behavior, struct nk_rect *content) +{ + struct nk_rect bounds; + NK_ASSERT(style); + NK_ASSERT(state); + NK_ASSERT(out); + if (!out || !style) + return nk_false; + + /* calculate button content space */ + content->x = r.x + style->padding.x + style->border + style->rounding; + content->y = r.y + style->padding.y + style->border + style->rounding; + content->w = r.w - (2 * style->padding.x + style->border + style->rounding*2); + content->h = r.h - (2 * style->padding.y + style->border + style->rounding*2); + + /* execute button behavior */ + bounds.x = r.x - style->touch_padding.x; + bounds.y = r.y - style->touch_padding.y; + bounds.w = r.w + 2 * style->touch_padding.x; + bounds.h = r.h + 2 * style->touch_padding.y; + return nk_button_behavior(state, bounds, in, behavior); +} + +NK_INTERN void +nk_draw_button_text(struct nk_command_buffer *out, + const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, + const struct nk_style_button *style, const char *txt, int len, + nk_flags text_alignment, const struct nk_user_font *font) +{ + struct nk_text text; + const struct nk_style_item *background; + background = nk_draw_button(out, bounds, state, style); + + /* select correct colors/images */ + if (background->type == NK_STYLE_ITEM_COLOR) + text.background = background->data.color; + else text.background = style->text_background; + if (state & NK_WIDGET_STATE_HOVER) + text.text = style->text_hover; + else if (state & NK_WIDGET_STATE_ACTIVED) + text.text = style->text_active; + else text.text = style->text_normal; + + text.padding = nk_vec2(0,0); + nk_widget_text(out, *content, txt, len, &text, text_alignment, font); +} + +NK_INTERN int +nk_do_button_text(nk_flags *state, + struct nk_command_buffer *out, struct nk_rect bounds, + const char *string, int len, nk_flags align, enum nk_button_behavior behavior, + const struct nk_style_button *style, const struct nk_input *in, + const struct nk_user_font *font) +{ + struct nk_rect content; + int ret = nk_false; + + NK_ASSERT(state); + NK_ASSERT(style); + NK_ASSERT(out); + NK_ASSERT(string); + NK_ASSERT(font); + if (!out || !style || !font || !string) + return nk_false; + + ret = nk_do_button(state, out, bounds, style, in, behavior, &content); + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_button_text(out, &bounds, &content, *state, style, string, len, align, font); + if (style->draw_end) style->draw_end(out, style->userdata); + return ret; +} + +NK_INTERN void +nk_draw_button_symbol(struct nk_command_buffer *out, + const struct nk_rect *bounds, const struct nk_rect *content, + nk_flags state, const struct nk_style_button *style, + enum nk_symbol_type type, const struct nk_user_font *font) +{ + struct nk_color sym, bg; + const struct nk_style_item *background; + + /* select correct colors/images */ + background = nk_draw_button(out, bounds, state, style); + if (background->type == NK_STYLE_ITEM_COLOR) + bg = background->data.color; + else bg = style->text_background; + + if (state & NK_WIDGET_STATE_HOVER) + sym = style->text_hover; + else if (state & NK_WIDGET_STATE_ACTIVED) + sym = style->text_active; + else sym = style->text_normal; + nk_draw_symbol(out, type, *content, bg, sym, 1, font); +} + +NK_INTERN int +nk_do_button_symbol(nk_flags *state, + struct nk_command_buffer *out, struct nk_rect bounds, + enum nk_symbol_type symbol, enum nk_button_behavior behavior, + const struct nk_style_button *style, const struct nk_input *in, + const struct nk_user_font *font) +{ + int ret; + struct nk_rect content; + + NK_ASSERT(state); + NK_ASSERT(style); + NK_ASSERT(font); + NK_ASSERT(out); + if (!out || !style || !font || !state) + return nk_false; + + ret = nk_do_button(state, out, bounds, style, in, behavior, &content); + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_button_symbol(out, &bounds, &content, *state, style, symbol, font); + if (style->draw_end) style->draw_end(out, style->userdata); + return ret; +} + +NK_INTERN void +nk_draw_button_image(struct nk_command_buffer *out, + const struct nk_rect *bounds, const struct nk_rect *content, + nk_flags state, const struct nk_style_button *style, const struct nk_image *img) +{ + nk_draw_button(out, bounds, state, style); + nk_draw_image(out, *content, img, nk_white); +} + +NK_INTERN int +nk_do_button_image(nk_flags *state, + struct nk_command_buffer *out, struct nk_rect bounds, + struct nk_image img, enum nk_button_behavior b, + const struct nk_style_button *style, const struct nk_input *in) +{ + int ret; + struct nk_rect content; + + NK_ASSERT(state); + NK_ASSERT(style); + NK_ASSERT(out); + if (!out || !style || !state) + return nk_false; + + ret = nk_do_button(state, out, bounds, style, in, b, &content); + content.x += style->image_padding.x; + content.y += style->image_padding.y; + content.w -= 2 * style->image_padding.x; + content.h -= 2 * style->image_padding.y; + + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_button_image(out, &bounds, &content, *state, style, &img); + if (style->draw_end) style->draw_end(out, style->userdata); + return ret; +} + +NK_INTERN void +nk_draw_button_text_symbol(struct nk_command_buffer *out, + const struct nk_rect *bounds, const struct nk_rect *label, + const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style, + const char *str, int len, enum nk_symbol_type type, + const struct nk_user_font *font) +{ + struct nk_color sym; + struct nk_text text; + const struct nk_style_item *background; + + /* select correct background colors/images */ + background = nk_draw_button(out, bounds, state, style); + if (background->type == NK_STYLE_ITEM_COLOR) + text.background = background->data.color; + else text.background = style->text_background; + + /* select correct text colors */ + if (state & NK_WIDGET_STATE_HOVER) { + sym = style->text_hover; + text.text = style->text_hover; + } else if (state & NK_WIDGET_STATE_ACTIVED) { + sym = style->text_active; + text.text = style->text_active; + } else { + sym = style->text_normal; + text.text = style->text_normal; + } + + text.padding = nk_vec2(0,0); + nk_draw_symbol(out, type, *symbol, style->text_background, sym, 0, font); + nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font); +} + +NK_INTERN int +nk_do_button_text_symbol(nk_flags *state, + struct nk_command_buffer *out, struct nk_rect bounds, + enum nk_symbol_type symbol, const char *str, int len, nk_flags align, + enum nk_button_behavior behavior, const struct nk_style_button *style, + const struct nk_user_font *font, const struct nk_input *in) +{ + int ret; + struct nk_rect tri = {0,0,0,0}; + struct nk_rect content; + + NK_ASSERT(style); + NK_ASSERT(out); + NK_ASSERT(font); + if (!out || !style || !font) + return nk_false; + + ret = nk_do_button(state, out, bounds, style, in, behavior, &content); + tri.y = content.y + (content.h/2) - font->height/2; + tri.w = font->height; tri.h = font->height; + if (align & NK_TEXT_ALIGN_LEFT) { + tri.x = (content.x + content.w) - (2 * style->padding.x + tri.w); + tri.x = NK_MAX(tri.x, 0); + } else tri.x = content.x + 2 * style->padding.x; + + /* draw button */ + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_button_text_symbol(out, &bounds, &content, &tri, + *state, style, str, len, symbol, font); + if (style->draw_end) style->draw_end(out, style->userdata); + return ret; +} + +NK_INTERN void +nk_draw_button_text_image(struct nk_command_buffer *out, + const struct nk_rect *bounds, const struct nk_rect *label, + const struct nk_rect *image, nk_flags state, const struct nk_style_button *style, + const char *str, int len, const struct nk_user_font *font, + const struct nk_image *img) +{ + struct nk_text text; + const struct nk_style_item *background; + background = nk_draw_button(out, bounds, state, style); + + /* select correct colors */ + if (background->type == NK_STYLE_ITEM_COLOR) + text.background = background->data.color; + else text.background = style->text_background; + if (state & NK_WIDGET_STATE_HOVER) + text.text = style->text_hover; + else if (state & NK_WIDGET_STATE_ACTIVED) + text.text = style->text_active; + else text.text = style->text_normal; + + text.padding = nk_vec2(0,0); + nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font); + nk_draw_image(out, *image, img, nk_white); +} + +NK_INTERN int +nk_do_button_text_image(nk_flags *state, + struct nk_command_buffer *out, struct nk_rect bounds, + struct nk_image img, const char* str, int len, nk_flags align, + enum nk_button_behavior behavior, const struct nk_style_button *style, + const struct nk_user_font *font, const struct nk_input *in) +{ + int ret; + struct nk_rect icon; + struct nk_rect content; + + NK_ASSERT(style); + NK_ASSERT(state); + NK_ASSERT(font); + NK_ASSERT(out); + if (!out || !font || !style || !str) + return nk_false; + + ret = nk_do_button(state, out, bounds, style, in, behavior, &content); + icon.y = bounds.y + style->padding.y; + icon.w = icon.h = bounds.h - 2 * style->padding.y; + if (align & NK_TEXT_ALIGN_LEFT) { + icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w); + icon.x = NK_MAX(icon.x, 0); + } else icon.x = bounds.x + 2 * style->padding.x; + + icon.x += style->image_padding.x; + icon.y += style->image_padding.y; + icon.w -= 2 * style->image_padding.x; + icon.h -= 2 * style->image_padding.y; + + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_button_text_image(out, &bounds, &content, &icon, *state, style, str, len, font, &img); + if (style->draw_end) style->draw_end(out, style->userdata); + return ret; +} + +/* =============================================================== + * + * TOGGLE + * + * ===============================================================*/ +enum nk_toggle_type { + NK_TOGGLE_CHECK, + NK_TOGGLE_OPTION +}; + +NK_INTERN int +nk_toggle_behavior(const struct nk_input *in, struct nk_rect select, + nk_flags *state, int active) +{ + nk_widget_state_reset(state); + if (nk_button_behavior(state, select, in, NK_BUTTON_DEFAULT)) { + *state = NK_WIDGET_STATE_ACTIVE; + active = !active; + } + if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, select)) + *state |= NK_WIDGET_STATE_ENTERED; + else if (nk_input_is_mouse_prev_hovering_rect(in, select)) + *state |= NK_WIDGET_STATE_LEFT; + return active; +} + +NK_INTERN void +nk_draw_checkbox(struct nk_command_buffer *out, + nk_flags state, const struct nk_style_toggle *style, int active, + const struct nk_rect *label, const struct nk_rect *selector, + const struct nk_rect *cursors, const char *string, int len, + const struct nk_user_font *font) +{ + const struct nk_style_item *background; + const struct nk_style_item *cursor; + struct nk_text text; + + /* select correct colors/images */ + if (state & NK_WIDGET_STATE_HOVER) { + background = &style->hover; + cursor = &style->cursor_hover; + text.text = style->text_hover; + } else if (state & NK_WIDGET_STATE_ACTIVED) { + background = &style->hover; + cursor = &style->cursor_hover; + text.text = style->text_active; + } else { + background = &style->normal; + cursor = &style->cursor_normal; + text.text = style->text_normal; + } + + /* draw background and cursor */ + if (background->type == NK_STYLE_ITEM_COLOR) { + nk_fill_rect(out, *selector, 0, style->border_color); + nk_fill_rect(out, nk_shrink_rect(*selector, style->border), 0, background->data.color); + } else nk_draw_image(out, *selector, &background->data.image, nk_white); + if (active) { + if (cursor->type == NK_STYLE_ITEM_IMAGE) + nk_draw_image(out, *cursors, &cursor->data.image, nk_white); + else nk_fill_rect(out, *cursors, 0, cursor->data.color); + } + + text.padding.x = 0; + text.padding.y = 0; + text.background = style->text_background; + nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font); +} + +NK_INTERN void +nk_draw_option(struct nk_command_buffer *out, + nk_flags state, const struct nk_style_toggle *style, int active, + const struct nk_rect *label, const struct nk_rect *selector, + const struct nk_rect *cursors, const char *string, int len, + const struct nk_user_font *font) +{ + const struct nk_style_item *background; + const struct nk_style_item *cursor; + struct nk_text text; + + /* select correct colors/images */ + if (state & NK_WIDGET_STATE_HOVER) { + background = &style->hover; + cursor = &style->cursor_hover; + text.text = style->text_hover; + } else if (state & NK_WIDGET_STATE_ACTIVED) { + background = &style->hover; + cursor = &style->cursor_hover; + text.text = style->text_active; + } else { + background = &style->normal; + cursor = &style->cursor_normal; + text.text = style->text_normal; + } + + /* draw background and cursor */ + if (background->type == NK_STYLE_ITEM_COLOR) { + nk_fill_circle(out, *selector, style->border_color); + nk_fill_circle(out, nk_shrink_rect(*selector, style->border), background->data.color); + } else nk_draw_image(out, *selector, &background->data.image, nk_white); + if (active) { + if (cursor->type == NK_STYLE_ITEM_IMAGE) + nk_draw_image(out, *cursors, &cursor->data.image, nk_white); + else nk_fill_circle(out, *cursors, cursor->data.color); + } + + text.padding.x = 0; + text.padding.y = 0; + text.background = style->text_background; + nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font); +} + +NK_INTERN int +nk_do_toggle(nk_flags *state, + struct nk_command_buffer *out, struct nk_rect r, + int *active, const char *str, int len, enum nk_toggle_type type, + const struct nk_style_toggle *style, const struct nk_input *in, + const struct nk_user_font *font) +{ + int was_active; + struct nk_rect bounds; + struct nk_rect select; + struct nk_rect cursor; + struct nk_rect label; + + NK_ASSERT(style); + NK_ASSERT(out); + NK_ASSERT(font); + if (!out || !style || !font || !active) + return 0; + + r.w = NK_MAX(r.w, font->height + 2 * style->padding.x); + r.h = NK_MAX(r.h, font->height + 2 * style->padding.y); + + /* add additional touch padding for touch screen devices */ + bounds.x = r.x - style->touch_padding.x; + bounds.y = r.y - style->touch_padding.y; + bounds.w = r.w + 2 * style->touch_padding.x; + bounds.h = r.h + 2 * style->touch_padding.y; + + /* calculate the selector space */ + select.w = font->height; + select.h = select.w; + select.y = r.y + r.h/2.0f - select.h/2.0f; + select.x = r.x; + + /* calculate the bounds of the cursor inside the selector */ + cursor.x = select.x + style->padding.x + style->border; + cursor.y = select.y + style->padding.y + style->border; + cursor.w = select.w - (2 * style->padding.x + 2 * style->border); + cursor.h = select.h - (2 * style->padding.y + 2 * style->border); + + /* label behind the selector */ + label.x = select.x + select.w + style->spacing; + label.y = select.y; + label.w = NK_MAX(r.x + r.w, label.x) - label.x; + label.h = select.w; + + /* update selector */ + was_active = *active; + *active = nk_toggle_behavior(in, bounds, state, *active); + + /* draw selector */ + if (style->draw_begin) + style->draw_begin(out, style->userdata); + if (type == NK_TOGGLE_CHECK) { + nk_draw_checkbox(out, *state, style, *active, &label, &select, &cursor, str, len, font); + } else { + nk_draw_option(out, *state, style, *active, &label, &select, &cursor, str, len, font); + } + if (style->draw_end) + style->draw_end(out, style->userdata); + return (was_active != *active); +} + +/* =============================================================== + * + * SELECTABLE + * + * ===============================================================*/ +NK_INTERN void +nk_draw_selectable(struct nk_command_buffer *out, + nk_flags state, const struct nk_style_selectable *style, int active, + const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img, + const char *string, int len, nk_flags align, const struct nk_user_font *font) +{ + const struct nk_style_item *background; + struct nk_text text; + text.padding = style->padding; + + /* select correct colors/images */ + if (!active) { + if (state & NK_WIDGET_STATE_ACTIVED) { + background = &style->pressed; + text.text = style->text_pressed; + } else if (state & NK_WIDGET_STATE_HOVER) { + background = &style->hover; + text.text = style->text_hover; + } else { + background = &style->normal; + text.text = style->text_normal; + } + } else { + if (state & NK_WIDGET_STATE_ACTIVED) { + background = &style->pressed_active; + text.text = style->text_pressed_active; + } else if (state & NK_WIDGET_STATE_HOVER) { + background = &style->hover_active; + text.text = style->text_hover_active; + } else { + background = &style->normal_active; + text.text = style->text_normal_active; + } + } + + + /* draw selectable background and text */ + if (background->type == NK_STYLE_ITEM_IMAGE) { + nk_draw_image(out, *bounds, &background->data.image, nk_white); + text.background = nk_rgba(0,0,0,0); + } else { + nk_fill_rect(out, *bounds, style->rounding, background->data.color); + text.background = background->data.color; + } + if (img && icon) nk_draw_image(out, *icon, img, nk_white); + nk_widget_text(out, *bounds, string, len, &text, align, font); +} + +NK_INTERN int +nk_do_selectable(nk_flags *state, struct nk_command_buffer *out, + struct nk_rect bounds, const char *str, int len, nk_flags align, int *value, + const struct nk_style_selectable *style, const struct nk_input *in, + const struct nk_user_font *font) +{ + int old_value; + struct nk_rect touch; + + NK_ASSERT(state); + NK_ASSERT(out); + NK_ASSERT(str); + NK_ASSERT(len); + NK_ASSERT(value); + NK_ASSERT(style); + NK_ASSERT(font); + + if (!state || !out || !str || !len || !value || !style || !font) return 0; + old_value = *value; + + /* remove padding */ + touch.x = bounds.x - style->touch_padding.x; + touch.y = bounds.y - style->touch_padding.y; + touch.w = bounds.w + style->touch_padding.x * 2; + touch.h = bounds.h + style->touch_padding.y * 2; + + /* update button */ + if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT)) + *value = !(*value); + + /* draw selectable */ + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_selectable(out, *state, style, *value, &bounds, 0,0, str, len, align, font); + if (style->draw_end) style->draw_end(out, style->userdata); + return old_value != *value; +} + +NK_INTERN int +nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out, + struct nk_rect bounds, const char *str, int len, nk_flags align, int *value, + const struct nk_image *img, const struct nk_style_selectable *style, + const struct nk_input *in, const struct nk_user_font *font) +{ + int old_value; + struct nk_rect touch; + struct nk_rect icon; + + NK_ASSERT(state); + NK_ASSERT(out); + NK_ASSERT(str); + NK_ASSERT(len); + NK_ASSERT(value); + NK_ASSERT(style); + NK_ASSERT(font); + + if (!state || !out || !str || !len || !value || !style || !font) return 0; + old_value = *value; + + /* toggle behavior */ + touch.x = bounds.x - style->touch_padding.x; + touch.y = bounds.y - style->touch_padding.y; + touch.w = bounds.w + style->touch_padding.x * 2; + touch.h = bounds.h + style->touch_padding.y * 2; + if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT)) + *value = !(*value); + + icon.y = bounds.y + style->padding.y; + icon.w = icon.h = bounds.h - 2 * style->padding.y; + if (align & NK_TEXT_ALIGN_LEFT) { + icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w); + icon.x = NK_MAX(icon.x, 0); + } else icon.x = bounds.x + 2 * style->padding.x; + + icon.x += style->image_padding.x; + icon.y += style->image_padding.y; + icon.w -= 2 * style->image_padding.x; + icon.h -= 2 * style->image_padding.y; + + /* draw selectable */ + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_selectable(out, *state, style, *value, &bounds, &icon, img, str, len, align, font); + if (style->draw_end) style->draw_end(out, style->userdata); + return old_value != *value; +} + + +/* =============================================================== + * + * SLIDER + * + * ===============================================================*/ +NK_INTERN float +nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor, + struct nk_rect *visual_cursor, struct nk_input *in, + struct nk_rect bounds, float slider_min, float slider_max, float slider_value, + float slider_step, float slider_steps) +{ + int left_mouse_down; + int left_mouse_click_in_cursor; + + /* check if visual cursor is being dragged */ + nk_widget_state_reset(state); + left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down; + left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in, + NK_BUTTON_LEFT, *visual_cursor, nk_true); + + if (left_mouse_down && left_mouse_click_in_cursor) + { + float ratio = 0; + const float d = in->mouse.pos.x - (visual_cursor->x+visual_cursor->w*0.5f); + const float pxstep = bounds.w / slider_steps; + + /* only update value if the next slider step is reached */ + *state = NK_WIDGET_STATE_ACTIVE; + if (NK_ABS(d) >= pxstep) { + const float steps = (float)((int)(NK_ABS(d) / pxstep)); + slider_value += (d > 0) ? (slider_step*steps) : -(slider_step*steps); + slider_value = NK_CLAMP(slider_min, slider_value, slider_max); + ratio = (slider_value - slider_min)/slider_step; + logical_cursor->x = bounds.x + (logical_cursor->w * ratio); + in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = logical_cursor->x; + } + } + + /* slider widget state */ + if (nk_input_is_mouse_hovering_rect(in, bounds)) + *state = NK_WIDGET_STATE_HOVERED; + if (*state & NK_WIDGET_STATE_HOVER && + !nk_input_is_mouse_prev_hovering_rect(in, bounds)) + *state |= NK_WIDGET_STATE_ENTERED; + else if (nk_input_is_mouse_prev_hovering_rect(in, bounds)) + *state |= NK_WIDGET_STATE_LEFT; + return slider_value; +} + +NK_INTERN void +nk_draw_slider(struct nk_command_buffer *out, nk_flags state, + const struct nk_style_slider *style, const struct nk_rect *bounds, + const struct nk_rect *visual_cursor, float min, float value, float max) +{ + struct nk_rect fill; + struct nk_rect bar; + const struct nk_style_item *background; + + /* select correct slider images/colors */ + struct nk_color bar_color; + const struct nk_style_item *cursor; + + NK_UNUSED(min); + NK_UNUSED(max); + NK_UNUSED(value); + + if (state & NK_WIDGET_STATE_ACTIVED) { + background = &style->active; + bar_color = style->bar_active; + cursor = &style->cursor_active; + } else if (state & NK_WIDGET_STATE_HOVER) { + background = &style->hover; + bar_color = style->bar_hover; + cursor = &style->cursor_hover; + } else { + background = &style->normal; + bar_color = style->bar_normal; + cursor = &style->cursor_normal; + } + + /* calculate slider background bar */ + bar.x = bounds->x; + bar.y = (visual_cursor->y + visual_cursor->h/2) - bounds->h/12; + bar.w = bounds->w; + bar.h = bounds->h/6; + + /* filled background bar style */ + fill.w = (visual_cursor->x + (visual_cursor->w/2.0f)) - bar.x; + fill.x = bar.x; + fill.y = bar.y; + fill.h = bar.h; + + /* draw background */ + if (background->type == NK_STYLE_ITEM_IMAGE) { + nk_draw_image(out, *bounds, &background->data.image, nk_white); + } else { + nk_fill_rect(out, *bounds, style->rounding, background->data.color); + nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); + } + + /* draw slider bar */ + nk_fill_rect(out, bar, style->rounding, bar_color); + nk_fill_rect(out, fill, style->rounding, style->bar_filled); + + /* draw cursor */ + if (cursor->type == NK_STYLE_ITEM_IMAGE) + nk_draw_image(out, *visual_cursor, &cursor->data.image, nk_white); + else nk_fill_circle(out, *visual_cursor, cursor->data.color); +} + +NK_INTERN float +nk_do_slider(nk_flags *state, + struct nk_command_buffer *out, struct nk_rect bounds, + float min, float val, float max, float step, + const struct nk_style_slider *style, struct nk_input *in, + const struct nk_user_font *font) +{ + float slider_range; + float slider_min; + float slider_max; + float slider_value; + float slider_steps; + float cursor_offset; + + struct nk_rect visual_cursor; + struct nk_rect logical_cursor; + + NK_ASSERT(style); + NK_ASSERT(out); + if (!out || !style) + return 0; + + /* remove padding from slider bounds */ + bounds.x = bounds.x + style->padding.x; + bounds.y = bounds.y + style->padding.y; + bounds.h = NK_MAX(bounds.h, 2*style->padding.y); + bounds.w = NK_MAX(bounds.w, 2*style->padding.x + style->cursor_size.x); + bounds.w -= 2 * style->padding.x; + bounds.h -= 2 * style->padding.y; + + /* optional buttons */ + if (style->show_buttons) { + nk_flags ws; + struct nk_rect button; + button.y = bounds.y; + button.w = bounds.h; + button.h = bounds.h; + + /* decrement button */ + button.x = bounds.x; + if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, NK_BUTTON_DEFAULT, + &style->dec_button, in, font)) + val -= step; + + /* increment button */ + button.x = (bounds.x + bounds.w) - button.w; + if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, NK_BUTTON_DEFAULT, + &style->inc_button, in, font)) + val += step; + + bounds.x = bounds.x + button.w + style->spacing.x; + bounds.w = bounds.w - (2*button.w + 2*style->spacing.x); + } + + /* remove one cursor size to support visual cursor */ + bounds.x += style->cursor_size.x*0.5f; + bounds.w -= style->cursor_size.x; + + /* make sure the provided values are correct */ + slider_max = NK_MAX(min, max); + slider_min = NK_MIN(min, max); + slider_value = NK_CLAMP(slider_min, val, slider_max); + slider_range = slider_max - slider_min; + slider_steps = slider_range / step; + cursor_offset = (slider_value - slider_min) / step; + + /* calculate cursor + Basically you have two cursors. One for visual representation and interaction + and one for updating the actual cursor value. */ + logical_cursor.h = bounds.h; + logical_cursor.w = bounds.w / slider_steps; + logical_cursor.x = bounds.x + (logical_cursor.w * cursor_offset); + logical_cursor.y = bounds.y; + + visual_cursor.h = style->cursor_size.y; + visual_cursor.w = style->cursor_size.x; + visual_cursor.y = (bounds.y + bounds.h*0.5f) - visual_cursor.h*0.5f; + visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f; + + slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor, + in, bounds, slider_min, slider_max, slider_value, step, slider_steps); + visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f; + + /* draw slider */ + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_slider(out, *state, style, &bounds, &visual_cursor, slider_min, slider_value, slider_max); + if (style->draw_end) style->draw_end(out, style->userdata); + return slider_value; +} + +/* =============================================================== + * + * PROGRESSBAR + * + * ===============================================================*/ +NK_INTERN nk_size +nk_progress_behavior(nk_flags *state, const struct nk_input *in, + struct nk_rect r, nk_size max, nk_size value, int modifiable) +{ + nk_widget_state_reset(state); + if (in && modifiable && nk_input_is_mouse_hovering_rect(in, r)) { + int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; + int left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in, + NK_BUTTON_LEFT, r, nk_true); + + if (left_mouse_down && left_mouse_click_in_cursor) { + float ratio = NK_MAX(0, (float)(in->mouse.pos.x - r.x)) / (float)r.w; + value = (nk_size)NK_MAX(0,((float)max * ratio)); + *state = NK_WIDGET_STATE_ACTIVE; + } else *state = NK_WIDGET_STATE_HOVERED; + } + + /* set progressbar widget state */ + if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, r)) + *state |= NK_WIDGET_STATE_ENTERED; + else if (nk_input_is_mouse_prev_hovering_rect(in, r)) + *state |= NK_WIDGET_STATE_LEFT; + + if (!max) return value; + value = NK_MIN(value, max); + return value; +} + +NK_INTERN void +nk_draw_progress(struct nk_command_buffer *out, nk_flags state, + const struct nk_style_progress *style, const struct nk_rect *bounds, + const struct nk_rect *scursor, nk_size value, nk_size max) +{ + const struct nk_style_item *background; + const struct nk_style_item *cursor; + + NK_UNUSED(max); + NK_UNUSED(value); + + /* select correct colors/images to draw */ + if (state & NK_WIDGET_STATE_ACTIVED) { + background = &style->active; + cursor = &style->cursor_active; + } else if (state & NK_WIDGET_STATE_HOVER){ + background = &style->hover; + cursor = &style->cursor_hover; + } else { + background = &style->normal; + cursor = &style->cursor_normal; + } + + /* draw background */ + if (background->type == NK_STYLE_ITEM_COLOR) { + nk_fill_rect(out, *bounds, style->rounding, background->data.color); + nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); + } else nk_draw_image(out, *bounds, &background->data.image, nk_white); + + /* draw cursor */ + if (background->type == NK_STYLE_ITEM_COLOR) { + nk_fill_rect(out, *scursor, style->rounding, cursor->data.color); + nk_stroke_rect(out, *scursor, style->rounding, style->border, style->border_color); + } else nk_draw_image(out, *scursor, &cursor->data.image, nk_white); +} + +NK_INTERN nk_size +nk_do_progress(nk_flags *state, + struct nk_command_buffer *out, struct nk_rect bounds, + nk_size value, nk_size max, int modifiable, + const struct nk_style_progress *style, const struct nk_input *in) +{ + float prog_scale; + nk_size prog_value; + struct nk_rect cursor; + + NK_ASSERT(style); + NK_ASSERT(out); + if (!out || !style) return 0; + + /* calculate progressbar cursor */ + cursor.w = NK_MAX(bounds.w, 2 * style->padding.x + 2 * style->border); + cursor.h = NK_MAX(bounds.h, 2 * style->padding.y + 2 * style->border); + cursor = nk_pad_rect(bounds, nk_vec2(style->padding.x + style->border, style->padding.y + style->border)); + prog_scale = (float)value / (float)max; + cursor.w = (bounds.w - 2) * prog_scale; + + /* update progressbar */ + prog_value = NK_MIN(value, max); + prog_value = nk_progress_behavior(state, in, bounds, max, prog_value, modifiable); + + /* draw progressbar */ + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_progress(out, *state, style, &bounds, &cursor, value, max); + if (style->draw_end) style->draw_end(out, style->userdata); + return prog_value; +} + +/* =============================================================== + * + * SCROLLBAR + * + * ===============================================================*/ +NK_INTERN float +nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, + int has_scrolling, const struct nk_rect *scroll, + const struct nk_rect *cursor, const struct nk_rect *empty0, + const struct nk_rect *empty1, float scroll_offset, + float target, float scroll_step, enum nk_orientation o) +{ + nk_flags ws = 0; + int left_mouse_down; + int left_mouse_click_in_cursor; + float scroll_delta; + + nk_widget_state_reset(state); + if (!in) return scroll_offset; + + left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; + left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in, + NK_BUTTON_LEFT, *cursor, nk_true); + if (nk_input_is_mouse_hovering_rect(in, *scroll)) + *state = NK_WIDGET_STATE_HOVERED; + + scroll_delta = (o == NK_VERTICAL) ? in->mouse.scroll_delta.y: in->mouse.scroll_delta.x; + if (left_mouse_down && left_mouse_click_in_cursor) { + /* update cursor by mouse dragging */ + float pixel, delta; + *state = NK_WIDGET_STATE_ACTIVE; + if (o == NK_VERTICAL) { + float cursor_y; + pixel = in->mouse.delta.y; + delta = (pixel / scroll->h) * target; + scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->h); + cursor_y = scroll->y + ((scroll_offset/target) * scroll->h); + in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = cursor_y + cursor->h/2.0f; + } else { + float cursor_x; + pixel = in->mouse.delta.x; + delta = (pixel / scroll->w) * target; + scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->w); + cursor_x = scroll->x + ((scroll_offset/target) * scroll->w); + in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor_x + cursor->w/2.0f; + } + } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_UP) && o == NK_VERTICAL && has_scrolling)|| + nk_button_behavior(&ws, *empty0, in, NK_BUTTON_DEFAULT)) { + /* scroll page up by click on empty space or shortcut */ + if (o == NK_VERTICAL) + scroll_offset = NK_MAX(0, scroll_offset - scroll->h); + else scroll_offset = NK_MAX(0, scroll_offset - scroll->w); + } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_DOWN) && o == NK_VERTICAL && has_scrolling) || + nk_button_behavior(&ws, *empty1, in, NK_BUTTON_DEFAULT)) { + /* scroll page down by click on empty space or shortcut */ + if (o == NK_VERTICAL) + scroll_offset = NK_MIN(scroll_offset + scroll->h, target - scroll->h); + else scroll_offset = NK_MIN(scroll_offset + scroll->w, target - scroll->w); + } else if (has_scrolling) { + if ((scroll_delta < 0 || (scroll_delta > 0))) { + /* update cursor by mouse scrolling */ + scroll_offset = scroll_offset + scroll_step * (-scroll_delta); + if (o == NK_VERTICAL) + scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->h); + else scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->w); + } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_START)) { + /* update cursor to the beginning */ + if (o == NK_VERTICAL) scroll_offset = 0; + } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_END)) { + /* update cursor to the end */ + if (o == NK_VERTICAL) scroll_offset = target - scroll->h; + } + } + if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *scroll)) + *state |= NK_WIDGET_STATE_ENTERED; + else if (nk_input_is_mouse_prev_hovering_rect(in, *scroll)) + *state |= NK_WIDGET_STATE_LEFT; + return scroll_offset; +} + +NK_INTERN void +nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state, + const struct nk_style_scrollbar *style, const struct nk_rect *bounds, + const struct nk_rect *scroll) +{ + const struct nk_style_item *background; + const struct nk_style_item *cursor; + + /* select correct colors/images to draw */ + if (state & NK_WIDGET_STATE_ACTIVED) { + background = &style->active; + cursor = &style->cursor_active; + } else if (state & NK_WIDGET_STATE_HOVER) { + background = &style->hover; + cursor = &style->cursor_hover; + } else { + background = &style->normal; + cursor = &style->cursor_normal; + } + + /* draw background */ + if (background->type == NK_STYLE_ITEM_COLOR) { + nk_fill_rect(out, *bounds, style->rounding, background->data.color); + nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); + } else { + nk_draw_image(out, *bounds, &background->data.image, nk_white); + } + + /* draw cursor */ + if (background->type == NK_STYLE_ITEM_COLOR) { + nk_fill_rect(out, *scroll, style->rounding_cursor, cursor->data.color); + nk_stroke_rect(out, *scroll, style->rounding_cursor, style->border_cursor, style->cursor_border_color); + } else nk_draw_image(out, *scroll, &cursor->data.image, nk_white); +} + +NK_INTERN float +nk_do_scrollbarv(nk_flags *state, + struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, + float offset, float target, float step, float button_pixel_inc, + const struct nk_style_scrollbar *style, struct nk_input *in, + const struct nk_user_font *font) +{ + struct nk_rect empty_north; + struct nk_rect empty_south; + struct nk_rect cursor; + + float scroll_step; + float scroll_offset; + float scroll_off; + float scroll_ratio; + + NK_ASSERT(out); + NK_ASSERT(style); + NK_ASSERT(state); + if (!out || !style) return 0; + + scroll.w = NK_MAX(scroll.w, 1); + scroll.h = NK_MAX(scroll.h, 0); + if (target <= scroll.h) return 0; + + /* optional scrollbar buttons */ + if (style->show_buttons) { + nk_flags ws; + float scroll_h; + struct nk_rect button; + + button.x = scroll.x; + button.w = scroll.w; + button.h = scroll.w; + + scroll_h = NK_MAX(scroll.h - 2 * button.h,0); + scroll_step = NK_MIN(step, button_pixel_inc); + + /* decrement button */ + button.y = scroll.y; + if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, + NK_BUTTON_REPEATER, &style->dec_button, in, font)) + offset = offset - scroll_step; + + /* increment button */ + button.y = scroll.y + scroll.h - button.h; + if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, + NK_BUTTON_REPEATER, &style->inc_button, in, font)) + offset = offset + scroll_step; + + scroll.y = scroll.y + button.h; + scroll.h = scroll_h; + } + + /* calculate scrollbar constants */ + scroll_step = NK_MIN(step, scroll.h); + scroll_offset = NK_CLAMP(0, offset, target - scroll.h); + scroll_ratio = scroll.h / target; + scroll_off = scroll_offset / target; + + /* calculate scrollbar cursor bounds */ + cursor.h = NK_MAX((scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y), 0); + cursor.y = scroll.y + (scroll_off * scroll.h) + style->border + style->padding.y; + cursor.w = scroll.w - (2 * style->border + 2 * style->padding.x); + cursor.x = scroll.x + style->border + style->padding.x; + + /* calculate empty space around cursor */ + empty_north.x = scroll.x; + empty_north.y = scroll.y; + empty_north.w = scroll.w; + empty_north.h = NK_MAX(cursor.y - scroll.y, 0); + + empty_south.x = scroll.x; + empty_south.y = cursor.y + cursor.h; + empty_south.w = scroll.w; + empty_south.h = NK_MAX((scroll.y + scroll.h) - (cursor.y + cursor.h), 0); + + /* update scrollbar */ + scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor, + &empty_north, &empty_south, scroll_offset, target, scroll_step, NK_VERTICAL); + scroll_off = scroll_offset / target; + cursor.y = scroll.y + (scroll_off * scroll.h) + style->border_cursor + style->padding.y; + + /* draw scrollbar */ + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_scrollbar(out, *state, style, &scroll, &cursor); + if (style->draw_end) style->draw_end(out, style->userdata); + return scroll_offset; +} + +NK_INTERN float +nk_do_scrollbarh(nk_flags *state, + struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, + float offset, float target, float step, float button_pixel_inc, + const struct nk_style_scrollbar *style, struct nk_input *in, + const struct nk_user_font *font) +{ + struct nk_rect cursor; + struct nk_rect empty_west; + struct nk_rect empty_east; + + float scroll_step; + float scroll_offset; + float scroll_off; + float scroll_ratio; + + NK_ASSERT(out); + NK_ASSERT(style); + if (!out || !style) return 0; + + /* scrollbar background */ + scroll.h = NK_MAX(scroll.h, 1); + scroll.w = NK_MAX(scroll.w, 2 * scroll.h); + if (target <= scroll.w) return 0; + + /* optional scrollbar buttons */ + if (style->show_buttons) { + nk_flags ws; + float scroll_w; + struct nk_rect button; + button.y = scroll.y; + button.w = scroll.h; + button.h = scroll.h; + + scroll_w = scroll.w - 2 * button.w; + scroll_step = NK_MIN(step, button_pixel_inc); + + /* decrement button */ + button.x = scroll.x; + if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, + NK_BUTTON_REPEATER, &style->dec_button, in, font)) + offset = offset - scroll_step; + + /* increment button */ + button.x = scroll.x + scroll.w - button.w; + if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, + NK_BUTTON_REPEATER, &style->inc_button, in, font)) + offset = offset + scroll_step; + + scroll.x = scroll.x + button.w; + scroll.w = scroll_w; + } + + /* calculate scrollbar constants */ + scroll_step = NK_MIN(step, scroll.w); + scroll_offset = NK_CLAMP(0, offset, target - scroll.w); + scroll_ratio = scroll.w / target; + scroll_off = scroll_offset / target; + + /* calculate cursor bounds */ + cursor.w = (scroll_ratio * scroll.w) - (2*style->border + 2*style->padding.x); + cursor.x = scroll.x + (scroll_off * scroll.w) + style->border + style->padding.x; + cursor.h = scroll.h - (2 * style->border + 2 * style->padding.y); + cursor.y = scroll.y + style->border + style->padding.y; + + /* calculate empty space around cursor */ + empty_west.x = scroll.x; + empty_west.y = scroll.y; + empty_west.w = cursor.x - scroll.x; + empty_west.h = scroll.h; + + empty_east.x = cursor.x + cursor.w; + empty_east.y = scroll.y; + empty_east.w = (scroll.x + scroll.w) - (cursor.x + cursor.w); + empty_east.h = scroll.h; + + /* update scrollbar */ + scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor, + &empty_west, &empty_east, scroll_offset, target, scroll_step, NK_HORIZONTAL); + scroll_off = scroll_offset / target; + cursor.x = scroll.x + (scroll_off * scroll.w); + + /* draw scrollbar */ + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_scrollbar(out, *state, style, &scroll, &cursor); + if (style->draw_end) style->draw_end(out, style->userdata); + return scroll_offset; +} + +/* =============================================================== + * + * FILTER + * + * ===============================================================*/ +NK_API int nk_filter_default(const struct nk_text_edit *box, nk_rune unicode) +{(void)unicode;NK_UNUSED(box);return nk_true;} + +NK_API int +nk_filter_ascii(const struct nk_text_edit *box, nk_rune unicode) +{ + NK_UNUSED(box); + if (unicode > 128) return nk_false; + else return nk_true; +} + +NK_API int +nk_filter_float(const struct nk_text_edit *box, nk_rune unicode) +{ + NK_UNUSED(box); + if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-') + return nk_false; + else return nk_true; +} + +NK_API int +nk_filter_decimal(const struct nk_text_edit *box, nk_rune unicode) +{ + NK_UNUSED(box); + if ((unicode < '0' || unicode > '9') && unicode != '-') + return nk_false; + else return nk_true; +} + +NK_API int +nk_filter_hex(const struct nk_text_edit *box, nk_rune unicode) +{ + NK_UNUSED(box); + if ((unicode < '0' || unicode > '9') && + (unicode < 'a' || unicode > 'f') && + (unicode < 'A' || unicode > 'F')) + return nk_false; + else return nk_true; +} + +NK_API int +nk_filter_oct(const struct nk_text_edit *box, nk_rune unicode) +{ + NK_UNUSED(box); + if (unicode < '0' || unicode > '7') + return nk_false; + else return nk_true; +} + +NK_API int +nk_filter_binary(const struct nk_text_edit *box, nk_rune unicode) +{ + NK_UNUSED(box); + if (unicode != '0' && unicode != '1') + return nk_false; + else return nk_true; +} + +/* =============================================================== + * + * EDIT + * + * ===============================================================*/ +NK_INTERN void +nk_edit_draw_text(struct nk_command_buffer *out, + const struct nk_style_edit *style, float pos_x, float pos_y, + float x_offset, const char *text, int byte_len, float row_height, + const struct nk_user_font *font, struct nk_color background, + struct nk_color foreground, int is_selected) +{ + NK_ASSERT(out); + NK_ASSERT(font); + NK_ASSERT(style); + if (!text || !byte_len || !out || !style) return; + + {int glyph_len = 0; + nk_rune unicode = 0; + int text_len = 0; + float line_width = 0; + float glyph_width; + const char *line = text; + float line_offset = 0; + int line_count = 0; + + struct nk_text txt; + txt.padding = nk_vec2(0,0); + txt.background = background; + txt.text = foreground; + + glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len); + if (!glyph_len) return; + while ((text_len < byte_len) && glyph_len) + { + if (unicode == '\n') { + /* new line sepeator so draw previous line */ + struct nk_rect label; + label.y = pos_y + line_offset; + label.h = row_height; + label.w = line_width; + label.x = pos_x; + if (!line_count) + label.x += x_offset; + + if (is_selected) /* selection needs to draw different background color */ + nk_fill_rect(out, label, 0, background); + nk_widget_text(out, label, line, (int)((text + text_len) - line), + &txt, NK_TEXT_CENTERED, font); + + text_len++; + line_count++; + line_width = 0; + line = text + text_len; + line_offset += row_height; + glyph_len = nk_utf_decode(text + text_len, &unicode, (int)(byte_len-text_len)); + continue; + } + if (unicode == '\r') { + text_len++; + glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len); + continue; + } + glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len); + line_width += (float)glyph_width; + text_len += glyph_len; + glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len); + continue; + } + if (line_width > 0) { + /* draw last line */ + struct nk_rect label; + label.y = pos_y + line_offset; + label.h = row_height; + label.w = line_width; + label.x = pos_x; + if (!line_count) + label.x += x_offset; + + if (is_selected) + nk_fill_rect(out, label, 0, background); + nk_widget_text(out, label, line, (int)((text + text_len) - line), + &txt, NK_TEXT_LEFT, font); + }} +} + +NK_INTERN nk_flags +nk_do_edit(nk_flags *state, struct nk_command_buffer *out, + struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter, + struct nk_text_edit *edit, const struct nk_style_edit *style, + struct nk_input *in, const struct nk_user_font *font) +{ + struct nk_rect area; + nk_flags ret = 0; + float row_height; + char prev_state = 0; + char is_hovered = 0; + char select_all = 0; + char cursor_follow = 0; + struct nk_rect old_clip; + struct nk_rect clip; + + NK_ASSERT(state); + NK_ASSERT(out); + NK_ASSERT(style); + if (!state || !out || !style) + return ret; + + /* visible text area calculation */ + area.x = bounds.x + style->padding.x + style->border; + area.y = bounds.y + style->padding.y + style->border; + area.w = bounds.w - (2.0f * style->padding.x + 2 * style->border); + area.h = bounds.h - (2.0f * style->padding.y + 2 * style->border); + if (flags & NK_EDIT_MULTILINE) + area.w = NK_MAX(0, area.w - style->scrollbar_size.x); + row_height = (flags & NK_EDIT_MULTILINE)? font->height + style->row_padding: area.h; + + /* calculate clipping rectangle */ + old_clip = out->clip; + nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h); + + /* update edit state */ + prev_state = (char)edit->active; + is_hovered = (char)nk_input_is_mouse_hovering_rect(in, bounds); + if (in && in->mouse.buttons[NK_BUTTON_LEFT].clicked && in->mouse.buttons[NK_BUTTON_LEFT].down) { + edit->active = NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, + bounds.x, bounds.y, bounds.w, bounds.h); + } + + /* (de)activate text editor */ + if (!prev_state && edit->active) { + const enum nk_text_edit_type type = (flags & NK_EDIT_MULTILINE) ? + NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE; + nk_textedit_clear_state(edit, type, filter); + if (flags & NK_EDIT_ALWAYS_INSERT_MODE) + edit->mode = NK_TEXT_EDIT_MODE_INSERT; + if (flags & NK_EDIT_AUTO_SELECT) + select_all = nk_true; + if (flags & NK_EDIT_GOTO_END_ON_ACTIVATE) { + edit->cursor = edit->string.len; + in = 0; + } + } else if (!edit->active) edit->mode = NK_TEXT_EDIT_MODE_VIEW; + if (flags & NK_EDIT_READ_ONLY) + edit->mode = NK_TEXT_EDIT_MODE_VIEW; + + ret = (edit->active) ? NK_EDIT_ACTIVE: NK_EDIT_INACTIVE; + if (prev_state != edit->active) + ret |= (edit->active) ? NK_EDIT_ACTIVATED: NK_EDIT_DEACTIVATED; + + /* handle user input */ + if (edit->active && in) + { + int shift_mod = in->keyboard.keys[NK_KEY_SHIFT].down; + const float mouse_x = (in->mouse.pos.x - area.x) + edit->scrollbar.x; + const float mouse_y = (in->mouse.pos.y - area.y) + edit->scrollbar.y; + + /* mouse click handler */ + is_hovered = (char)nk_input_is_mouse_hovering_rect(in, area); + if (select_all) { + nk_textedit_select_all(edit); + } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down && + in->mouse.buttons[NK_BUTTON_LEFT].clicked) { + nk_textedit_click(edit, mouse_x, mouse_y, font, row_height); + } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down && + (in->mouse.delta.x != 0.0f || in->mouse.delta.y != 0.0f)) { + nk_textedit_drag(edit, mouse_x, mouse_y, font, row_height); + cursor_follow = nk_true; + } else if (is_hovered && in->mouse.buttons[NK_BUTTON_RIGHT].clicked && + in->mouse.buttons[NK_BUTTON_RIGHT].down) { + nk_textedit_key(edit, NK_KEY_TEXT_WORD_LEFT, nk_false, font, row_height); + nk_textedit_key(edit, NK_KEY_TEXT_WORD_RIGHT, nk_true, font, row_height); + cursor_follow = nk_true; + } + + {int i; /* keyboard input */ + int old_mode = edit->mode; + for (i = 0; i < NK_KEY_MAX; ++i) { + if (i == NK_KEY_ENTER || i == NK_KEY_TAB) continue; /* special case */ + if (nk_input_is_key_pressed(in, (enum nk_keys)i)) { + nk_textedit_key(edit, (enum nk_keys)i, shift_mod, font, row_height); + cursor_follow = nk_true; + } + } + if (old_mode != edit->mode) { + in->keyboard.text_len = 0; + }} + + /* text input */ + edit->filter = filter; + if (in->keyboard.text_len) { + nk_textedit_text(edit, in->keyboard.text, in->keyboard.text_len); + cursor_follow = nk_true; + in->keyboard.text_len = 0; + } + + /* enter key handler */ + if (nk_input_is_key_pressed(in, NK_KEY_ENTER)) { + cursor_follow = nk_true; + if (flags & NK_EDIT_CTRL_ENTER_NEWLINE && shift_mod) + nk_textedit_text(edit, "\n", 1); + else if (flags & NK_EDIT_SIG_ENTER) + ret |= NK_EDIT_COMMITED; + else nk_textedit_text(edit, "\n", 1); + } + + /* cut & copy handler */ + {int copy= nk_input_is_key_pressed(in, NK_KEY_COPY); + int cut = nk_input_is_key_pressed(in, NK_KEY_CUT); + if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD)) + { + int glyph_len; + nk_rune unicode; + const char *text; + int b = edit->select_start; + int e = edit->select_end; + + int begin = NK_MIN(b, e); + int end = NK_MAX(b, e); + text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len); + if (edit->clip.copy) + edit->clip.copy(edit->clip.userdata, text, end - begin); + if (cut && !(flags & NK_EDIT_READ_ONLY)){ + nk_textedit_cut(edit); + cursor_follow = nk_true; + } + }} + + /* paste handler */ + {int paste = nk_input_is_key_pressed(in, NK_KEY_PASTE); + if (paste && (flags & NK_EDIT_CLIPBOARD) && edit->clip.paste) { + edit->clip.paste(edit->clip.userdata, edit); + cursor_follow = nk_true; + }} + + /* tab handler */ + {int tab = nk_input_is_key_pressed(in, NK_KEY_TAB); + if (tab && (flags & NK_EDIT_ALLOW_TAB)) { + nk_textedit_text(edit, " ", 4); + cursor_follow = nk_true; + }} + } + + /* set widget state */ + if (edit->active) + *state = NK_WIDGET_STATE_ACTIVE; + else nk_widget_state_reset(state); + + if (is_hovered) + *state |= NK_WIDGET_STATE_HOVERED; + + /* DRAW EDIT */ + {const char *text = nk_str_get_const(&edit->string); + int len = nk_str_len_char(&edit->string); + + {/* select background colors/images */ + const struct nk_style_item *background; + if (*state & NK_WIDGET_STATE_ACTIVED) + background = &style->active; + else if (*state & NK_WIDGET_STATE_HOVER) + background = &style->hover; + else background = &style->normal; + + /* draw background frame */ + if (background->type == NK_STYLE_ITEM_COLOR) { + nk_stroke_rect(out, bounds, style->rounding, style->border, style->border_color); + nk_fill_rect(out, bounds, style->rounding, background->data.color); + } else nk_draw_image(out, bounds, &background->data.image, nk_white);} + + area.w = NK_MAX(0, area.w - style->cursor_size); + if (edit->active) + { + int total_lines = 1; + struct nk_vec2 text_size = nk_vec2(0,0); + + /* text pointer positions */ + const char *cursor_ptr = 0; + const char *select_begin_ptr = 0; + const char *select_end_ptr = 0; + + /* 2D pixel positions */ + struct nk_vec2 cursor_pos = nk_vec2(0,0); + struct nk_vec2 selection_offset_start = nk_vec2(0,0); + struct nk_vec2 selection_offset_end = nk_vec2(0,0); + + int selection_begin = NK_MIN(edit->select_start, edit->select_end); + int selection_end = NK_MAX(edit->select_start, edit->select_end); + + /* calculate total line count + total space + cursor/selection position */ + float line_width = 0.0f; + if (text && len) + { + /* utf8 encoding */ + float glyph_width; + int glyph_len = 0; + nk_rune unicode = 0; + int text_len = 0; + int glyphs = 0; + int row_begin = 0; + + glyph_len = nk_utf_decode(text, &unicode, len); + glyph_width = font->width(font->userdata, font->height, text, glyph_len); + line_width = 0; + + /* iterate all lines */ + while ((text_len < len) && glyph_len) + { + /* set cursor 2D position and line */ + if (!cursor_ptr && glyphs == edit->cursor) + { + int glyph_offset; + struct nk_vec2 out_offset; + struct nk_vec2 row_size; + const char *remaining; + + /* calculate 2d position */ + cursor_pos.y = (float)(total_lines-1) * row_height; + row_size = nk_text_calculate_text_bounds(font, text+row_begin, + text_len-row_begin, row_height, &remaining, + &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); + cursor_pos.x = row_size.x; + cursor_ptr = text + text_len; + } + + /* set start selection 2D position and line */ + if (!select_begin_ptr && edit->select_start != edit->select_end && + glyphs == selection_begin) + { + int glyph_offset; + struct nk_vec2 out_offset; + struct nk_vec2 row_size; + const char *remaining; + + /* calculate 2d position */ + selection_offset_start.y = (float)(NK_MAX(total_lines-1,0)) * row_height; + row_size = nk_text_calculate_text_bounds(font, text+row_begin, + text_len-row_begin, row_height, &remaining, + &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); + selection_offset_start.x = row_size.x; + select_begin_ptr = text + text_len; + } + + /* set end selection 2D position and line */ + if (!select_end_ptr && edit->select_start != edit->select_end && + glyphs == selection_end) + { + int glyph_offset; + struct nk_vec2 out_offset; + struct nk_vec2 row_size; + const char *remaining; + + /* calculate 2d position */ + selection_offset_end.y = (float)(total_lines-1) * row_height; + row_size = nk_text_calculate_text_bounds(font, text+row_begin, + text_len-row_begin, row_height, &remaining, + &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); + selection_offset_end.x = row_size.x; + select_end_ptr = text + text_len; + } + if (unicode == '\n') { + text_size.x = NK_MAX(text_size.x, line_width); + total_lines++; + line_width = 0; + text_len++; + glyphs++; + row_begin = text_len; + glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len); + glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len); + continue; + } + + glyphs++; + text_len += glyph_len; + line_width += (float)glyph_width; + + glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len); + glyph_width = font->width(font->userdata, font->height, + text+text_len, glyph_len); + continue; + } + text_size.y = (float)total_lines * row_height; + + /* handle case when cursor is at end of text buffer */ + if (!cursor_ptr && edit->cursor == edit->string.len) { + cursor_pos.x = line_width; + cursor_pos.y = text_size.y - row_height; + } + } + { + /* scrollbar */ + if (cursor_follow) + { + /* update scrollbar to follow cursor */ + if (!(flags & NK_EDIT_NO_HORIZONTAL_SCROLL)) { + /* horizontal scroll */ + const float scroll_increment = area.w * 0.25f; + if (cursor_pos.x < edit->scrollbar.x) + edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - scroll_increment); + if (cursor_pos.x >= edit->scrollbar.x + area.w) + edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x); + } else edit->scrollbar.x = 0; + + if (flags & NK_EDIT_MULTILINE) { + /* vertical scroll */ + if (cursor_pos.y < edit->scrollbar.y) + edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y - row_height); + if (cursor_pos.y >= edit->scrollbar.y + area.h) + edit->scrollbar.y = edit->scrollbar.y + row_height; + } else edit->scrollbar.y = 0; + } + + /* scrollbar widget */ + if (flags & NK_EDIT_MULTILINE) + { + nk_flags ws; + struct nk_rect scroll; + float scroll_target; + float scroll_offset; + float scroll_step; + float scroll_inc; + + scroll = area; + scroll.x = (bounds.x + bounds.w - style->border) - style->scrollbar_size.x; + scroll.w = style->scrollbar_size.x; + + scroll_offset = edit->scrollbar.y; + scroll_step = scroll.h * 0.10f; + scroll_inc = scroll.h * 0.01f; + scroll_target = text_size.y; + edit->scrollbar.y = nk_do_scrollbarv(&ws, out, scroll, 0, + scroll_offset, scroll_target, scroll_step, scroll_inc, + &style->scrollbar, in, font); + } + } + + /* draw text */ + {struct nk_color background_color; + struct nk_color text_color; + struct nk_color sel_background_color; + struct nk_color sel_text_color; + struct nk_color cursor_color; + struct nk_color cursor_text_color; + const struct nk_style_item *background; + nk_push_scissor(out, clip); + + /* select correct colors to draw */ + if (*state & NK_WIDGET_STATE_ACTIVED) { + background = &style->active; + text_color = style->text_active; + sel_text_color = style->selected_text_hover; + sel_background_color = style->selected_hover; + cursor_color = style->cursor_hover; + cursor_text_color = style->cursor_text_hover; + } else if (*state & NK_WIDGET_STATE_HOVER) { + background = &style->hover; + text_color = style->text_hover; + sel_text_color = style->selected_text_hover; + sel_background_color = style->selected_hover; + cursor_text_color = style->cursor_text_hover; + cursor_color = style->cursor_hover; + } else { + background = &style->normal; + text_color = style->text_normal; + sel_text_color = style->selected_text_normal; + sel_background_color = style->selected_normal; + cursor_color = style->cursor_normal; + cursor_text_color = style->cursor_text_normal; + } + if (background->type == NK_STYLE_ITEM_IMAGE) + background_color = nk_rgba(0,0,0,0); + else background_color = background->data.color; + + + if (edit->select_start == edit->select_end) { + /* no selection so just draw the complete text */ + const char *begin = nk_str_get_const(&edit->string); + int l = nk_str_len_char(&edit->string); + nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, + area.y - edit->scrollbar.y, 0, begin, l, row_height, font, + background_color, text_color, nk_false); + } else { + /* edit has selection so draw 1-3 text chunks */ + if (edit->select_start != edit->select_end && selection_begin > 0){ + /* draw unselected text before selection */ + const char *begin = nk_str_get_const(&edit->string); + NK_ASSERT(select_begin_ptr); + nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, + area.y - edit->scrollbar.y, 0, begin, (int)(select_begin_ptr - begin), + row_height, font, background_color, text_color, nk_false); + } + if (edit->select_start != edit->select_end) { + /* draw selected text */ + NK_ASSERT(select_begin_ptr); + if (!select_end_ptr) { + const char *begin = nk_str_get_const(&edit->string); + select_end_ptr = begin + nk_str_len_char(&edit->string); + } + nk_edit_draw_text(out, style, + area.x - edit->scrollbar.x, + area.y + selection_offset_start.y - edit->scrollbar.y, + selection_offset_start.x, + select_begin_ptr, (int)(select_end_ptr - select_begin_ptr), + row_height, font, sel_background_color, sel_text_color, nk_true); + } + if ((edit->select_start != edit->select_end && + selection_end < edit->string.len)) + { + /* draw unselected text after selected text */ + const char *begin = select_end_ptr; + const char *end = nk_str_get_const(&edit->string) + + nk_str_len_char(&edit->string); + NK_ASSERT(select_end_ptr); + nk_edit_draw_text(out, style, + area.x - edit->scrollbar.x, + area.y + selection_offset_end.y - edit->scrollbar.y, + selection_offset_end.x, + begin, (int)(end - begin), row_height, font, + background_color, text_color, nk_true); + } + } + + /* cursor */ + if (edit->select_start == edit->select_end) + { + if (edit->cursor >= nk_str_len(&edit->string) || + (cursor_ptr && *cursor_ptr == '\n')) { + /* draw cursor at end of line */ + struct nk_rect cursor; + cursor.w = style->cursor_size; + cursor.h = font->height; + cursor.x = area.x + cursor_pos.x - edit->scrollbar.x; + cursor.y = area.y + cursor_pos.y + row_height/2.0f - cursor.h/2.0f; + cursor.y -= edit->scrollbar.y; + nk_fill_rect(out, cursor, 0, cursor_color); + } else { + /* draw cursor inside text */ + int glyph_len; + struct nk_rect label; + struct nk_text txt; + + nk_rune unicode; + NK_ASSERT(cursor_ptr); + glyph_len = nk_utf_decode(cursor_ptr, &unicode, 4); + + label.x = area.x + cursor_pos.x - edit->scrollbar.x; + label.y = area.y + cursor_pos.y - edit->scrollbar.y; + label.w = font->width(font->userdata, font->height, cursor_ptr, glyph_len); + label.h = row_height; + + txt.padding = nk_vec2(0,0); + txt.background = cursor_color;; + txt.text = cursor_text_color; + nk_fill_rect(out, label, 0, cursor_color); + nk_widget_text(out, label, cursor_ptr, glyph_len, &txt, NK_TEXT_LEFT, font); + } + }} + } else { + /* not active so just draw text */ + int l = nk_str_len_char(&edit->string); + const char *begin = nk_str_get_const(&edit->string); + + const struct nk_style_item *background; + struct nk_color background_color; + struct nk_color text_color; + nk_push_scissor(out, clip); + if (*state & NK_WIDGET_STATE_ACTIVED) { + background = &style->active; + text_color = style->text_active; + } else if (*state & NK_WIDGET_STATE_HOVER) { + background = &style->hover; + text_color = style->text_hover; + } else { + background = &style->normal; + text_color = style->text_normal; + } + if (background->type == NK_STYLE_ITEM_IMAGE) + background_color = nk_rgba(0,0,0,0); + else background_color = background->data.color; + nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, + area.y - edit->scrollbar.y, 0, begin, l, row_height, font, + background_color, text_color, nk_false); + } + nk_push_scissor(out, old_clip);} + return ret; +} + +/* =============================================================== + * + * PROPERTY + * + * ===============================================================*/ +enum nk_property_status { + NK_PROPERTY_DEFAULT, + NK_PROPERTY_EDIT, + NK_PROPERTY_DRAG +}; +enum nk_property_filter { + NK_FILTER_INT, + NK_FILTER_FLOAT +}; +enum nk_property_kind { + NK_PROPERTY_INT, + NK_PROPERTY_FLOAT, + NK_PROPERTY_DOUBLE +}; +union nk_property { + int i; + float f; + double d; +}; +struct nk_property_variant { + enum nk_property_kind kind; + union nk_property value; + union nk_property min_value; + union nk_property max_value; + union nk_property step; +}; + +NK_INTERN void +nk_drag_behavior(nk_flags *state, const struct nk_input *in, + struct nk_rect drag, struct nk_property_variant *variant, + float inc_per_pixel) +{ + int left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down; + int left_mouse_click_in_cursor = in && + nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, drag, nk_true); + + nk_widget_state_reset(state); + if (nk_input_is_mouse_hovering_rect(in, drag)) + *state = NK_WIDGET_STATE_HOVERED; + + if (left_mouse_down && left_mouse_click_in_cursor) { + float delta, pixels; + pixels = in->mouse.delta.x; + delta = pixels * inc_per_pixel; + switch (variant->kind) { + default: break; + case NK_PROPERTY_INT: + variant->value.i = variant->value.i + (int)delta; + variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i); + break; + case NK_PROPERTY_FLOAT: + variant->value.f = variant->value.f + (float)delta; + variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f); + break; + case NK_PROPERTY_DOUBLE: + variant->value.d = variant->value.d + (double)delta; + variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); + break; + } + *state = NK_WIDGET_STATE_ACTIVE; + } + if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, drag)) + *state |= NK_WIDGET_STATE_ENTERED; + else if (nk_input_is_mouse_prev_hovering_rect(in, drag)) + *state |= NK_WIDGET_STATE_LEFT; +} + +NK_INTERN void +nk_property_behavior(nk_flags *ws, const struct nk_input *in, + struct nk_rect property, struct nk_rect label, struct nk_rect edit, + struct nk_rect empty, int *state, struct nk_property_variant *variant, + float inc_per_pixel) +{ + if (in && *state == NK_PROPERTY_DEFAULT) { + if (nk_button_behavior(ws, edit, in, NK_BUTTON_DEFAULT)) + *state = NK_PROPERTY_EDIT; + else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, label, nk_true)) + *state = NK_PROPERTY_DRAG; + else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, empty, nk_true)) + *state = NK_PROPERTY_DRAG; + } + if (*state == NK_PROPERTY_DRAG) { + nk_drag_behavior(ws, in, property, variant, inc_per_pixel); + if (!(*ws & NK_WIDGET_STATE_ACTIVED)) *state = NK_PROPERTY_DEFAULT; + } +} + +NK_INTERN void +nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style, + const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state, + const char *name, int len, const struct nk_user_font *font) +{ + struct nk_text text; + const struct nk_style_item *background; + + /* select correct background and text color */ + if (state & NK_WIDGET_STATE_ACTIVED) { + background = &style->active; + text.text = style->label_active; + } else if (state & NK_WIDGET_STATE_HOVER) { + background = &style->hover; + text.text = style->label_hover; + } else { + background = &style->normal; + text.text = style->label_normal; + } + + /* draw background */ + if (background->type == NK_STYLE_ITEM_IMAGE) { + nk_draw_image(out, *bounds, &background->data.image, nk_white); + text.background = nk_rgba(0,0,0,0); + } else { + text.background = background->data.color; + nk_fill_rect(out, *bounds, style->rounding, background->data.color); + nk_stroke_rect(out, *bounds, style->rounding, style->border, background->data.color); + } + + /* draw label */ + text.padding = nk_vec2(0,0); + nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font); +} + +NK_INTERN void +nk_do_property(nk_flags *ws, + struct nk_command_buffer *out, struct nk_rect property, + const char *name, struct nk_property_variant *variant, + float inc_per_pixel, char *buffer, int *len, + int *state, int *cursor, int *select_begin, int *select_end, + const struct nk_style_property *style, + enum nk_property_filter filter, struct nk_input *in, + const struct nk_user_font *font, struct nk_text_edit *text_edit, + enum nk_button_behavior behavior) +{ + const nk_plugin_filter filters[] = { + nk_filter_decimal, + nk_filter_float + }; + int active, old; + int num_len, name_len; + char string[NK_MAX_NUMBER_BUFFER]; + float size; + + char *dst = 0; + int *length; + + struct nk_rect left; + struct nk_rect right; + struct nk_rect label; + struct nk_rect edit; + struct nk_rect empty; + + /* left decrement button */ + left.h = font->height/2; + left.w = left.h; + left.x = property.x + style->border + style->padding.x; + left.y = property.y + style->border + property.h/2.0f - left.h/2; + + /* text label */ + name_len = nk_strlen(name); + size = font->width(font->userdata, font->height, name, name_len); + label.x = left.x + left.w + style->padding.x; + label.w = (float)size + 2 * style->padding.x; + label.y = property.y + style->border + style->padding.y; + label.h = property.h - (2 * style->border + 2 * style->padding.y); + + /* right increment button */ + right.y = left.y; + right.w = left.w; + right.h = left.h; + right.x = property.x + property.w - (right.w + style->padding.x); + + /* edit */ + if (*state == NK_PROPERTY_EDIT) { + size = font->width(font->userdata, font->height, buffer, *len); + size += style->edit.cursor_size; + length = len; + dst = buffer; + } else { + switch (variant->kind) { + default: break; + case NK_PROPERTY_INT: + nk_itoa(string, variant->value.i); + num_len = nk_strlen(string); + break; + case NK_PROPERTY_FLOAT: + nk_dtoa(string, (double)variant->value.f); + num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); + break; + case NK_PROPERTY_DOUBLE: + nk_dtoa(string, variant->value.d); + num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); + break; + } + size = font->width(font->userdata, font->height, string, num_len); + dst = string; + length = &num_len; + } + + edit.w = (float)size + 2 * style->padding.x; + edit.w = NK_MIN(edit.w, right.x - (label.x + label.w)); + edit.x = right.x - (edit.w + style->padding.x); + edit.y = property.y + style->border; + edit.h = property.h - (2 * style->border); + + /* empty left space activator */ + empty.w = edit.x - (label.x + label.w); + empty.x = label.x + label.w; + empty.y = property.y; + empty.h = property.h; + + /* update property */ + old = (*state == NK_PROPERTY_EDIT); + nk_property_behavior(ws, in, property, label, edit, empty, state, variant, inc_per_pixel); + + /* draw property */ + if (style->draw_begin) style->draw_begin(out, style->userdata); + nk_draw_property(out, style, &property, &label, *ws, name, name_len, font); + if (style->draw_end) style->draw_end(out, style->userdata); + + /* execute right button */ + if (nk_do_button_symbol(ws, out, left, style->sym_left, behavior, &style->dec_button, in, font)) { + switch (variant->kind) { + default: break; + case NK_PROPERTY_INT: + variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i - variant->step.i, variant->max_value.i); break; + case NK_PROPERTY_FLOAT: + variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f - variant->step.f, variant->max_value.f); break; + case NK_PROPERTY_DOUBLE: + variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break; + } + } + /* execute left button */ + if (nk_do_button_symbol(ws, out, right, style->sym_right, behavior, &style->inc_button, in, font)) { + switch (variant->kind) { + default: break; + case NK_PROPERTY_INT: + variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i + variant->step.i, variant->max_value.i); break; + case NK_PROPERTY_FLOAT: + variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f + variant->step.f, variant->max_value.f); break; + case NK_PROPERTY_DOUBLE: + variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break; + } + } + if (old != NK_PROPERTY_EDIT && (*state == NK_PROPERTY_EDIT)) { + /* property has been activated so setup buffer */ + NK_MEMCPY(buffer, dst, (nk_size)*length); + *cursor = nk_utf_len(buffer, *length); + *len = *length; + length = len; + dst = buffer; + active = 0; + } else active = (*state == NK_PROPERTY_EDIT); + + /* execute and run text edit field */ + nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]); + text_edit->active = (unsigned char)active; + text_edit->string.len = *length; + text_edit->cursor = NK_CLAMP(0, *cursor, *length); + text_edit->select_start = NK_CLAMP(0,*select_begin, *length); + text_edit->select_end = NK_CLAMP(0,*select_end, *length); + text_edit->string.buffer.allocated = (nk_size)*length; + text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER; + text_edit->string.buffer.memory.ptr = dst; + text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER; + text_edit->mode = NK_TEXT_EDIT_MODE_INSERT; + nk_do_edit(ws, out, edit, NK_EDIT_FIELD|NK_EDIT_AUTO_SELECT, + filters[filter], text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font); + + *length = text_edit->string.len; + *cursor = text_edit->cursor; + *select_begin = text_edit->select_start; + *select_end = text_edit->select_end; + if (text_edit->active && nk_input_is_key_pressed(in, NK_KEY_ENTER)) + text_edit->active = nk_false; + + if (active && !text_edit->active) { + /* property is now not active so convert edit text to value*/ + *state = NK_PROPERTY_DEFAULT; + buffer[*len] = '\0'; + switch (variant->kind) { + default: break; + case NK_PROPERTY_INT: + variant->value.i = nk_strtoi(buffer, 0); + variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i); + break; + case NK_PROPERTY_FLOAT: + nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); + variant->value.f = nk_strtof(buffer, 0); + variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f); + break; + case NK_PROPERTY_DOUBLE: + nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); + variant->value.d = nk_strtod(buffer, 0); + variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); + break; + } + } +} +/* =============================================================== + * + * COLOR PICKER + * + * ===============================================================*/ +NK_INTERN int +nk_color_picker_behavior(nk_flags *state, + const struct nk_rect *bounds, const struct nk_rect *matrix, + const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, + struct nk_color *color, const struct nk_input *in) +{ + float hsva[4]; + int value_changed = 0; + int hsv_changed = 0; + + NK_ASSERT(state); + NK_ASSERT(matrix); + NK_ASSERT(hue_bar); + NK_ASSERT(color); + + /* color matrix */ + nk_color_hsva_fv(hsva, *color); + if (nk_button_behavior(state, *matrix, in, NK_BUTTON_REPEATER)) { + hsva[1] = NK_SATURATE((in->mouse.pos.x - matrix->x) / (matrix->w-1)); + hsva[2] = 1.0f - NK_SATURATE((in->mouse.pos.y - matrix->y) / (matrix->h-1)); + value_changed = hsv_changed = 1; + } + + /* hue bar */ + if (nk_button_behavior(state, *hue_bar, in, NK_BUTTON_REPEATER)) { + hsva[0] = NK_SATURATE((in->mouse.pos.y - hue_bar->y) / (hue_bar->h-1)); + value_changed = hsv_changed = 1; + } + + /* alpha bar */ + if (alpha_bar) { + if (nk_button_behavior(state, *alpha_bar, in, NK_BUTTON_REPEATER)) { + hsva[3] = 1.0f - NK_SATURATE((in->mouse.pos.y - alpha_bar->y) / (alpha_bar->h-1)); + value_changed = 1; + } + } + nk_widget_state_reset(state); + if (hsv_changed) { + *color = nk_hsva_fv(hsva); + *state = NK_WIDGET_STATE_ACTIVE; + } + if (value_changed) { + color->a = (nk_byte)(hsva[3] * 255.0f); + *state = NK_WIDGET_STATE_ACTIVE; + } + + /* set color picker widget state */ + if (nk_input_is_mouse_hovering_rect(in, *bounds)) + *state = NK_WIDGET_STATE_HOVERED; + if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *bounds)) + *state |= NK_WIDGET_STATE_ENTERED; + else if (nk_input_is_mouse_prev_hovering_rect(in, *bounds)) + *state |= NK_WIDGET_STATE_LEFT; + return value_changed; +} + +NK_INTERN void +nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix, + const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, + struct nk_color color) +{ + NK_STORAGE const struct nk_color black = {0,0,0,255}; + NK_STORAGE const struct nk_color white = {255, 255, 255, 255}; + NK_STORAGE const struct nk_color black_trans = {0,0,0,0}; + + const float crosshair_size = 7.0f; + struct nk_color temp; + float hsva[4]; + float line_y; + int i; + + NK_ASSERT(o); + NK_ASSERT(matrix); + NK_ASSERT(hue_bar); + + /* draw hue bar */ + nk_color_hsv_fv(hsva, color); + for (i = 0; i < 6; ++i) { + NK_GLOBAL const struct nk_color hue_colors[] = { + {255, 0, 0, 255}, + {255,255,0,255}, + {0,255,0,255}, + {0, 255,255,255}, + {0,0,255,255}, + {255, 0, 255, 255}, + {255, 0, 0, 255} + }; + nk_fill_rect_multi_color(o, + nk_rect(hue_bar->x, hue_bar->y + (float)i * (hue_bar->h/6.0f) + 0.5f, + hue_bar->w, (hue_bar->h/6.0f) + 0.5f), hue_colors[i], hue_colors[i], + hue_colors[i+1], hue_colors[i+1]); + } + line_y = (float)(int)(hue_bar->y + hsva[0] * matrix->h + 0.5f); + nk_stroke_line(o, hue_bar->x-1, line_y, hue_bar->x + hue_bar->w + 2, + line_y, 1, nk_rgb(255,255,255)); + + /* draw alpha bar */ + if (alpha_bar) { + float alpha = NK_SATURATE((float)color.a/255.0f); + line_y = (float)(int)(alpha_bar->y + (1.0f - alpha) * matrix->h + 0.5f); + + nk_fill_rect_multi_color(o, *alpha_bar, white, white, black, black); + nk_stroke_line(o, alpha_bar->x-1, line_y, alpha_bar->x + alpha_bar->w + 2, + line_y, 1, nk_rgb(255,255,255)); + } + + /* draw color matrix */ + temp = nk_hsv_f(hsva[0], 1.0f, 1.0f); + nk_fill_rect_multi_color(o, *matrix, white, temp, temp, white); + nk_fill_rect_multi_color(o, *matrix, black_trans, black_trans, black, black); + + /* draw cross-hair */ + {struct nk_vec2 p; float S = hsva[1]; float V = hsva[2]; + p.x = (float)(int)(matrix->x + S * matrix->w); + p.y = (float)(int)(matrix->y + (1.0f - V) * matrix->h); + nk_stroke_line(o, p.x - crosshair_size, p.y, p.x-2, p.y, 1.0f, white); + nk_stroke_line(o, p.x + crosshair_size + 1, p.y, p.x+3, p.y, 1.0f, white); + nk_stroke_line(o, p.x, p.y + crosshair_size + 1, p.x, p.y+3, 1.0f, white); + nk_stroke_line(o, p.x, p.y - crosshair_size, p.x, p.y-2, 1.0f, white);} +} + +NK_INTERN int +nk_do_color_picker(nk_flags *state, + struct nk_command_buffer *out, struct nk_color *color, + enum nk_color_format fmt, struct nk_rect bounds, + struct nk_vec2 padding, const struct nk_input *in, + const struct nk_user_font *font) +{ + int ret = 0; + struct nk_rect matrix; + struct nk_rect hue_bar; + struct nk_rect alpha_bar; + float bar_w; + + NK_ASSERT(out); + NK_ASSERT(color); + NK_ASSERT(state); + NK_ASSERT(font); + if (!out || !color || !state || !font) + return ret; + + bar_w = font->height; + bounds.x += padding.x; + bounds.y += padding.x; + bounds.w -= 2 * padding.x; + bounds.h -= 2 * padding.y; + + matrix.x = bounds.x; + matrix.y = bounds.y; + matrix.h = bounds.h; + matrix.w = bounds.w - (3 * padding.x + 2 * bar_w); + + hue_bar.w = bar_w; + hue_bar.y = bounds.y; + hue_bar.h = matrix.h; + hue_bar.x = matrix.x + matrix.w + padding.x; + + alpha_bar.x = hue_bar.x + hue_bar.w + padding.x; + alpha_bar.y = bounds.y; + alpha_bar.w = bar_w; + alpha_bar.h = matrix.h; + + ret = nk_color_picker_behavior(state, &bounds, &matrix, &hue_bar, + (fmt == NK_RGBA) ? &alpha_bar:0, color, in); + nk_draw_color_picker(out, &matrix, &hue_bar, (fmt == NK_RGBA) ? &alpha_bar:0, *color); + return ret; +} + +/* ============================================================== + * + * STYLE + * + * ===============================================================*/ +NK_API void nk_style_default(struct nk_context *ctx){nk_style_from_table(ctx, 0);} +#define NK_COLOR_MAP(NK_COLOR)\ + NK_COLOR(NK_COLOR_TEXT, 175,175,175,255) \ + NK_COLOR(NK_COLOR_WINDOW, 45, 45, 45, 255) \ + NK_COLOR(NK_COLOR_HEADER, 40, 40, 40, 255) \ + NK_COLOR(NK_COLOR_BORDER, 65, 65, 65, 255) \ + NK_COLOR(NK_COLOR_BUTTON, 50, 50, 50, 255) \ + NK_COLOR(NK_COLOR_BUTTON_HOVER, 40, 40, 40, 255) \ + NK_COLOR(NK_COLOR_BUTTON_ACTIVE, 35, 35, 35, 255) \ + NK_COLOR(NK_COLOR_TOGGLE, 100,100,100,255) \ + NK_COLOR(NK_COLOR_TOGGLE_HOVER, 120,120,120,255) \ + NK_COLOR(NK_COLOR_TOGGLE_CURSOR, 45, 45, 45, 255) \ + NK_COLOR(NK_COLOR_SELECT, 45, 45, 45, 255) \ + NK_COLOR(NK_COLOR_SELECT_ACTIVE, 35, 35, 35,255) \ + NK_COLOR(NK_COLOR_SLIDER, 38, 38, 38, 255) \ + NK_COLOR(NK_COLOR_SLIDER_CURSOR, 100,100,100,255) \ + NK_COLOR(NK_COLOR_SLIDER_CURSOR_HOVER, 120,120,120,255) \ + NK_COLOR(NK_COLOR_SLIDER_CURSOR_ACTIVE, 150,150,150,255) \ + NK_COLOR(NK_COLOR_PROPERTY, 38, 38, 38, 255) \ + NK_COLOR(NK_COLOR_EDIT, 38, 38, 38, 255) \ + NK_COLOR(NK_COLOR_EDIT_CURSOR, 175,175,175,255) \ + NK_COLOR(NK_COLOR_COMBO, 45, 45, 45, 255) \ + NK_COLOR(NK_COLOR_CHART, 120,120,120,255) \ + NK_COLOR(NK_COLOR_CHART_COLOR, 45, 45, 45, 255) \ + NK_COLOR(NK_COLOR_CHART_COLOR_HIGHLIGHT,255, 0, 0, 255) \ + NK_COLOR(NK_COLOR_SCROLLBAR, 40, 40, 40, 255) \ + NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR, 100,100,100,255) \ + NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_HOVER,120,120,120,255) \ + NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,150,150,150,255) \ + NK_COLOR(NK_COLOR_TAB_HEADER, 40, 40, 40,255) + +NK_GLOBAL const struct nk_color +nk_default_color_style[NK_COLOR_COUNT] = { +#define NK_COLOR(a,b,c,d,e) {b,c,d,e}, + NK_COLOR_MAP(NK_COLOR) +#undef NK_COLOR +}; + +NK_GLOBAL const char *nk_color_names[NK_COLOR_COUNT] = { +#define NK_COLOR(a,b,c,d,e) #a, + NK_COLOR_MAP(NK_COLOR) +#undef NK_COLOR +}; + +NK_API const char *nk_style_get_color_by_name(enum nk_style_colors c) +{return nk_color_names[c];} + +NK_API struct nk_style_item nk_style_item_image(struct nk_image img) +{struct nk_style_item i; i.type = NK_STYLE_ITEM_IMAGE; i.data.image = img; return i;} + +NK_API struct nk_style_item nk_style_item_color(struct nk_color col) +{struct nk_style_item i; i.type = NK_STYLE_ITEM_COLOR; i.data.color = col; return i;} + +NK_API struct nk_style_item nk_style_item_hide(void) +{struct nk_style_item i; i.type = NK_STYLE_ITEM_COLOR; i.data.color = nk_rgba(0,0,0,0); return i;} + +NK_API void +nk_style_from_table(struct nk_context *ctx, const struct nk_color *table) +{ + struct nk_style *style; + struct nk_style_text *text; + struct nk_style_button *button; + struct nk_style_toggle *toggle; + struct nk_style_selectable *select; + struct nk_style_slider *slider; + struct nk_style_progress *prog; + struct nk_style_scrollbar *scroll; + struct nk_style_edit *edit; + struct nk_style_property *property; + struct nk_style_combo *combo; + struct nk_style_chart *chart; + struct nk_style_tab *tab; + struct nk_style_window *win; + + NK_ASSERT(ctx); + if (!ctx) return; + style = &ctx->style; + table = (!table) ? nk_default_color_style: table; + + /* default text */ + text = &style->text; + text->color = table[NK_COLOR_TEXT]; + text->padding = nk_vec2(0,0); + + /* default button */ + button = &style->button; + nk_zero_struct(*button); + button->normal = nk_style_item_color(table[NK_COLOR_BUTTON]); + button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]); + button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]); + button->border_color = table[NK_COLOR_BORDER]; + button->text_background = table[NK_COLOR_BUTTON]; + button->text_normal = table[NK_COLOR_TEXT]; + button->text_hover = table[NK_COLOR_TEXT]; + button->text_active = table[NK_COLOR_TEXT]; + button->padding = nk_vec2(2.0f,2.0f); + button->image_padding = nk_vec2(0.0f,0.0f); + button->touch_padding = nk_vec2(0.0f, 0.0f); + button->userdata = nk_handle_ptr(0); + button->text_alignment = NK_TEXT_CENTERED; + button->border = 1.0f; + button->rounding = 4.0f; + button->draw_begin = 0; + button->draw_end = 0; + + /* contextual button */ + button = &style->contextual_button; + nk_zero_struct(*button); + button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); + button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]); + button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]); + button->border_color = table[NK_COLOR_WINDOW]; + button->text_background = table[NK_COLOR_WINDOW]; + button->text_normal = table[NK_COLOR_TEXT]; + button->text_hover = table[NK_COLOR_TEXT]; + button->text_active = table[NK_COLOR_TEXT]; + button->padding = nk_vec2(2.0f,2.0f); + button->touch_padding = nk_vec2(0.0f,0.0f); + button->userdata = nk_handle_ptr(0); + button->text_alignment = NK_TEXT_CENTERED; + button->border = 0.0f; + button->rounding = 0.0f; + button->draw_begin = 0; + button->draw_end = 0; + + /* menu button */ + button = &style->menu_button; + nk_zero_struct(*button); + button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); + button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]); + button->active = nk_style_item_color(table[NK_COLOR_WINDOW]); + button->border_color = table[NK_COLOR_WINDOW]; + button->text_background = table[NK_COLOR_WINDOW]; + button->text_normal = table[NK_COLOR_TEXT]; + button->text_hover = table[NK_COLOR_TEXT]; + button->text_active = table[NK_COLOR_TEXT]; + button->padding = nk_vec2(2.0f,2.0f); + button->touch_padding = nk_vec2(0.0f,0.0f); + button->userdata = nk_handle_ptr(0); + button->text_alignment = NK_TEXT_CENTERED; + button->border = 0.0f; + button->rounding = 1.0f; + button->draw_begin = 0; + button->draw_end = 0; + + /* checkbox toggle */ + toggle = &style->checkbox; + nk_zero_struct(*toggle); + toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]); + toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); + toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); + toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); + toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); + toggle->userdata = nk_handle_ptr(0); + toggle->text_background = table[NK_COLOR_WINDOW]; + toggle->text_normal = table[NK_COLOR_TEXT]; + toggle->text_hover = table[NK_COLOR_TEXT]; + toggle->text_active = table[NK_COLOR_TEXT]; + toggle->padding = nk_vec2(2.0f, 2.0f); + toggle->touch_padding = nk_vec2(0,0); + toggle->border_color = nk_rgba(0,0,0,0); + toggle->border = 0.0f; + toggle->spacing = 4; + + /* option toggle */ + toggle = &style->option; + nk_zero_struct(*toggle); + toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]); + toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); + toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); + toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); + toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); + toggle->userdata = nk_handle_ptr(0); + toggle->text_background = table[NK_COLOR_WINDOW]; + toggle->text_normal = table[NK_COLOR_TEXT]; + toggle->text_hover = table[NK_COLOR_TEXT]; + toggle->text_active = table[NK_COLOR_TEXT]; + toggle->padding = nk_vec2(3.0f, 3.0f); + toggle->touch_padding = nk_vec2(0,0); + toggle->border_color = nk_rgba(0,0,0,0); + toggle->border = 0.0f; + toggle->spacing = 4; + + /* selectable */ + select = &style->selectable; + nk_zero_struct(*select); + select->normal = nk_style_item_color(table[NK_COLOR_SELECT]); + select->hover = nk_style_item_color(table[NK_COLOR_SELECT]); + select->pressed = nk_style_item_color(table[NK_COLOR_SELECT]); + select->normal_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); + select->hover_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); + select->pressed_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); + select->text_normal = table[NK_COLOR_TEXT]; + select->text_hover = table[NK_COLOR_TEXT]; + select->text_pressed = table[NK_COLOR_TEXT]; + select->text_normal_active = table[NK_COLOR_TEXT]; + select->text_hover_active = table[NK_COLOR_TEXT]; + select->text_pressed_active = table[NK_COLOR_TEXT]; + select->padding = nk_vec2(2.0f,2.0f); + select->touch_padding = nk_vec2(0,0); + select->userdata = nk_handle_ptr(0); + select->rounding = 0.0f; + select->draw_begin = 0; + select->draw_end = 0; + + /* slider */ + slider = &style->slider; + nk_zero_struct(*slider); + slider->normal = nk_style_item_hide(); + slider->hover = nk_style_item_hide(); + slider->active = nk_style_item_hide(); + slider->bar_normal = table[NK_COLOR_SLIDER]; + slider->bar_hover = table[NK_COLOR_SLIDER]; + slider->bar_active = table[NK_COLOR_SLIDER]; + slider->bar_filled = table[NK_COLOR_SLIDER_CURSOR]; + slider->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]); + slider->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]); + slider->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]); + slider->inc_symbol = NK_SYMBOL_TRIANGLE_RIGHT; + slider->dec_symbol = NK_SYMBOL_TRIANGLE_LEFT; + slider->cursor_size = nk_vec2(16,16); + slider->padding = nk_vec2(2,2); + slider->spacing = nk_vec2(2,2); + slider->userdata = nk_handle_ptr(0); + slider->show_buttons = nk_false; + slider->bar_height = 8; + slider->rounding = 0; + slider->draw_begin = 0; + slider->draw_end = 0; + + /* slider buttons */ + button = &style->slider.inc_button; + button->normal = nk_style_item_color(nk_rgb(40,40,40)); + button->hover = nk_style_item_color(nk_rgb(42,42,42)); + button->active = nk_style_item_color(nk_rgb(44,44,44)); + button->border_color = nk_rgb(65,65,65); + button->text_background = nk_rgb(40,40,40); + button->text_normal = nk_rgb(175,175,175); + button->text_hover = nk_rgb(175,175,175); + button->text_active = nk_rgb(175,175,175); + button->padding = nk_vec2(8.0f,8.0f); + button->touch_padding = nk_vec2(0.0f,0.0f); + button->userdata = nk_handle_ptr(0); + button->text_alignment = NK_TEXT_CENTERED; + button->border = 1.0f; + button->rounding = 0.0f; + button->draw_begin = 0; + button->draw_end = 0; + style->slider.dec_button = style->slider.inc_button; + + /* progressbar */ + prog = &style->progress; + nk_zero_struct(*prog); + prog->normal = nk_style_item_color(table[NK_COLOR_SLIDER]); + prog->hover = nk_style_item_color(table[NK_COLOR_SLIDER]); + prog->active = nk_style_item_color(table[NK_COLOR_SLIDER]); + prog->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]); + prog->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]); + prog->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]); + prog->border_color = nk_rgba(0,0,0,0); + prog->cursor_border_color = nk_rgba(0,0,0,0); + prog->userdata = nk_handle_ptr(0); + prog->padding = nk_vec2(4,4); + prog->rounding = 0; + prog->border = 0; + prog->cursor_rounding = 0; + prog->cursor_border = 0; + prog->draw_begin = 0; + prog->draw_end = 0; + + /* scrollbars */ + scroll = &style->scrollh; + nk_zero_struct(*scroll); + scroll->normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); + scroll->hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); + scroll->active = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); + scroll->cursor_normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR]); + scroll->cursor_hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_HOVER]); + scroll->cursor_active = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE]); + scroll->dec_symbol = NK_SYMBOL_CIRCLE_SOLID; + scroll->inc_symbol = NK_SYMBOL_CIRCLE_SOLID; + scroll->userdata = nk_handle_ptr(0); + scroll->border_color = table[NK_COLOR_SCROLLBAR]; + scroll->cursor_border_color = table[NK_COLOR_SCROLLBAR]; + scroll->padding = nk_vec2(0,0); + scroll->show_buttons = nk_false; + scroll->border = 0; + scroll->rounding = 0; + scroll->border_cursor = 0; + scroll->rounding_cursor = 0; + scroll->draw_begin = 0; + scroll->draw_end = 0; + style->scrollv = style->scrollh; + + /* scrollbars buttons */ + button = &style->scrollh.inc_button; + button->normal = nk_style_item_color(nk_rgb(40,40,40)); + button->hover = nk_style_item_color(nk_rgb(42,42,42)); + button->active = nk_style_item_color(nk_rgb(44,44,44)); + button->border_color = nk_rgb(65,65,65); + button->text_background = nk_rgb(40,40,40); + button->text_normal = nk_rgb(175,175,175); + button->text_hover = nk_rgb(175,175,175); + button->text_active = nk_rgb(175,175,175); + button->padding = nk_vec2(4.0f,4.0f); + button->touch_padding = nk_vec2(0.0f,0.0f); + button->userdata = nk_handle_ptr(0); + button->text_alignment = NK_TEXT_CENTERED; + button->border = 1.0f; + button->rounding = 0.0f; + button->draw_begin = 0; + button->draw_end = 0; + style->scrollh.dec_button = style->scrollh.inc_button; + style->scrollv.inc_button = style->scrollh.inc_button; + style->scrollv.dec_button = style->scrollh.inc_button; + + /* edit */ + edit = &style->edit; + nk_zero_struct(*edit); + edit->normal = nk_style_item_color(table[NK_COLOR_EDIT]); + edit->hover = nk_style_item_color(table[NK_COLOR_EDIT]); + edit->active = nk_style_item_color(table[NK_COLOR_EDIT]); + edit->cursor_normal = table[NK_COLOR_TEXT]; + edit->cursor_hover = table[NK_COLOR_TEXT]; + edit->cursor_text_normal= table[NK_COLOR_EDIT]; + edit->cursor_text_hover = table[NK_COLOR_EDIT]; + edit->border_color = table[NK_COLOR_BORDER]; + edit->text_normal = table[NK_COLOR_TEXT]; + edit->text_hover = table[NK_COLOR_TEXT]; + edit->text_active = table[NK_COLOR_TEXT]; + edit->selected_normal = table[NK_COLOR_TEXT]; + edit->selected_hover = table[NK_COLOR_TEXT]; + edit->selected_text_normal = table[NK_COLOR_EDIT]; + edit->selected_text_hover = table[NK_COLOR_EDIT]; + edit->scrollbar_size = nk_vec2(10,10); + edit->scrollbar = style->scrollv; + edit->padding = nk_vec2(4,4); + edit->row_padding = 2; + edit->cursor_size = 4; + edit->border = 1; + edit->rounding = 0; + + /* property */ + property = &style->property; + nk_zero_struct(*property); + property->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); + property->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); + property->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); + property->border_color = table[NK_COLOR_BORDER]; + property->label_normal = table[NK_COLOR_TEXT]; + property->label_hover = table[NK_COLOR_TEXT]; + property->label_active = table[NK_COLOR_TEXT]; + property->sym_left = NK_SYMBOL_TRIANGLE_LEFT; + property->sym_right = NK_SYMBOL_TRIANGLE_RIGHT; + property->userdata = nk_handle_ptr(0); + property->padding = nk_vec2(4,4); + property->border = 1; + property->rounding = 10; + property->draw_begin = 0; + property->draw_end = 0; + + /* property buttons */ + button = &style->property.dec_button; + nk_zero_struct(*button); + button->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); + button->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); + button->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); + button->border_color = nk_rgba(0,0,0,0); + button->text_background = table[NK_COLOR_PROPERTY]; + button->text_normal = table[NK_COLOR_TEXT]; + button->text_hover = table[NK_COLOR_TEXT]; + button->text_active = table[NK_COLOR_TEXT]; + button->padding = nk_vec2(0.0f,0.0f); + button->touch_padding = nk_vec2(0.0f,0.0f); + button->userdata = nk_handle_ptr(0); + button->text_alignment = NK_TEXT_CENTERED; + button->border = 0.0f; + button->rounding = 0.0f; + button->draw_begin = 0; + button->draw_end = 0; + style->property.inc_button = style->property.dec_button; + + /* property edit */ + edit = &style->property.edit; + nk_zero_struct(*edit); + edit->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); + edit->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); + edit->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); + edit->border_color = nk_rgba(0,0,0,0); + edit->cursor_normal = table[NK_COLOR_TEXT]; + edit->cursor_hover = table[NK_COLOR_TEXT]; + edit->cursor_text_normal= table[NK_COLOR_EDIT]; + edit->cursor_text_hover = table[NK_COLOR_EDIT]; + edit->text_normal = table[NK_COLOR_TEXT]; + edit->text_hover = table[NK_COLOR_TEXT]; + edit->text_active = table[NK_COLOR_TEXT]; + edit->selected_normal = table[NK_COLOR_TEXT]; + edit->selected_hover = table[NK_COLOR_TEXT]; + edit->selected_text_normal = table[NK_COLOR_EDIT]; + edit->selected_text_hover = table[NK_COLOR_EDIT]; + edit->padding = nk_vec2(0,0); + edit->cursor_size = 8; + edit->border = 0; + edit->rounding = 0; + + /* chart */ + chart = &style->chart; + nk_zero_struct(*chart); + chart->background = nk_style_item_color(table[NK_COLOR_CHART]); + chart->border_color = table[NK_COLOR_BORDER]; + chart->selected_color = table[NK_COLOR_CHART_COLOR_HIGHLIGHT]; + chart->color = table[NK_COLOR_CHART_COLOR]; + chart->padding = nk_vec2(4,4); + chart->border = 0; + chart->rounding = 0; + + /* combo */ + combo = &style->combo; + combo->normal = nk_style_item_color(table[NK_COLOR_COMBO]); + combo->hover = nk_style_item_color(table[NK_COLOR_COMBO]); + combo->active = nk_style_item_color(table[NK_COLOR_COMBO]); + combo->border_color = table[NK_COLOR_BORDER]; + combo->label_normal = table[NK_COLOR_TEXT]; + combo->label_hover = table[NK_COLOR_TEXT]; + combo->label_active = table[NK_COLOR_TEXT]; + combo->sym_normal = NK_SYMBOL_TRIANGLE_DOWN; + combo->sym_hover = NK_SYMBOL_TRIANGLE_DOWN; + combo->sym_active = NK_SYMBOL_TRIANGLE_DOWN; + combo->content_padding = nk_vec2(4,4); + combo->button_padding = nk_vec2(0,4); + combo->spacing = nk_vec2(4,0); + combo->border = 1; + combo->rounding = 0; + + /* combo button */ + button = &style->combo.button; + nk_zero_struct(*button); + button->normal = nk_style_item_color(table[NK_COLOR_COMBO]); + button->hover = nk_style_item_color(table[NK_COLOR_COMBO]); + button->active = nk_style_item_color(table[NK_COLOR_COMBO]); + button->border_color = nk_rgba(0,0,0,0); + button->text_background = table[NK_COLOR_COMBO]; + button->text_normal = table[NK_COLOR_TEXT]; + button->text_hover = table[NK_COLOR_TEXT]; + button->text_active = table[NK_COLOR_TEXT]; + button->padding = nk_vec2(2.0f,2.0f); + button->touch_padding = nk_vec2(0.0f,0.0f); + button->userdata = nk_handle_ptr(0); + button->text_alignment = NK_TEXT_CENTERED; + button->border = 0.0f; + button->rounding = 0.0f; + button->draw_begin = 0; + button->draw_end = 0; + + /* tab */ + tab = &style->tab; + tab->background = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); + tab->border_color = table[NK_COLOR_BORDER]; + tab->text = table[NK_COLOR_TEXT]; + tab->sym_minimize = NK_SYMBOL_TRIANGLE_RIGHT; + tab->sym_maximize = NK_SYMBOL_TRIANGLE_DOWN; + tab->padding = nk_vec2(4,4); + tab->spacing = nk_vec2(4,4); + tab->indent = 10.0f; + tab->border = 1; + tab->rounding = 0; + + /* tab button */ + button = &style->tab.tab_minimize_button; + nk_zero_struct(*button); + button->normal = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); + button->hover = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); + button->active = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); + button->border_color = nk_rgba(0,0,0,0); + button->text_background = table[NK_COLOR_TAB_HEADER]; + button->text_normal = table[NK_COLOR_TEXT]; + button->text_hover = table[NK_COLOR_TEXT]; + button->text_active = table[NK_COLOR_TEXT]; + button->padding = nk_vec2(2.0f,2.0f); + button->touch_padding = nk_vec2(0.0f,0.0f); + button->userdata = nk_handle_ptr(0); + button->text_alignment = NK_TEXT_CENTERED; + button->border = 0.0f; + button->rounding = 0.0f; + button->draw_begin = 0; + button->draw_end = 0; + style->tab.tab_maximize_button =*button; + + /* node button */ + button = &style->tab.node_minimize_button; + nk_zero_struct(*button); + button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); + button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]); + button->active = nk_style_item_color(table[NK_COLOR_WINDOW]); + button->border_color = nk_rgba(0,0,0,0); + button->text_background = table[NK_COLOR_TAB_HEADER]; + button->text_normal = table[NK_COLOR_TEXT]; + button->text_hover = table[NK_COLOR_TEXT]; + button->text_active = table[NK_COLOR_TEXT]; + button->padding = nk_vec2(2.0f,2.0f); + button->touch_padding = nk_vec2(0.0f,0.0f); + button->userdata = nk_handle_ptr(0); + button->text_alignment = NK_TEXT_CENTERED; + button->border = 0.0f; + button->rounding = 0.0f; + button->draw_begin = 0; + button->draw_end = 0; + style->tab.node_maximize_button =*button; + + /* window header */ + win = &style->window; + win->header.align = NK_HEADER_RIGHT; + win->header.close_symbol = NK_SYMBOL_X; + win->header.minimize_symbol = NK_SYMBOL_MINUS; + win->header.maximize_symbol = NK_SYMBOL_PLUS; + win->header.normal = nk_style_item_color(table[NK_COLOR_HEADER]); + win->header.hover = nk_style_item_color(table[NK_COLOR_HEADER]); + win->header.active = nk_style_item_color(table[NK_COLOR_HEADER]); + win->header.label_normal = table[NK_COLOR_TEXT]; + win->header.label_hover = table[NK_COLOR_TEXT]; + win->header.label_active = table[NK_COLOR_TEXT]; + win->header.label_padding = nk_vec2(4,4); + win->header.padding = nk_vec2(4,4); + win->header.spacing = nk_vec2(0,0); + + /* window header close button */ + button = &style->window.header.close_button; + nk_zero_struct(*button); + button->normal = nk_style_item_color(table[NK_COLOR_HEADER]); + button->hover = nk_style_item_color(table[NK_COLOR_HEADER]); + button->active = nk_style_item_color(table[NK_COLOR_HEADER]); + button->border_color = nk_rgba(0,0,0,0); + button->text_background = table[NK_COLOR_HEADER]; + button->text_normal = table[NK_COLOR_TEXT]; + button->text_hover = table[NK_COLOR_TEXT]; + button->text_active = table[NK_COLOR_TEXT]; + button->padding = nk_vec2(0.0f,0.0f); + button->touch_padding = nk_vec2(0.0f,0.0f); + button->userdata = nk_handle_ptr(0); + button->text_alignment = NK_TEXT_CENTERED; + button->border = 0.0f; + button->rounding = 0.0f; + button->draw_begin = 0; + button->draw_end = 0; + + /* window header minimize button */ + button = &style->window.header.minimize_button; + nk_zero_struct(*button); + button->normal = nk_style_item_color(table[NK_COLOR_HEADER]); + button->hover = nk_style_item_color(table[NK_COLOR_HEADER]); + button->active = nk_style_item_color(table[NK_COLOR_HEADER]); + button->border_color = nk_rgba(0,0,0,0); + button->text_background = table[NK_COLOR_HEADER]; + button->text_normal = table[NK_COLOR_TEXT]; + button->text_hover = table[NK_COLOR_TEXT]; + button->text_active = table[NK_COLOR_TEXT]; + button->padding = nk_vec2(0.0f,0.0f); + button->touch_padding = nk_vec2(0.0f,0.0f); + button->userdata = nk_handle_ptr(0); + button->text_alignment = NK_TEXT_CENTERED; + button->border = 0.0f; + button->rounding = 0.0f; + button->draw_begin = 0; + button->draw_end = 0; + + /* window */ + win->background = table[NK_COLOR_WINDOW]; + win->fixed_background = nk_style_item_color(table[NK_COLOR_WINDOW]); + win->border_color = table[NK_COLOR_BORDER]; + win->popup_border_color = table[NK_COLOR_BORDER]; + win->combo_border_color = table[NK_COLOR_BORDER]; + win->contextual_border_color = table[NK_COLOR_BORDER]; + win->menu_border_color = table[NK_COLOR_BORDER]; + win->group_border_color = table[NK_COLOR_BORDER]; + win->tooltip_border_color = table[NK_COLOR_BORDER]; + win->scaler = nk_style_item_color(table[NK_COLOR_TEXT]); + + win->rounding = 0.0f; + win->spacing = nk_vec2(4,4); + win->scrollbar_size = nk_vec2(10,10); + win->min_size = nk_vec2(64,64); + + win->combo_border = 1.0f; + win->contextual_border = 1.0f; + win->menu_border = 1.0f; + win->group_border = 1.0f; + win->tooltip_border = 1.0f; + win->popup_border = 1.0f; + win->border = 2.0f; + win->min_row_height_padding = 8; + + win->padding = nk_vec2(4,4); + win->group_padding = nk_vec2(4,4); + win->popup_padding = nk_vec2(4,4); + win->combo_padding = nk_vec2(4,4); + win->contextual_padding = nk_vec2(4,4); + win->menu_padding = nk_vec2(4,4); + win->tooltip_padding = nk_vec2(4,4); +} + +NK_API void +nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font) +{ + struct nk_style *style; + NK_ASSERT(ctx); + + if (!ctx) return; + style = &ctx->style; + style->font = font; + ctx->stacks.fonts.head = 0; + if (ctx->current) + nk_layout_reset_min_row_height(ctx); +} + +NK_API int +nk_style_push_font(struct nk_context *ctx, const struct nk_user_font *font) +{ + struct nk_config_stack_user_font *font_stack; + struct nk_config_stack_user_font_element *element; + + NK_ASSERT(ctx); + if (!ctx) return 0; + + font_stack = &ctx->stacks.fonts; + NK_ASSERT(font_stack->head < (int)NK_LEN(font_stack->elements)); + if (font_stack->head >= (int)NK_LEN(font_stack->elements)) + return 0; + + element = &font_stack->elements[font_stack->head++]; + element->address = &ctx->style.font; + element->old_value = ctx->style.font; + ctx->style.font = font; + return 1; +} + +NK_API int +nk_style_pop_font(struct nk_context *ctx) +{ + struct nk_config_stack_user_font *font_stack; + struct nk_config_stack_user_font_element *element; + + NK_ASSERT(ctx); + if (!ctx) return 0; + + font_stack = &ctx->stacks.fonts; + NK_ASSERT(font_stack->head > 0); + if (font_stack->head < 1) + return 0; + + element = &font_stack->elements[--font_stack->head]; + *element->address = element->old_value; + return 1; +} + +#define NK_STYLE_PUSH_IMPLEMENATION(prefix, type, stack) \ +nk_style_push_##type(struct nk_context *ctx, prefix##_##type *address, prefix##_##type value)\ +{\ + struct nk_config_stack_##type * type_stack;\ + struct nk_config_stack_##type##_element *element;\ + NK_ASSERT(ctx);\ + if (!ctx) return 0;\ + type_stack = &ctx->stacks.stack;\ + NK_ASSERT(type_stack->head < (int)NK_LEN(type_stack->elements));\ + if (type_stack->head >= (int)NK_LEN(type_stack->elements))\ + return 0;\ + element = &type_stack->elements[type_stack->head++];\ + element->address = address;\ + element->old_value = *address;\ + *address = value;\ + return 1;\ +} + +#define NK_STYLE_POP_IMPLEMENATION(type, stack) \ +nk_style_pop_##type(struct nk_context *ctx)\ +{\ + struct nk_config_stack_##type *type_stack;\ + struct nk_config_stack_##type##_element *element;\ + NK_ASSERT(ctx);\ + if (!ctx) return 0;\ + type_stack = &ctx->stacks.stack;\ + NK_ASSERT(type_stack->head > 0);\ + if (type_stack->head < 1)\ + return 0;\ + element = &type_stack->elements[--type_stack->head];\ + *element->address = element->old_value;\ + return 1;\ +} + +NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, style_item, style_items) +NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,float, floats) +NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, vec2, vectors) +NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,flags, flags) +NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk,color, colors) + +NK_API int NK_STYLE_POP_IMPLEMENATION(style_item, style_items) +NK_API int NK_STYLE_POP_IMPLEMENATION(float,floats) +NK_API int NK_STYLE_POP_IMPLEMENATION(vec2, vectors) +NK_API int NK_STYLE_POP_IMPLEMENATION(flags,flags) +NK_API int NK_STYLE_POP_IMPLEMENATION(color,colors) + +NK_API int +nk_style_set_cursor(struct nk_context *ctx, enum nk_style_cursor c) +{ + struct nk_style *style; + NK_ASSERT(ctx); + if (!ctx) return 0; + style = &ctx->style; + if (style->cursors[c]) { + style->cursor_active = style->cursors[c]; + return 1; + } + return 0; +} + +NK_API void +nk_style_show_cursor(struct nk_context *ctx) +{ + ctx->style.cursor_visible = nk_true; +} + +NK_API void +nk_style_hide_cursor(struct nk_context *ctx) +{ + ctx->style.cursor_visible = nk_false; +} + +NK_API void +nk_style_load_cursor(struct nk_context *ctx, enum nk_style_cursor cursor, + const struct nk_cursor *c) +{ + struct nk_style *style; + NK_ASSERT(ctx); + if (!ctx) return; + style = &ctx->style; + style->cursors[cursor] = c; +} + +NK_API void +nk_style_load_all_cursors(struct nk_context *ctx, struct nk_cursor *cursors) +{ + int i = 0; + struct nk_style *style; + NK_ASSERT(ctx); + if (!ctx) return; + style = &ctx->style; + for (i = 0; i < NK_CURSOR_COUNT; ++i) + style->cursors[i] = &cursors[i]; + style->cursor_visible = nk_true; +} + +/* =============================================================== + * + * POOL + * + * ===============================================================*/ +NK_INTERN void +nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc, + unsigned int capacity) +{ + nk_zero(pool, sizeof(*pool)); + pool->alloc = *alloc; + pool->capacity = capacity; + pool->type = NK_BUFFER_DYNAMIC; + pool->pages = 0; +} + +NK_INTERN void +nk_pool_free(struct nk_pool *pool) +{ + struct nk_page *iter = pool->pages; + if (!pool) return; + if (pool->type == NK_BUFFER_FIXED) return; + while (iter) { + struct nk_page *next = iter->next; + pool->alloc.free(pool->alloc.userdata, iter); + iter = next; + } +} + +NK_INTERN void +nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size) +{ + nk_zero(pool, sizeof(*pool)); + NK_ASSERT(size >= sizeof(struct nk_page)); + if (size < sizeof(struct nk_page)) return; + pool->capacity = (unsigned)(size - sizeof(struct nk_page)) / sizeof(struct nk_page_element); + pool->pages = (struct nk_page*)memory; + pool->type = NK_BUFFER_FIXED; + pool->size = size; +} + +NK_INTERN struct nk_page_element* +nk_pool_alloc(struct nk_pool *pool) +{ + if (!pool->pages || pool->pages->size >= pool->capacity) { + /* allocate new page */ + struct nk_page *page; + if (pool->type == NK_BUFFER_FIXED) { + if (!pool->pages) { + NK_ASSERT(pool->pages); + return 0; + } + NK_ASSERT(pool->pages->size < pool->capacity); + return 0; + } else { + nk_size size = sizeof(struct nk_page); + size += NK_POOL_DEFAULT_CAPACITY * sizeof(union nk_page_data); + page = (struct nk_page*)pool->alloc.alloc(pool->alloc.userdata,0, size); + page->next = pool->pages; + pool->pages = page; + page->size = 0; + } + } + return &pool->pages->win[pool->pages->size++]; +} + +/* =============================================================== + * + * CONTEXT + * + * ===============================================================*/ +NK_INTERN void* nk_create_window(struct nk_context *ctx); +NK_INTERN void nk_remove_window(struct nk_context*, struct nk_window*); +NK_INTERN void nk_free_window(struct nk_context *ctx, struct nk_window *win); +NK_INTERN void nk_free_table(struct nk_context *ctx, struct nk_table *tbl); +NK_INTERN void nk_remove_table(struct nk_window *win, struct nk_table *tbl); +NK_INTERN void* nk_create_panel(struct nk_context *ctx); +NK_INTERN void nk_free_panel(struct nk_context*, struct nk_panel *pan); + +NK_INTERN void +nk_setup(struct nk_context *ctx, const struct nk_user_font *font) +{ + NK_ASSERT(ctx); + if (!ctx) return; + nk_zero_struct(*ctx); + nk_style_default(ctx); + ctx->seq = 1; + if (font) ctx->style.font = font; +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT + nk_draw_list_init(&ctx->draw_list); +#endif +} + +#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR +NK_API int +nk_init_default(struct nk_context *ctx, const struct nk_user_font *font) +{ + struct nk_allocator alloc; + alloc.userdata.ptr = 0; + alloc.alloc = nk_malloc; + alloc.free = nk_mfree; + return nk_init(ctx, &alloc, font); +} +#endif + +NK_API int +nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, + const struct nk_user_font *font) +{ + NK_ASSERT(memory); + if (!memory) return 0; + nk_setup(ctx, font); + nk_buffer_init_fixed(&ctx->memory, memory, size); + ctx->use_pool = nk_false; + return 1; +} + +NK_API int +nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, + struct nk_buffer *pool, const struct nk_user_font *font) +{ + NK_ASSERT(cmds); + NK_ASSERT(pool); + if (!cmds || !pool) return 0; + + nk_setup(ctx, font); + ctx->memory = *cmds; + if (pool->type == NK_BUFFER_FIXED) { + /* take memory from buffer and alloc fixed pool */ + nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size); + } else { + /* create dynamic pool from buffer allocator */ + struct nk_allocator *alloc = &pool->pool; + nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY); + } + ctx->use_pool = nk_true; + return 1; +} + +NK_API int +nk_init(struct nk_context *ctx, struct nk_allocator *alloc, + const struct nk_user_font *font) +{ + NK_ASSERT(alloc); + if (!alloc) return 0; + nk_setup(ctx, font); + nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE); + nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY); + ctx->use_pool = nk_true; + return 1; +} + +#ifdef NK_INCLUDE_COMMAND_USERDATA +NK_API void +nk_set_user_data(struct nk_context *ctx, nk_handle handle) +{ + if (!ctx) return; + ctx->userdata = handle; + if (ctx->current) + ctx->current->buffer.userdata = handle; +} +#endif + +NK_API void +nk_free(struct nk_context *ctx) +{ + NK_ASSERT(ctx); + if (!ctx) return; + nk_buffer_free(&ctx->memory); + if (ctx->use_pool) + nk_pool_free(&ctx->pool); + + nk_zero(&ctx->input, sizeof(ctx->input)); + nk_zero(&ctx->style, sizeof(ctx->style)); + nk_zero(&ctx->memory, sizeof(ctx->memory)); + + ctx->seq = 0; + ctx->build = 0; + ctx->begin = 0; + ctx->end = 0; + ctx->active = 0; + ctx->current = 0; + ctx->freelist = 0; + ctx->count = 0; +} + +NK_API void +nk_clear(struct nk_context *ctx) +{ + struct nk_window *iter; + struct nk_window *next; + NK_ASSERT(ctx); + + if (!ctx) return; + if (ctx->use_pool) + nk_buffer_clear(&ctx->memory); + else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT); + + ctx->build = 0; + ctx->memory.calls = 0; + ctx->last_widget_state = 0; + ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW]; + NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay)); +#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT + nk_draw_list_clear(&ctx->draw_list); +#endif + + /* garbage collector */ + iter = ctx->begin; + while (iter) { + /* make sure minimized windows do not get removed */ + if ((iter->flags & NK_WINDOW_MINIMIZED) && + !(iter->flags & NK_WINDOW_CLOSED)) { + iter = iter->next; + continue; + } + /* remove hotness from hidden or closed windows*/ + if (((iter->flags & NK_WINDOW_HIDDEN) || + (iter->flags & NK_WINDOW_CLOSED)) && + iter == ctx->active) + ctx->active = iter->next; + + /* free unused popup windows */ + if (iter->popup.win && iter->popup.win->seq != ctx->seq) { + nk_free_window(ctx, iter->popup.win); + iter->popup.win = 0; + } + /* remove unused window state tables */ + {struct nk_table *n, *it = iter->tables; + while (it) { + n = it->next; + if (it->seq != ctx->seq) { + nk_remove_table(iter, it); + nk_zero(it, sizeof(union nk_page_data)); + nk_free_table(ctx, it); + if (it == iter->tables) + iter->tables = n; + } + it = n; + }} + /* window itself is not used anymore so free */ + if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) { + next = iter->next; + nk_remove_window(ctx, iter); + nk_free_window(ctx, iter); + iter = next; + } else iter = iter->next; + } + ctx->seq++; +} + +/* ---------------------------------------------------------------- + * + * BUFFERING + * + * ---------------------------------------------------------------*/ +NK_INTERN void +nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer) +{ + NK_ASSERT(ctx); + NK_ASSERT(buffer); + if (!ctx || !buffer) return; + buffer->begin = ctx->memory.allocated; + buffer->end = buffer->begin; + buffer->last = buffer->begin; + buffer->clip = nk_null_rect; +} + +NK_INTERN void +nk_start(struct nk_context *ctx, struct nk_window *win) +{ + NK_ASSERT(ctx); + NK_ASSERT(win); + nk_start_buffer(ctx, &win->buffer); +} + +NK_INTERN void +nk_start_popup(struct nk_context *ctx, struct nk_window *win) +{ + struct nk_popup_buffer *buf; + NK_ASSERT(ctx); + NK_ASSERT(win); + if (!ctx || !win) return; + + /* save buffer fill state for popup */ + buf = &win->popup.buf; + buf->begin = win->buffer.end; + buf->end = win->buffer.end; + buf->parent = win->buffer.last; + buf->last = buf->begin; + buf->active = nk_true; +} + +NK_INTERN void +nk_finish_popup(struct nk_context *ctx, struct nk_window *win) +{ + struct nk_popup_buffer *buf; + NK_ASSERT(ctx); + NK_ASSERT(win); + if (!ctx || !win) return; + + buf = &win->popup.buf; + buf->last = win->buffer.last; + buf->end = win->buffer.end; +} + +NK_INTERN void +nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer) +{ + NK_ASSERT(ctx); + NK_ASSERT(buffer); + if (!ctx || !buffer) return; + buffer->end = ctx->memory.allocated; +} + +NK_INTERN void +nk_finish(struct nk_context *ctx, struct nk_window *win) +{ + struct nk_popup_buffer *buf; + struct nk_command *parent_last; + void *memory; + + NK_ASSERT(ctx); + NK_ASSERT(win); + if (!ctx || !win) return; + nk_finish_buffer(ctx, &win->buffer); + if (!win->popup.buf.active) return; + + buf = &win->popup.buf; + memory = ctx->memory.memory.ptr; + parent_last = nk_ptr_add(struct nk_command, memory, buf->parent); + parent_last->next = buf->end; +} + +NK_INTERN void +nk_build(struct nk_context *ctx) +{ + struct nk_window *iter = 0; + struct nk_command *cmd = 0; + nk_byte *buffer = 0; + + /* draw cursor overlay */ + if (!ctx->style.cursor_active) + ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW]; + if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) { + struct nk_rect mouse_bounds; + const struct nk_cursor *cursor = ctx->style.cursor_active; + nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF); + nk_start_buffer(ctx, &ctx->overlay); + + mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x; + mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y; + mouse_bounds.w = cursor->size.x; + mouse_bounds.h = cursor->size.y; + + nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white); + nk_finish_buffer(ctx, &ctx->overlay); + } + /* build one big draw command list out of all window buffers */ + iter = ctx->begin; + buffer = (nk_byte*)ctx->memory.memory.ptr; + while (iter != 0) { + struct nk_window *next = iter->next; + if (iter->buffer.last == iter->buffer.begin || (iter->flags & NK_WINDOW_HIDDEN)|| + iter->seq != ctx->seq) + goto cont; + + cmd = nk_ptr_add(struct nk_command, buffer, iter->buffer.last); + while (next && ((next->buffer.last == next->buffer.begin) || + (next->flags & NK_WINDOW_HIDDEN))) + next = next->next; /* skip empty command buffers */ + + if (next) cmd->next = next->buffer.begin; + cont: iter = next; + } + /* append all popup draw commands into lists */ + iter = ctx->begin; + while (iter != 0) { + struct nk_window *next = iter->next; + struct nk_popup_buffer *buf; + if (!iter->popup.buf.active) + goto skip; + + buf = &iter->popup.buf; + cmd->next = buf->begin; + cmd = nk_ptr_add(struct nk_command, buffer, buf->last); + buf->active = nk_false; + skip: iter = next; + } + /* append overlay commands */ + if (cmd) { + if (ctx->overlay.end != ctx->overlay.begin) + cmd->next = ctx->overlay.begin; + else cmd->next = ctx->memory.allocated; + } +} + +NK_API const struct nk_command* +nk__begin(struct nk_context *ctx) +{ + struct nk_window *iter; + nk_byte *buffer; + NK_ASSERT(ctx); + if (!ctx) return 0; + if (!ctx->count) return 0; + + buffer = (nk_byte*)ctx->memory.memory.ptr; + if (!ctx->build) { + nk_build(ctx); + ctx->build = nk_true; + } + iter = ctx->begin; + while (iter && ((iter->buffer.begin == iter->buffer.end) || (iter->flags & NK_WINDOW_HIDDEN))) + iter = iter->next; + if (!iter) return 0; + return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin); +} + +NK_API const struct nk_command* +nk__next(struct nk_context *ctx, const struct nk_command *cmd) +{ + nk_byte *buffer; + const struct nk_command *next; + NK_ASSERT(ctx); + if (!ctx || !cmd || !ctx->count) return 0; + if (cmd->next >= ctx->memory.allocated) return 0; + buffer = (nk_byte*)ctx->memory.memory.ptr; + next = nk_ptr_add_const(struct nk_command, buffer, cmd->next); + return next; +} + +/* ---------------------------------------------------------------- + * + * PANEL + * + * ---------------------------------------------------------------*/ +static int +nk_panel_has_header(nk_flags flags, const char *title) +{ + int active = 0; + active = (flags & (NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE)); + active = active || (flags & NK_WINDOW_TITLE); + active = active && !(flags & NK_WINDOW_HIDDEN) && title; + return active; +} + +NK_INTERN struct nk_vec2 +nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type) +{ + switch (type) { + default: + case NK_PANEL_WINDOW: return style->window.padding; + case NK_PANEL_GROUP: return style->window.group_padding; + case NK_PANEL_POPUP: return style->window.popup_padding; + case NK_PANEL_CONTEXTUAL: return style->window.contextual_padding; + case NK_PANEL_COMBO: return style->window.combo_padding; + case NK_PANEL_MENU: return style->window.menu_padding; + case NK_PANEL_TOOLTIP: return style->window.menu_padding; + } +} + +NK_INTERN float +nk_panel_get_border(const struct nk_style *style, nk_flags flags, + enum nk_panel_type type) +{ + if (flags & NK_WINDOW_BORDER) { + switch (type) { + default: + case NK_PANEL_WINDOW: return style->window.border; + case NK_PANEL_GROUP: return style->window.group_border; + case NK_PANEL_POPUP: return style->window.popup_border; + case NK_PANEL_CONTEXTUAL: return style->window.contextual_border; + case NK_PANEL_COMBO: return style->window.combo_border; + case NK_PANEL_MENU: return style->window.menu_border; + case NK_PANEL_TOOLTIP: return style->window.menu_border; + }} else return 0; +} + +NK_INTERN struct nk_color +nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type) +{ + switch (type) { + default: + case NK_PANEL_WINDOW: return style->window.border_color; + case NK_PANEL_GROUP: return style->window.group_border_color; + case NK_PANEL_POPUP: return style->window.popup_border_color; + case NK_PANEL_CONTEXTUAL: return style->window.contextual_border_color; + case NK_PANEL_COMBO: return style->window.combo_border_color; + case NK_PANEL_MENU: return style->window.menu_border_color; + case NK_PANEL_TOOLTIP: return style->window.menu_border_color; + } +} + +NK_INTERN int +nk_panel_is_sub(enum nk_panel_type type) +{ + return (type & NK_PANEL_SET_SUB)?1:0; +} + +NK_INTERN int +nk_panel_is_nonblock(enum nk_panel_type type) +{ + return (type & NK_PANEL_SET_NONBLOCK)?1:0; +} + +NK_INTERN int +nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type) +{ + struct nk_input *in; + struct nk_window *win; + struct nk_panel *layout; + struct nk_command_buffer *out; + const struct nk_style *style; + const struct nk_user_font *font; + + struct nk_vec2 scrollbar_size; + struct nk_vec2 panel_padding; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) return 0; + nk_zero(ctx->current->layout, sizeof(*ctx->current->layout)); + if ((ctx->current->flags & NK_WINDOW_HIDDEN) || (ctx->current->flags & NK_WINDOW_CLOSED)) { + nk_zero(ctx->current->layout, sizeof(struct nk_panel)); + ctx->current->layout->type = panel_type; + return 0; + } + /* pull state into local stack */ + style = &ctx->style; + font = style->font; + win = ctx->current; + layout = win->layout; + out = &win->buffer; + in = (win->flags & NK_WINDOW_NO_INPUT) ? 0: &ctx->input; +#ifdef NK_INCLUDE_COMMAND_USERDATA + win->buffer.userdata = ctx->userdata; +#endif + /* pull style configuration into local stack */ + scrollbar_size = style->window.scrollbar_size; + panel_padding = nk_panel_get_padding(style, panel_type); + + /* window movement */ + if ((win->flags & NK_WINDOW_MOVABLE) && !(win->flags & NK_WINDOW_ROM)) { + int left_mouse_down; + int left_mouse_click_in_cursor; + + /* calculate draggable window space */ + struct nk_rect header; + header.x = win->bounds.x; + header.y = win->bounds.y; + header.w = win->bounds.w; + if (nk_panel_has_header(win->flags, title)) { + header.h = font->height + 2.0f * style->window.header.padding.y; + header.h += 2.0f * style->window.header.label_padding.y; + } else header.h = panel_padding.y; + + /* window movement by dragging */ + left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; + left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in, + NK_BUTTON_LEFT, header, nk_true); + if (left_mouse_down && left_mouse_click_in_cursor) { + win->bounds.x = win->bounds.x + in->mouse.delta.x; + win->bounds.y = win->bounds.y + in->mouse.delta.y; + in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x += in->mouse.delta.x; + in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y += in->mouse.delta.y; + ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_MOVE]; + } + } + + /* setup panel */ + layout->type = panel_type; + layout->flags = win->flags; + layout->bounds = win->bounds; + layout->bounds.x += panel_padding.x; + layout->bounds.w -= 2*panel_padding.x; + if (win->flags & NK_WINDOW_BORDER) { + layout->border = nk_panel_get_border(style, win->flags, panel_type); + layout->bounds = nk_shrink_rect(layout->bounds, layout->border); + } else layout->border = 0; + layout->at_y = layout->bounds.y; + layout->at_x = layout->bounds.x; + layout->max_x = 0; + layout->header_height = 0; + layout->footer_height = 0; + nk_layout_reset_min_row_height(ctx); + layout->row.index = 0; + layout->row.columns = 0; + layout->row.ratio = 0; + layout->row.item_width = 0; + layout->row.tree_depth = 0; + layout->row.height = panel_padding.y; + layout->has_scrolling = nk_true; + if (!(win->flags & NK_WINDOW_NO_SCROLLBAR)) + layout->bounds.w -= scrollbar_size.x; + if (!nk_panel_is_nonblock(panel_type)) { + layout->footer_height = 0; + if (!(win->flags & NK_WINDOW_NO_SCROLLBAR) || win->flags & NK_WINDOW_SCALABLE) + layout->footer_height = scrollbar_size.y; + layout->bounds.h -= layout->footer_height; + } + + /* panel header */ + if (nk_panel_has_header(win->flags, title)) + { + struct nk_text text; + struct nk_rect header; + const struct nk_style_item *background = 0; + + /* calculate header bounds */ + header.x = win->bounds.x; + header.y = win->bounds.y; + header.w = win->bounds.w; + header.h = font->height + 2.0f * style->window.header.padding.y; + header.h += (2.0f * style->window.header.label_padding.y); + + /* shrink panel by header */ + layout->header_height = header.h; + layout->bounds.y += header.h; + layout->bounds.h -= header.h; + layout->at_y += header.h; + + /* select correct header background and text color */ + if (ctx->active == win) { + background = &style->window.header.active; + text.text = style->window.header.label_active; + } else if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) { + background = &style->window.header.hover; + text.text = style->window.header.label_hover; + } else { + background = &style->window.header.normal; + text.text = style->window.header.label_normal; + } + + /* draw header background */ + header.h += 1.0f; + if (background->type == NK_STYLE_ITEM_IMAGE) { + text.background = nk_rgba(0,0,0,0); + nk_draw_image(&win->buffer, header, &background->data.image, nk_white); + } else { + text.background = background->data.color; + nk_fill_rect(out, header, 0, background->data.color); + } + + /* window close button */ + {struct nk_rect button; + button.y = header.y + style->window.header.padding.y; + button.h = header.h - 2 * style->window.header.padding.y; + button.w = button.h; + if (win->flags & NK_WINDOW_CLOSABLE) { + nk_flags ws = 0; + if (style->window.header.align == NK_HEADER_RIGHT) { + button.x = (header.w + header.x) - (button.w + style->window.header.padding.x); + header.w -= button.w + style->window.header.spacing.x + style->window.header.padding.x; + } else { + button.x = header.x + style->window.header.padding.x; + header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x; + } + + if (nk_do_button_symbol(&ws, &win->buffer, button, + style->window.header.close_symbol, NK_BUTTON_DEFAULT, + &style->window.header.close_button, in, style->font) && !(win->flags & NK_WINDOW_ROM)) + { + layout->flags |= NK_WINDOW_HIDDEN; + layout->flags &= (nk_flags)~NK_WINDOW_MINIMIZED; + } + } + + /* window minimize button */ + if (win->flags & NK_WINDOW_MINIMIZABLE) { + nk_flags ws = 0; + if (style->window.header.align == NK_HEADER_RIGHT) { + button.x = (header.w + header.x) - button.w; + if (!(win->flags & NK_WINDOW_CLOSABLE)) { + button.x -= style->window.header.padding.x; + header.w -= style->window.header.padding.x; + } + header.w -= button.w + style->window.header.spacing.x; + } else { + button.x = header.x; + header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x; + } + if (nk_do_button_symbol(&ws, &win->buffer, button, (layout->flags & NK_WINDOW_MINIMIZED)? + style->window.header.maximize_symbol: style->window.header.minimize_symbol, + NK_BUTTON_DEFAULT, &style->window.header.minimize_button, in, style->font) && !(win->flags & NK_WINDOW_ROM)) + layout->flags = (layout->flags & NK_WINDOW_MINIMIZED) ? + layout->flags & (nk_flags)~NK_WINDOW_MINIMIZED: + layout->flags | NK_WINDOW_MINIMIZED; + }} + + {/* window header title */ + int text_len = nk_strlen(title); + struct nk_rect label = {0,0,0,0}; + float t = font->width(font->userdata, font->height, title, text_len); + text.padding = nk_vec2(0,0); + + label.x = header.x + style->window.header.padding.x; + label.x += style->window.header.label_padding.x; + label.y = header.y + style->window.header.label_padding.y; + label.h = font->height + 2 * style->window.header.label_padding.y; + label.w = t + 2 * style->window.header.spacing.x; + label.w = NK_CLAMP(0, label.w, header.x + header.w - label.x); + nk_widget_text(out, label,(const char*)title, text_len, &text, NK_TEXT_LEFT, font);} + } + + /* draw window background */ + if (!(layout->flags & NK_WINDOW_MINIMIZED) && !(layout->flags & NK_WINDOW_DYNAMIC)) { + struct nk_rect body; + body.x = win->bounds.x; + body.w = win->bounds.w; + body.y = (win->bounds.y + layout->header_height); + body.h = (win->bounds.h - layout->header_height); + if (style->window.fixed_background.type == NK_STYLE_ITEM_IMAGE) + nk_draw_image(out, body, &style->window.fixed_background.data.image, nk_white); + else nk_fill_rect(out, body, 0, style->window.fixed_background.data.color); + } + + /* set clipping rectangle */ + {struct nk_rect clip; + layout->clip = layout->bounds; + nk_unify(&clip, &win->buffer.clip, layout->clip.x, layout->clip.y, + layout->clip.x + layout->clip.w, layout->clip.y + layout->clip.h); + nk_push_scissor(out, clip); + layout->clip = clip;} + return !(layout->flags & NK_WINDOW_HIDDEN) && !(layout->flags & NK_WINDOW_MINIMIZED); +} + +NK_INTERN void +nk_panel_end(struct nk_context *ctx) +{ + struct nk_input *in; + struct nk_window *window; + struct nk_panel *layout; + const struct nk_style *style; + struct nk_command_buffer *out; + + struct nk_vec2 scrollbar_size; + struct nk_vec2 panel_padding; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + window = ctx->current; + layout = window->layout; + style = &ctx->style; + out = &window->buffer; + in = (layout->flags & NK_WINDOW_ROM || layout->flags & NK_WINDOW_NO_INPUT) ? 0 :&ctx->input; + if (!nk_panel_is_sub(layout->type)) + nk_push_scissor(out, nk_null_rect); + + /* cache configuration data */ + scrollbar_size = style->window.scrollbar_size; + panel_padding = nk_panel_get_padding(style, layout->type); + + /* update the current cursor Y-position to point over the last added widget */ + layout->at_y += layout->row.height; + + /* dynamic panels */ + if (layout->flags & NK_WINDOW_DYNAMIC && !(layout->flags & NK_WINDOW_MINIMIZED)) + { + /* update panel height to fit dynamic growth */ + struct nk_rect empty_space; + if (layout->at_y < (layout->bounds.y + layout->bounds.h)) + layout->bounds.h = layout->at_y - layout->bounds.y; + + /* fill top empty space */ + empty_space.x = window->bounds.x; + empty_space.y = layout->bounds.y; + empty_space.h = panel_padding.y; + empty_space.w = window->bounds.w; + nk_fill_rect(out, empty_space, 0, style->window.background); + + /* fill left empty space */ + empty_space.x = window->bounds.x; + empty_space.y = layout->bounds.y; + empty_space.w = panel_padding.x + layout->border; + empty_space.h = layout->bounds.h; + nk_fill_rect(out, empty_space, 0, style->window.background); + + /* fill right empty space */ + empty_space.x = layout->bounds.x + layout->bounds.w - layout->border; + empty_space.y = layout->bounds.y; + empty_space.w = panel_padding.x + layout->border; + empty_space.h = layout->bounds.h; + if (*layout->offset_y == 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR)) + empty_space.w += scrollbar_size.x; + nk_fill_rect(out, empty_space, 0, style->window.background); + + /* fill bottom empty space */ + if (*layout->offset_x != 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR)) { + empty_space.x = window->bounds.x; + empty_space.y = layout->bounds.y + layout->bounds.h; + empty_space.w = window->bounds.w; + empty_space.h = scrollbar_size.y; + nk_fill_rect(out, empty_space, 0, style->window.background); + } + } + + /* scrollbars */ + if (!(layout->flags & NK_WINDOW_NO_SCROLLBAR) && + !(layout->flags & NK_WINDOW_MINIMIZED) && + window->scrollbar_hiding_timer < NK_SCROLLBAR_HIDING_TIMEOUT) + { + struct nk_rect scroll; + int scroll_has_scrolling; + float scroll_target; + float scroll_offset; + float scroll_step; + float scroll_inc; + + /* mouse wheel scrolling */ + if (nk_panel_is_sub(layout->type)) + { + /* sub-window mouse wheel scrolling */ + struct nk_window *root_window = window; + struct nk_panel *root_panel = window->layout; + while (root_panel->parent) + root_panel = root_panel->parent; + while (root_window->parent) + root_window = root_window->parent; + + /* only allow scrolling if parent window is active */ + scroll_has_scrolling = 0; + if ((root_window == ctx->active) && layout->has_scrolling) { + /* and panel is being hovered and inside clip rect*/ + if (nk_input_is_mouse_hovering_rect(in, layout->bounds) && + NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h, + root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h)) + { + /* deactivate all parent scrolling */ + root_panel = window->layout; + while (root_panel->parent) { + root_panel->has_scrolling = nk_false; + root_panel = root_panel->parent; + } + root_panel->has_scrolling = nk_false; + scroll_has_scrolling = nk_true; + } + } + } else if (!nk_panel_is_sub(layout->type)) { + /* window mouse wheel scrolling */ + scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling; + if (in && (in->mouse.scroll_delta.y > 0 || in->mouse.scroll_delta.x > 0) && scroll_has_scrolling) + window->scrolled = nk_true; + else window->scrolled = nk_false; + } else scroll_has_scrolling = nk_false; + + { + /* vertical scrollbar */ + nk_flags state = 0; + scroll.x = layout->bounds.x + layout->bounds.w + panel_padding.x; + scroll.y = layout->bounds.y; + scroll.w = scrollbar_size.x; + scroll.h = layout->bounds.h; + + scroll_offset = (float)*layout->offset_y; + scroll_step = scroll.h * 0.10f; + scroll_inc = scroll.h * 0.01f; + scroll_target = (float)(int)(layout->at_y - scroll.y); + scroll_offset = nk_do_scrollbarv(&state, out, scroll, scroll_has_scrolling, + scroll_offset, scroll_target, scroll_step, scroll_inc, + &ctx->style.scrollv, in, style->font); + *layout->offset_y = (nk_uint)scroll_offset; + if (in && scroll_has_scrolling) + in->mouse.scroll_delta.y = 0; + } + { + /* horizontal scrollbar */ + nk_flags state = 0; + scroll.x = layout->bounds.x; + scroll.y = layout->bounds.y + layout->bounds.h; + scroll.w = layout->bounds.w; + scroll.h = scrollbar_size.y; + + scroll_offset = (float)*layout->offset_x; + scroll_target = (float)(int)(layout->max_x - scroll.x); + scroll_step = layout->max_x * 0.05f; + scroll_inc = layout->max_x * 0.005f; + scroll_offset = nk_do_scrollbarh(&state, out, scroll, scroll_has_scrolling, + scroll_offset, scroll_target, scroll_step, scroll_inc, + &ctx->style.scrollh, in, style->font); + *layout->offset_x = (nk_uint)scroll_offset; + } + } + + /* hide scroll if no user input */ + if (window->flags & NK_WINDOW_SCROLL_AUTO_HIDE) { + int has_input = ctx->input.mouse.delta.x != 0 || ctx->input.mouse.delta.y != 0 || ctx->input.mouse.scroll_delta.y != 0; + int is_window_hovered = nk_window_is_hovered(ctx); + int any_item_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED); + if ((!has_input && is_window_hovered) || (!is_window_hovered && !any_item_active)) + window->scrollbar_hiding_timer += ctx->delta_time_seconds; + else window->scrollbar_hiding_timer = 0; + } else window->scrollbar_hiding_timer = 0; + + /* window border */ + if (layout->flags & NK_WINDOW_BORDER) + { + struct nk_color border_color = nk_panel_get_border_color(style, layout->type); + const float padding_y = (layout->flags & NK_WINDOW_MINIMIZED) ? + style->window.border + window->bounds.y + layout->header_height: + (layout->flags & NK_WINDOW_DYNAMIC)? + layout->bounds.y + layout->bounds.h + layout->footer_height: + window->bounds.y + window->bounds.h; + + /* draw border top */ + nk_stroke_line(out,window->bounds.x,window->bounds.y, + window->bounds.x + window->bounds.w, window->bounds.y, + layout->border, border_color); + + /* draw bottom border */ + nk_stroke_line(out, window->bounds.x, padding_y, + window->bounds.x + window->bounds.w, padding_y, layout->border, border_color); + + /* draw left border */ + nk_stroke_line(out, window->bounds.x + layout->border*0.5f, + window->bounds.y, window->bounds.x + layout->border*0.5f, + padding_y, layout->border, border_color); + + /* draw right border */ + nk_stroke_line(out, window->bounds.x + window->bounds.w - layout->border*0.5f, + window->bounds.y, window->bounds.x + window->bounds.w - layout->border*0.5f, + padding_y, layout->border, border_color); + } + + /* scaler */ + if ((layout->flags & NK_WINDOW_SCALABLE) && in && !(layout->flags & NK_WINDOW_MINIMIZED)) + { + /* calculate scaler bounds */ + struct nk_rect scaler; + scaler.w = scrollbar_size.x; + scaler.h = scrollbar_size.y; + scaler.y = layout->bounds.y + layout->bounds.h; + if (layout->flags & NK_WINDOW_SCALE_LEFT) + scaler.x = layout->bounds.x - panel_padding.x * 0.5f; + else scaler.x = layout->bounds.x + layout->bounds.w + panel_padding.x; + if (layout->flags & NK_WINDOW_NO_SCROLLBAR) + scaler.x -= scaler.w; + + /* draw scaler */ + {const struct nk_style_item *item = &style->window.scaler; + if (item->type == NK_STYLE_ITEM_IMAGE) + nk_draw_image(out, scaler, &item->data.image, nk_white); + else { + if (layout->flags & NK_WINDOW_SCALE_LEFT) { + nk_fill_triangle(out, scaler.x, scaler.y, scaler.x, + scaler.y + scaler.h, scaler.x + scaler.w, + scaler.y + scaler.h, item->data.color); + } else { + nk_fill_triangle(out, scaler.x + scaler.w, scaler.y, scaler.x + scaler.w, + scaler.y + scaler.h, scaler.x, scaler.y + scaler.h, item->data.color); + } + }} + + /* do window scaling */ + if (!(window->flags & NK_WINDOW_ROM)) { + struct nk_vec2 window_size = style->window.min_size; + int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; + int left_mouse_click_in_scaler = nk_input_has_mouse_click_down_in_rect(in, + NK_BUTTON_LEFT, scaler, nk_true); + + if (left_mouse_down && left_mouse_click_in_scaler) { + float delta_x = in->mouse.delta.x; + if (layout->flags & NK_WINDOW_SCALE_LEFT) { + delta_x = -delta_x; + window->bounds.x += in->mouse.delta.x; + } + /* dragging in x-direction */ + if (window->bounds.w + delta_x >= window_size.x) { + if ((delta_x < 0) || (delta_x > 0 && in->mouse.pos.x >= scaler.x)) { + window->bounds.w = window->bounds.w + delta_x; + scaler.x += in->mouse.delta.x; + } + } + /* dragging in y-direction (only possible if static window) */ + if (!(layout->flags & NK_WINDOW_DYNAMIC)) { + if (window_size.y < window->bounds.h + in->mouse.delta.y) { + if ((in->mouse.delta.y < 0) || (in->mouse.delta.y > 0 && in->mouse.pos.y >= scaler.y)) { + window->bounds.h = window->bounds.h + in->mouse.delta.y; + scaler.y += in->mouse.delta.y; + } + } + } + ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT]; + in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f; + in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f; + } + } + } + if (!nk_panel_is_sub(layout->type)) { + /* window is hidden so clear command buffer */ + if (layout->flags & NK_WINDOW_HIDDEN) + nk_command_buffer_reset(&window->buffer); + /* window is visible and not tab */ + else nk_finish(ctx, window); + } + + /* NK_WINDOW_REMOVE_ROM flag was set so remove NK_WINDOW_ROM */ + if (layout->flags & NK_WINDOW_REMOVE_ROM) { + layout->flags &= ~(nk_flags)NK_WINDOW_ROM; + layout->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM; + } + window->flags = layout->flags; + + /* property garbage collector */ + if (window->property.active && window->property.old != window->property.seq && + window->property.active == window->property.prev) { + nk_zero(&window->property, sizeof(window->property)); + } else { + window->property.old = window->property.seq; + window->property.prev = window->property.active; + window->property.seq = 0; + } + /* edit garbage collector */ + if (window->edit.active && window->edit.old != window->edit.seq && + window->edit.active == window->edit.prev) { + nk_zero(&window->edit, sizeof(window->edit)); + } else { + window->edit.old = window->edit.seq; + window->edit.prev = window->edit.active; + window->edit.seq = 0; + } + /* contextual garbage collector */ + if (window->popup.active_con && window->popup.con_old != window->popup.con_count) { + window->popup.con_count = 0; + window->popup.con_old = 0; + window->popup.active_con = 0; + } else { + window->popup.con_old = window->popup.con_count; + window->popup.con_count = 0; + } + window->popup.combo_count = 0; + /* helper to make sure you have a 'nk_tree_push' for every 'nk_tree_pop' */ + NK_ASSERT(!layout->row.tree_depth); +} + +/* ---------------------------------------------------------------- + * + * PAGE ELEMENT + * + * ---------------------------------------------------------------*/ +NK_INTERN struct nk_page_element* +nk_create_page_element(struct nk_context *ctx) +{ + struct nk_page_element *elem; + if (ctx->freelist) { + /* unlink page element from free list */ + elem = ctx->freelist; + ctx->freelist = elem->next; + } else if (ctx->use_pool) { + /* allocate page element from memory pool */ + elem = nk_pool_alloc(&ctx->pool); + NK_ASSERT(elem); + if (!elem) return 0; + } else { + /* allocate new page element from back of fixed size memory buffer */ + NK_STORAGE const nk_size size = sizeof(struct nk_page_element); + NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_page_element); + elem = (struct nk_page_element*)nk_buffer_alloc(&ctx->memory, NK_BUFFER_BACK, size, align); + NK_ASSERT(elem); + if (!elem) return 0; + } + nk_zero_struct(*elem); + elem->next = 0; + elem->prev = 0; + return elem; +} + +NK_INTERN void +nk_link_page_element_into_freelist(struct nk_context *ctx, + struct nk_page_element *elem) +{ + /* link table into freelist */ + if (!ctx->freelist) { + ctx->freelist = elem; + } else { + elem->next = ctx->freelist; + ctx->freelist = elem; + } +} + +NK_INTERN void +nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem) +{ + /* we have a pool so just add to free list */ + if (ctx->use_pool) { + nk_link_page_element_into_freelist(ctx, elem); + return; + } + /* if possible remove last element from back of fixed memory buffer */ + {void *elem_end = (void*)(elem + 1); + void *buffer_end = (nk_byte*)ctx->memory.memory.ptr + ctx->memory.size; + if (elem_end == buffer_end) + ctx->memory.size -= sizeof(struct nk_page_element); + else nk_link_page_element_into_freelist(ctx, elem);} +} + +/* ---------------------------------------------------------------- + * + * PANEL + * + * ---------------------------------------------------------------*/ +NK_INTERN void* +nk_create_panel(struct nk_context *ctx) +{ + struct nk_page_element *elem; + elem = nk_create_page_element(ctx); + if (!elem) return 0; + nk_zero_struct(*elem); + return &elem->data.pan; +} + +NK_INTERN void +nk_free_panel(struct nk_context *ctx, struct nk_panel *pan) +{ + union nk_page_data *pd = NK_CONTAINER_OF(pan, union nk_page_data, pan); + struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); + nk_free_page_element(ctx, pe); +} + +/* ---------------------------------------------------------------- + * + * TABLES + * + * ---------------------------------------------------------------*/ +NK_INTERN struct nk_table* +nk_create_table(struct nk_context *ctx) +{ + struct nk_page_element *elem; + elem = nk_create_page_element(ctx); + if (!elem) return 0; + nk_zero_struct(*elem); + return &elem->data.tbl; +} + +NK_INTERN void +nk_free_table(struct nk_context *ctx, struct nk_table *tbl) +{ + union nk_page_data *pd = NK_CONTAINER_OF(tbl, union nk_page_data, tbl); + struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); + nk_free_page_element(ctx, pe); +} + +NK_INTERN void +nk_push_table(struct nk_window *win, struct nk_table *tbl) +{ + if (!win->tables) { + win->tables = tbl; + tbl->next = 0; + tbl->prev = 0; + tbl->size = 0; + win->table_count = 1; + return; + } + win->tables->prev = tbl; + tbl->next = win->tables; + tbl->prev = 0; + tbl->size = 0; + win->tables = tbl; + win->table_count++; +} + +NK_INTERN void +nk_remove_table(struct nk_window *win, struct nk_table *tbl) +{ + if (win->tables == tbl) + win->tables = tbl->next; + if (tbl->next) + tbl->next->prev = tbl->prev; + if (tbl->prev) + tbl->prev->next = tbl->next; + tbl->next = 0; + tbl->prev = 0; +} + +NK_INTERN nk_uint* +nk_add_value(struct nk_context *ctx, struct nk_window *win, + nk_hash name, nk_uint value) +{ + NK_ASSERT(ctx); + NK_ASSERT(win); + if (!win || !ctx) return 0; + if (!win->tables || win->tables->size >= NK_VALUE_PAGE_CAPACITY) { + struct nk_table *tbl = nk_create_table(ctx); + NK_ASSERT(tbl); + if (!tbl) return 0; + nk_push_table(win, tbl); + } + win->tables->seq = win->seq; + win->tables->keys[win->tables->size] = name; + win->tables->values[win->tables->size] = value; + return &win->tables->values[win->tables->size++]; +} + +NK_INTERN nk_uint* +nk_find_value(struct nk_window *win, nk_hash name) +{ + struct nk_table *iter = win->tables; + while (iter) { + unsigned int i = 0; + unsigned int size = iter->size; + for (i = 0; i < size; ++i) { + if (iter->keys[i] == name) { + iter->seq = win->seq; + return &iter->values[i]; + } + } size = NK_VALUE_PAGE_CAPACITY; + iter = iter->next; + } + return 0; +} + +/* ---------------------------------------------------------------- + * + * WINDOW + * + * ---------------------------------------------------------------*/ +NK_INTERN void* +nk_create_window(struct nk_context *ctx) +{ + struct nk_page_element *elem; + elem = nk_create_page_element(ctx); + if (!elem) return 0; + elem->data.win.seq = ctx->seq; + return &elem->data.win; +} + +NK_INTERN void +nk_free_window(struct nk_context *ctx, struct nk_window *win) +{ + /* unlink windows from list */ + struct nk_table *it = win->tables; + if (win->popup.win) { + nk_free_window(ctx, win->popup.win); + win->popup.win = 0; + } + win->next = 0; + win->prev = 0; + + while (it) { + /*free window state tables */ + struct nk_table *n = it->next; + nk_remove_table(win, it); + nk_free_table(ctx, it); + if (it == win->tables) + win->tables = n; + it = n; + } + + /* link windows into freelist */ + {union nk_page_data *pd = NK_CONTAINER_OF(win, union nk_page_data, win); + struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); + nk_free_page_element(ctx, pe);} +} + +NK_INTERN struct nk_window* +nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name) +{ + struct nk_window *iter; + iter = ctx->begin; + while (iter) { + NK_ASSERT(iter != iter->next); + if (iter->name == hash) { + int max_len = nk_strlen(iter->name_string); + if (!nk_stricmpn(iter->name_string, name, max_len)) + return iter; + } + iter = iter->next; + } + return 0; +} + +enum nk_window_insert_location { + NK_INSERT_BACK, /* inserts window into the back of list (front of screen) */ + NK_INSERT_FRONT /* inserts window into the front of list (back of screen) */ +}; +NK_INTERN void +nk_insert_window(struct nk_context *ctx, struct nk_window *win, + enum nk_window_insert_location loc) +{ + const struct nk_window *iter; + NK_ASSERT(ctx); + NK_ASSERT(win); + if (!win || !ctx) return; + + iter = ctx->begin; + while (iter) { + NK_ASSERT(iter != iter->next); + NK_ASSERT(iter != win); + if (iter == win) return; + iter = iter->next; + } + + if (!ctx->begin) { + win->next = 0; + win->prev = 0; + ctx->begin = win; + ctx->end = win; + ctx->count = 1; + return; + } + if (loc == NK_INSERT_BACK) { + struct nk_window *end; + end = ctx->end; + end->flags |= NK_WINDOW_ROM; + end->next = win; + win->prev = ctx->end; + win->next = 0; + ctx->end = win; + ctx->active = ctx->end; + ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM; + } else { + ctx->end->flags |= NK_WINDOW_ROM; + ctx->begin->prev = win; + win->next = ctx->begin; + win->prev = 0; + ctx->begin = win; + ctx->begin->flags &= ~(nk_flags)NK_WINDOW_ROM; + } + ctx->count++; +} + +NK_INTERN void +nk_remove_window(struct nk_context *ctx, struct nk_window *win) +{ + if (win == ctx->begin || win == ctx->end) { + if (win == ctx->begin) { + ctx->begin = win->next; + if (win->next) + win->next->prev = 0; + } + if (win == ctx->end) { + ctx->end = win->prev; + if (win->prev) + win->prev->next = 0; + } + } else { + if (win->next) + win->next->prev = win->prev; + if (win->prev) + win->prev->next = win->next; + } + if (win == ctx->active || !ctx->active) { + ctx->active = ctx->end; + if (ctx->end) + ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM; + } + win->next = 0; + win->prev = 0; + ctx->count--; +} + +NK_API int +nk_begin(struct nk_context *ctx, const char *title, + struct nk_rect bounds, nk_flags flags) +{ + return nk_begin_titled(ctx, title, title, bounds, flags); +} + +NK_API int +nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, + struct nk_rect bounds, nk_flags flags) +{ + struct nk_window *win; + struct nk_style *style; + nk_hash title_hash; + int title_len; + int ret = 0; + + NK_ASSERT(ctx); + NK_ASSERT(name); + NK_ASSERT(title); + NK_ASSERT(ctx->style.font && ctx->style.font->width && "if this triggers you forgot to add a font"); + NK_ASSERT(!ctx->current && "if this triggers you missed a `nk_end` call"); + if (!ctx || ctx->current || !title || !name) + return 0; + + /* find or create window */ + style = &ctx->style; + title_len = (int)nk_strlen(name); + title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); + win = nk_find_window(ctx, title_hash, name); + if (!win) { + /* create new window */ + nk_size name_length = (nk_size)nk_strlen(name); + win = (struct nk_window*)nk_create_window(ctx); + NK_ASSERT(win); + if (!win) return 0; + + if (flags & NK_WINDOW_BACKGROUND) + nk_insert_window(ctx, win, NK_INSERT_FRONT); + else nk_insert_window(ctx, win, NK_INSERT_BACK); + nk_command_buffer_init(&win->buffer, &ctx->memory, NK_CLIPPING_ON); + + win->flags = flags; + win->bounds = bounds; + win->name = title_hash; + name_length = NK_MIN(name_length, NK_WINDOW_MAX_NAME-1); + NK_MEMCPY(win->name_string, name, name_length); + win->name_string[name_length] = 0; + win->popup.win = 0; + if (!ctx->active) + ctx->active = win; + } else { + /* update window */ + win->flags &= ~(nk_flags)(NK_WINDOW_PRIVATE-1); + win->flags |= flags; + if (!(win->flags & (NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE))) + win->bounds = bounds; + /* If this assert triggers you either: + * + * I.) Have more than one window with the same name or + * II.) You forgot to actually draw the window. + * More specific you did not call `nk_clear` (nk_clear will be + * automatically called for you if you are using one of the + * provided demo backends). */ + NK_ASSERT(win->seq != ctx->seq); + win->seq = ctx->seq; + if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN)) + ctx->active = win; + } + if (win->flags & NK_WINDOW_HIDDEN) { + ctx->current = win; + win->layout = 0; + return 0; + } + + /* window overlapping */ + if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT)) + { + int inpanel, ishovered; + const struct nk_window *iter = win; + float h = ctx->style.font->height + 2.0f * style->window.header.padding.y + + (2.0f * style->window.header.label_padding.y); + struct nk_rect win_bounds = (!(win->flags & NK_WINDOW_MINIMIZED))? + win->bounds: nk_rect(win->bounds.x, win->bounds.y, win->bounds.w, h); + + /* activate window if hovered and no other window is overlapping this window */ + nk_start(ctx, win); + inpanel = nk_input_has_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_LEFT, win_bounds, nk_true); + inpanel = inpanel && ctx->input.mouse.buttons[NK_BUTTON_LEFT].clicked; + ishovered = nk_input_is_mouse_hovering_rect(&ctx->input, win_bounds); + if ((win != ctx->active) && ishovered && !ctx->input.mouse.buttons[NK_BUTTON_LEFT].down) { + iter = win->next; + while (iter) { + struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))? + iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h); + if (NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, + iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) && + (!(iter->flags & NK_WINDOW_HIDDEN) || !(iter->flags & NK_WINDOW_BACKGROUND))) + break; + + if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) && + NK_INTERSECT(win->bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, + iter->popup.win->bounds.x, iter->popup.win->bounds.y, + iter->popup.win->bounds.w, iter->popup.win->bounds.h)) + break; + iter = iter->next; + } + } + + /* activate window if clicked */ + if (iter && inpanel && (win != ctx->end) && !(iter->flags & NK_WINDOW_BACKGROUND)) { + iter = win->next; + while (iter) { + /* try to find a panel with higher priority in the same position */ + struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))? + iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h); + if (NK_INBOX(ctx->input.mouse.pos.x, ctx->input.mouse.pos.y, + iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) && + !(iter->flags & NK_WINDOW_HIDDEN)) + break; + if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) && + NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, + iter->popup.win->bounds.x, iter->popup.win->bounds.y, + iter->popup.win->bounds.w, iter->popup.win->bounds.h)) + break; + iter = iter->next; + } + } + + if (!iter && ctx->end != win) { + if (!(win->flags & NK_WINDOW_BACKGROUND)) { + /* current window is active in that position so transfer to top + * at the highest priority in stack */ + nk_remove_window(ctx, win); + nk_insert_window(ctx, win, NK_INSERT_BACK); + } + win->flags &= ~(nk_flags)NK_WINDOW_ROM; + ctx->active = win; + } + if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND)) + win->flags |= NK_WINDOW_ROM; + } + + win->layout = (struct nk_panel*)nk_create_panel(ctx); + ctx->current = win; + ret = nk_panel_begin(ctx, title, NK_PANEL_WINDOW); + win->layout->offset_x = &win->scrollbar.x; + win->layout->offset_y = &win->scrollbar.y; + return ret; +} + +NK_API void +nk_end(struct nk_context *ctx) +{ + struct nk_panel *layout; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current && "if this triggers you forgot to call `nk_begin`"); + if (!ctx || !ctx->current) + return; + + layout = ctx->current->layout; + if (!layout || (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN))) { + ctx->current = 0; + return; + } + nk_panel_end(ctx); + nk_free_panel(ctx, ctx->current->layout); + ctx->current = 0; +} + +NK_API struct nk_rect +nk_window_get_bounds(const struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return nk_rect(0,0,0,0); + return ctx->current->bounds; +} + +NK_API struct nk_vec2 +nk_window_get_position(const struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return nk_vec2(0,0); + return nk_vec2(ctx->current->bounds.x, ctx->current->bounds.y); +} + +NK_API struct nk_vec2 +nk_window_get_size(const struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return nk_vec2(0,0); + return nk_vec2(ctx->current->bounds.w, ctx->current->bounds.h); +} + +NK_API float +nk_window_get_width(const struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return 0; + return ctx->current->bounds.w; +} + +NK_API float +nk_window_get_height(const struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return 0; + return ctx->current->bounds.h; +} + +NK_API struct nk_rect +nk_window_get_content_region(struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return nk_rect(0,0,0,0); + return ctx->current->layout->clip; +} + +NK_API struct nk_vec2 +nk_window_get_content_region_min(struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current) return nk_vec2(0,0); + return nk_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y); +} + +NK_API struct nk_vec2 +nk_window_get_content_region_max(struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current) return nk_vec2(0,0); + return nk_vec2(ctx->current->layout->clip.x + ctx->current->layout->clip.w, + ctx->current->layout->clip.y + ctx->current->layout->clip.h); +} + +NK_API struct nk_vec2 +nk_window_get_content_region_size(struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current) return nk_vec2(0,0); + return nk_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h); +} + +NK_API struct nk_command_buffer* +nk_window_get_canvas(struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current) return 0; + return &ctx->current->buffer; +} + +NK_API struct nk_panel* +nk_window_get_panel(struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return 0; + return ctx->current->layout; +} + +NK_API int +nk_window_has_focus(const struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current) return 0; + return ctx->current == ctx->active; +} + +NK_API int +nk_window_is_hovered(struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return 0; + return nk_input_is_mouse_hovering_rect(&ctx->input, ctx->current->bounds); +} + +NK_API int +nk_window_is_any_hovered(struct nk_context *ctx) +{ + struct nk_window *iter; + NK_ASSERT(ctx); + if (!ctx) return 0; + iter = ctx->begin; + while (iter) { + /* check if window is being hovered */ + if (iter->flags & NK_WINDOW_MINIMIZED) { + struct nk_rect header = iter->bounds; + header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y; + if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) + return 1; + } else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) { + return 1; + } + /* check if window popup is being hovered */ + if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds)) + return 1; + iter = iter->next; + } + return 0; +} + +NK_API int +nk_item_is_any_active(struct nk_context *ctx) +{ + int any_hovered = nk_window_is_any_hovered(ctx); + int any_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED); + return any_hovered || any_active; +} + +NK_API int +nk_window_is_collapsed(struct nk_context *ctx, const char *name) +{ + int title_len; + nk_hash title_hash; + struct nk_window *win; + NK_ASSERT(ctx); + if (!ctx) return 0; + + title_len = (int)nk_strlen(name); + title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); + win = nk_find_window(ctx, title_hash, name); + if (!win) return 0; + return win->flags & NK_WINDOW_MINIMIZED; +} + +NK_API int +nk_window_is_closed(struct nk_context *ctx, const char *name) +{ + int title_len; + nk_hash title_hash; + struct nk_window *win; + NK_ASSERT(ctx); + if (!ctx) return 1; + + title_len = (int)nk_strlen(name); + title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); + win = nk_find_window(ctx, title_hash, name); + if (!win) return 1; + return (win->flags & NK_WINDOW_CLOSED); +} + +NK_API int +nk_window_is_hidden(struct nk_context *ctx, const char *name) +{ + int title_len; + nk_hash title_hash; + struct nk_window *win; + NK_ASSERT(ctx); + if (!ctx) return 1; + + title_len = (int)nk_strlen(name); + title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); + win = nk_find_window(ctx, title_hash, name); + if (!win) return 1; + return (win->flags & NK_WINDOW_HIDDEN); +} + +NK_API int +nk_window_is_active(struct nk_context *ctx, const char *name) +{ + int title_len; + nk_hash title_hash; + struct nk_window *win; + NK_ASSERT(ctx); + if (!ctx) return 0; + + title_len = (int)nk_strlen(name); + title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); + win = nk_find_window(ctx, title_hash, name); + if (!win) return 0; + return win == ctx->active; +} + +NK_API struct nk_window* +nk_window_find(struct nk_context *ctx, const char *name) +{ + int title_len; + nk_hash title_hash; + title_len = (int)nk_strlen(name); + title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); + return nk_find_window(ctx, title_hash, name); +} + +NK_API void +nk_window_close(struct nk_context *ctx, const char *name) +{ + struct nk_window *win; + NK_ASSERT(ctx); + if (!ctx) return; + win = nk_window_find(ctx, name); + if (!win) return; + NK_ASSERT(ctx->current != win && "You cannot close a currently active window"); + if (ctx->current == win) return; + win->flags |= NK_WINDOW_HIDDEN; + win->flags |= NK_WINDOW_CLOSED; +} + +NK_API void +nk_window_set_bounds(struct nk_context *ctx, struct nk_rect bounds) +{ + NK_ASSERT(ctx); NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + ctx->current->bounds = bounds; +} + +NK_API void +nk_window_set_position(struct nk_context *ctx, struct nk_vec2 pos) +{ + NK_ASSERT(ctx); NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + ctx->current->bounds.x = pos.x; + ctx->current->bounds.y = pos.y; +} + +NK_API void +nk_window_set_size(struct nk_context *ctx, struct nk_vec2 size) +{ + NK_ASSERT(ctx); NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + ctx->current->bounds.w = size.x; + ctx->current->bounds.h = size.y; +} + +NK_API void +nk_window_collapse(struct nk_context *ctx, const char *name, + enum nk_collapse_states c) +{ + int title_len; + nk_hash title_hash; + struct nk_window *win; + NK_ASSERT(ctx); + if (!ctx) return; + + title_len = (int)nk_strlen(name); + title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); + win = nk_find_window(ctx, title_hash, name); + if (!win) return; + if (c == NK_MINIMIZED) + win->flags |= NK_WINDOW_MINIMIZED; + else win->flags &= ~(nk_flags)NK_WINDOW_MINIMIZED; +} + +NK_API void +nk_window_collapse_if(struct nk_context *ctx, const char *name, + enum nk_collapse_states c, int cond) +{ + NK_ASSERT(ctx); + if (!ctx || !cond) return; + nk_window_collapse(ctx, name, c); +} + +NK_API void +nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states s) +{ + int title_len; + nk_hash title_hash; + struct nk_window *win; + NK_ASSERT(ctx); + if (!ctx) return; + + title_len = (int)nk_strlen(name); + title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); + win = nk_find_window(ctx, title_hash, name); + if (!win) return; + if (s == NK_HIDDEN) { + win->flags |= NK_WINDOW_HIDDEN; + } else win->flags &= ~(nk_flags)NK_WINDOW_HIDDEN; +} + +NK_API void +nk_window_show_if(struct nk_context *ctx, const char *name, + enum nk_show_states s, int cond) +{ + NK_ASSERT(ctx); + if (!ctx || !cond) return; + nk_window_show(ctx, name, s); +} + +NK_API void +nk_window_set_focus(struct nk_context *ctx, const char *name) +{ + int title_len; + nk_hash title_hash; + struct nk_window *win; + NK_ASSERT(ctx); + if (!ctx) return; + + title_len = (int)nk_strlen(name); + title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); + win = nk_find_window(ctx, title_hash, name); + if (win && ctx->end != win) { + nk_remove_window(ctx, win); + nk_insert_window(ctx, win, NK_INSERT_BACK); + } + ctx->active = win; +} + +/*---------------------------------------------------------------- + * + * MENUBAR + * + * --------------------------------------------------------------*/ +NK_API void +nk_menubar_begin(struct nk_context *ctx) +{ + struct nk_panel *layout; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + layout = ctx->current->layout; + NK_ASSERT(layout->at_y == layout->bounds.y); + /* if this assert triggers you allocated space between nk_begin and nk_menubar_begin. + If you want a menubar the first nuklear function after `nk_begin` has to be a + `nk_menubar_begin` call. Inside the menubar you then have to allocate space for + widgets (also supports multiple rows). + Example: + if (nk_begin(...)) { + nk_menubar_begin(...); + nk_layout_xxxx(...); + nk_button(...); + nk_layout_xxxx(...); + nk_button(...); + nk_menubar_end(...); + } + nk_end(...); + */ + if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED) + return; + + layout->menu.x = layout->at_x; + layout->menu.y = layout->at_y + layout->row.height; + layout->menu.w = layout->bounds.w; + layout->menu.offset.x = *layout->offset_x; + layout->menu.offset.y = *layout->offset_y; + *layout->offset_y = 0; +} + +NK_API void +nk_menubar_end(struct nk_context *ctx) +{ + struct nk_window *win; + struct nk_panel *layout; + struct nk_command_buffer *out; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + out = &win->buffer; + layout = win->layout; + if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED) + return; + + layout->menu.h = layout->at_y - layout->menu.y; + layout->bounds.y += layout->menu.h + ctx->style.window.spacing.y + layout->row.height; + layout->bounds.h -= layout->menu.h + ctx->style.window.spacing.y + layout->row.height; + + *layout->offset_x = layout->menu.offset.x; + *layout->offset_y = layout->menu.offset.y; + layout->at_y = layout->bounds.y - layout->row.height; + + layout->clip.y = layout->bounds.y; + layout->clip.h = layout->bounds.h; + nk_push_scissor(out, layout->clip); +} +/* ------------------------------------------------------------- + * + * LAYOUT + * + * --------------------------------------------------------------*/ +NK_API void +nk_layout_set_min_row_height(struct nk_context *ctx, float height) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + layout->row.min_height = height; +} + +NK_API void +nk_layout_reset_min_row_height(struct nk_context *ctx) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + layout->row.min_height = ctx->style.font->height; + layout->row.min_height += ctx->style.text.padding.y*2; + layout->row.min_height += ctx->style.window.min_row_height_padding*2; +} + +NK_INTERN float +nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type, + float total_space, int columns) +{ + float panel_padding; + float panel_spacing; + float panel_space; + + struct nk_vec2 spacing; + struct nk_vec2 padding; + + spacing = style->window.spacing; + padding = nk_panel_get_padding(style, type); + + /* calculate the usable panel space */ + panel_padding = 2 * padding.x; + panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x; + panel_space = total_space - panel_padding - panel_spacing; + return panel_space; +} + +NK_INTERN void +nk_panel_layout(const struct nk_context *ctx, struct nk_window *win, + float height, int cols) +{ + struct nk_panel *layout; + const struct nk_style *style; + struct nk_command_buffer *out; + + struct nk_vec2 item_spacing; + struct nk_color color; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + /* prefetch some configuration data */ + layout = win->layout; + style = &ctx->style; + out = &win->buffer; + color = style->window.background; + item_spacing = style->window.spacing; + + /* if one of these triggers you forgot to add an `if` condition around either + a window, group, popup, combobox or contextual menu `begin` and `end` block. + Example: + if (nk_begin(...) {...} nk_end(...); or + if (nk_group_begin(...) { nk_group_end(...);} */ + NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED)); + NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN)); + NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED)); + + /* update the current row and set the current row layout */ + layout->row.index = 0; + layout->at_y += layout->row.height; + layout->row.columns = cols; + if (height == 0.0f) + layout->row.height = NK_MAX(height, layout->row.min_height) + item_spacing.y; + else layout->row.height = height + item_spacing.y; + + layout->row.item_offset = 0; + if (layout->flags & NK_WINDOW_DYNAMIC) { + /* draw background for dynamic panels */ + struct nk_rect background; + background.x = win->bounds.x; + background.w = win->bounds.w; + background.y = layout->at_y - 1.0f; + background.h = layout->row.height + 1.0f; + nk_fill_rect(out, background, 0, color); + } +} + +NK_INTERN void +nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt, + float height, int cols, int width) +{ + /* update the current row and set the current row layout */ + struct nk_window *win; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + nk_panel_layout(ctx, win, height, cols); + if (fmt == NK_DYNAMIC) + win->layout->row.type = NK_LAYOUT_DYNAMIC_FIXED; + else win->layout->row.type = NK_LAYOUT_STATIC_FIXED; + + win->layout->row.ratio = 0; + win->layout->row.filled = 0; + win->layout->row.item_offset = 0; + win->layout->row.item_width = (float)width; +} + +NK_API float +nk_layout_ratio_from_pixel(struct nk_context *ctx, float pixel_width) +{ + struct nk_window *win; + NK_ASSERT(ctx); + NK_ASSERT(pixel_width); + if (!ctx || !ctx->current || !ctx->current->layout) return 0; + win = ctx->current; + return NK_CLAMP(0.0f, pixel_width/win->bounds.x, 1.0f); +} + +NK_API void +nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols) +{ + nk_row_layout(ctx, NK_DYNAMIC, height, cols, 0); +} + +NK_API void +nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols) +{ + nk_row_layout(ctx, NK_STATIC, height, cols, item_width); +} + +NK_API void +nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, + float row_height, int cols) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + nk_panel_layout(ctx, win, row_height, cols); + if (fmt == NK_DYNAMIC) + layout->row.type = NK_LAYOUT_DYNAMIC_ROW; + else layout->row.type = NK_LAYOUT_STATIC_ROW; + + layout->row.ratio = 0; + layout->row.filled = 0; + layout->row.item_width = 0; + layout->row.item_offset = 0; + layout->row.columns = cols; +} + +NK_API void +nk_layout_row_push(struct nk_context *ctx, float ratio_or_width) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW); + if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW) + return; + + if (layout->row.type == NK_LAYOUT_DYNAMIC_ROW) { + float ratio = ratio_or_width; + if ((ratio + layout->row.filled) > 1.0f) return; + if (ratio > 0.0f) + layout->row.item_width = NK_SATURATE(ratio); + else layout->row.item_width = 1.0f - layout->row.filled; + } else layout->row.item_width = ratio_or_width; +} + +NK_API void +nk_layout_row_end(struct nk_context *ctx) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW); + if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW) + return; + layout->row.item_width = 0; + layout->row.item_offset = 0; +} + +NK_API void +nk_layout_row(struct nk_context *ctx, enum nk_layout_format fmt, + float height, int cols, const float *ratio) +{ + int i; + int n_undef = 0; + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + nk_panel_layout(ctx, win, height, cols); + if (fmt == NK_DYNAMIC) { + /* calculate width of undefined widget ratios */ + float r = 0; + layout->row.ratio = ratio; + for (i = 0; i < cols; ++i) { + if (ratio[i] < 0.0f) + n_undef++; + else r += ratio[i]; + } + r = NK_SATURATE(1.0f - r); + layout->row.type = NK_LAYOUT_DYNAMIC; + layout->row.item_width = (r > 0 && n_undef > 0) ? (r / (float)n_undef):0; + } else { + layout->row.ratio = ratio; + layout->row.type = NK_LAYOUT_STATIC; + layout->row.item_width = 0; + layout->row.item_offset = 0; + } + layout->row.item_offset = 0; + layout->row.filled = 0; +} + +NK_API void +nk_layout_row_template_begin(struct nk_context *ctx, float height) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + nk_panel_layout(ctx, win, height, 1); + layout->row.type = NK_LAYOUT_TEMPLATE; + layout->row.columns = 0; + layout->row.ratio = 0; + layout->row.item_width = 0; + layout->row.item_height = 0; + layout->row.item_offset = 0; + layout->row.filled = 0; + layout->row.item.x = 0; + layout->row.item.y = 0; + layout->row.item.w = 0; + layout->row.item.h = 0; +} + +NK_API void +nk_layout_row_template_push_dynamic(struct nk_context *ctx) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); + NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); + if (layout->row.type != NK_LAYOUT_TEMPLATE) return; + if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; + layout->row.templates[layout->row.columns++] = -1.0f; +} + +NK_API void +nk_layout_row_template_push_variable(struct nk_context *ctx, float min_width) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); + NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); + if (layout->row.type != NK_LAYOUT_TEMPLATE) return; + if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; + layout->row.templates[layout->row.columns++] = -min_width; +} + +NK_API void +nk_layout_row_template_push_static(struct nk_context *ctx, float width) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); + NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); + if (layout->row.type != NK_LAYOUT_TEMPLATE) return; + if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; + layout->row.templates[layout->row.columns++] = width; +} + +NK_API void +nk_layout_row_template_end(struct nk_context *ctx) +{ + struct nk_window *win; + struct nk_panel *layout; + + int i = 0; + int variable_count = 0; + int min_variable_count = 0; + float min_fixed_width = 0.0f; + float total_fixed_width = 0.0f; + float max_variable_width = 0.0f; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); + if (layout->row.type != NK_LAYOUT_TEMPLATE) return; + for (i = 0; i < layout->row.columns; ++i) { + float width = layout->row.templates[i]; + if (width >= 0.0f) { + total_fixed_width += width; + min_fixed_width += width; + } else if (width < -1.0f) { + width = -width; + total_fixed_width += width; + max_variable_width = NK_MAX(max_variable_width, width); + variable_count++; + } else { + min_variable_count++; + variable_count++; + } + } + if (variable_count) { + float space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type, + layout->bounds.w, layout->row.columns); + float var_width = (NK_MAX(space-min_fixed_width,0.0f)) / (float)variable_count; + int enough_space = var_width >= max_variable_width; + if (!enough_space) + var_width = (NK_MAX(space-total_fixed_width,0)) / (float)min_variable_count; + for (i = 0; i < layout->row.columns; ++i) { + float *width = &layout->row.templates[i]; + *width = (*width >= 0.0f)? *width: (*width < -1.0f && !enough_space)? -(*width): var_width; + } + } +} + +NK_API void +nk_layout_space_begin(struct nk_context *ctx, enum nk_layout_format fmt, + float height, int widget_count) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + nk_panel_layout(ctx, win, height, widget_count); + if (fmt == NK_STATIC) + layout->row.type = NK_LAYOUT_STATIC_FREE; + else layout->row.type = NK_LAYOUT_DYNAMIC_FREE; + + layout->row.ratio = 0; + layout->row.filled = 0; + layout->row.item_width = 0; + layout->row.item_offset = 0; +} + +NK_API void +nk_layout_space_end(struct nk_context *ctx) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + layout->row.item_width = 0; + layout->row.item_height = 0; + layout->row.item_offset = 0; + nk_zero(&layout->row.item, sizeof(layout->row.item)); +} + +NK_API void +nk_layout_space_push(struct nk_context *ctx, struct nk_rect rect) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + layout->row.item = rect; +} + +NK_API struct nk_rect +nk_layout_space_bounds(struct nk_context *ctx) +{ + struct nk_rect ret; + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + win = ctx->current; + layout = win->layout; + + ret.x = layout->clip.x; + ret.y = layout->clip.y; + ret.w = layout->clip.w; + ret.h = layout->row.height; + return ret; +} + +NK_API struct nk_rect +nk_layout_widget_bounds(struct nk_context *ctx) +{ + struct nk_rect ret; + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + win = ctx->current; + layout = win->layout; + + ret.x = layout->at_x; + ret.y = layout->at_y; + ret.w = layout->bounds.w - NK_MAX(layout->at_x - layout->bounds.x,0); + ret.h = layout->row.height; + return ret; +} + +NK_API struct nk_vec2 +nk_layout_space_to_screen(struct nk_context *ctx, struct nk_vec2 ret) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + win = ctx->current; + layout = win->layout; + + ret.x += layout->at_x - (float)*layout->offset_x; + ret.y += layout->at_y - (float)*layout->offset_y; + return ret; +} + +NK_API struct nk_vec2 +nk_layout_space_to_local(struct nk_context *ctx, struct nk_vec2 ret) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + win = ctx->current; + layout = win->layout; + + ret.x += -layout->at_x + (float)*layout->offset_x; + ret.y += -layout->at_y + (float)*layout->offset_y; + return ret; +} + +NK_API struct nk_rect +nk_layout_space_rect_to_screen(struct nk_context *ctx, struct nk_rect ret) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + win = ctx->current; + layout = win->layout; + + ret.x += layout->at_x - (float)*layout->offset_x; + ret.y += layout->at_y - (float)*layout->offset_y; + return ret; +} + +NK_API struct nk_rect +nk_layout_space_rect_to_local(struct nk_context *ctx, struct nk_rect ret) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + win = ctx->current; + layout = win->layout; + + ret.x += -layout->at_x + (float)*layout->offset_x; + ret.y += -layout->at_y + (float)*layout->offset_y; + return ret; +} + +NK_INTERN void +nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win) +{ + struct nk_panel *layout = win->layout; + struct nk_vec2 spacing = ctx->style.window.spacing; + const float row_height = layout->row.height - spacing.y; + nk_panel_layout(ctx, win, row_height, layout->row.columns); +} + +NK_INTERN void +nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, + struct nk_window *win, int modify) +{ + struct nk_panel *layout; + const struct nk_style *style; + + struct nk_vec2 spacing; + struct nk_vec2 padding; + + float item_offset = 0; + float item_width = 0; + float item_spacing = 0; + float panel_space = 0; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + style = &ctx->style; + NK_ASSERT(bounds); + + spacing = style->window.spacing; + padding = nk_panel_get_padding(style, layout->type); + panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type, + layout->bounds.w, layout->row.columns); + + /* calculate the width of one item inside the current layout space */ + switch (layout->row.type) { + case NK_LAYOUT_DYNAMIC_FIXED: { + /* scaling fixed size widgets item width */ + item_width = NK_MAX(1.0f,panel_space-1.0f) / (float)layout->row.columns; + item_offset = (float)layout->row.index * item_width; + item_spacing = (float)layout->row.index * spacing.x; + } break; + case NK_LAYOUT_DYNAMIC_ROW: { + /* scaling single ratio widget width */ + item_width = layout->row.item_width * panel_space; + item_offset = layout->row.item_offset; + item_spacing = 0; + + if (modify) { + layout->row.item_offset += item_width + spacing.x; + layout->row.filled += layout->row.item_width; + layout->row.index = 0; + } + } break; + case NK_LAYOUT_DYNAMIC_FREE: { + /* panel width depended free widget placing */ + bounds->x = layout->at_x + (layout->bounds.w * layout->row.item.x); + bounds->x -= (float)*layout->offset_x; + bounds->y = layout->at_y + (layout->row.height * layout->row.item.y); + bounds->y -= (float)*layout->offset_y; + bounds->w = layout->bounds.w * layout->row.item.w; + bounds->h = layout->row.height * layout->row.item.h; + return; + } break; + case NK_LAYOUT_DYNAMIC: { + /* scaling arrays of panel width ratios for every widget */ + float ratio; + NK_ASSERT(layout->row.ratio); + ratio = (layout->row.ratio[layout->row.index] < 0) ? + layout->row.item_width : layout->row.ratio[layout->row.index]; + + item_spacing = (float)layout->row.index * spacing.x; + item_width = (ratio * panel_space); + item_offset = layout->row.item_offset; + + if (modify) { + layout->row.item_offset += item_width; + layout->row.filled += ratio; + } + } break; + case NK_LAYOUT_STATIC_FIXED: { + /* non-scaling fixed widgets item width */ + item_width = layout->row.item_width; + item_offset = (float)layout->row.index * item_width; + item_spacing = (float)layout->row.index * spacing.x; + } break; + case NK_LAYOUT_STATIC_ROW: { + /* scaling single ratio widget width */ + item_width = layout->row.item_width; + item_offset = layout->row.item_offset; + item_spacing = (float)layout->row.index * spacing.x; + if (modify) layout->row.item_offset += item_width; + } break; + case NK_LAYOUT_STATIC_FREE: { + /* free widget placing */ + bounds->x = layout->at_x + layout->row.item.x; + bounds->w = layout->row.item.w; + if (((bounds->x + bounds->w) > layout->max_x) && modify) + layout->max_x = (bounds->x + bounds->w); + bounds->x -= (float)*layout->offset_x; + bounds->y = layout->at_y + layout->row.item.y; + bounds->y -= (float)*layout->offset_y; + bounds->h = layout->row.item.h; + return; + } break; + case NK_LAYOUT_STATIC: { + /* non-scaling array of panel pixel width for every widget */ + item_spacing = (float)layout->row.index * spacing.x; + item_width = layout->row.ratio[layout->row.index]; + item_offset = layout->row.item_offset; + if (modify) layout->row.item_offset += item_width; + } break; + case NK_LAYOUT_TEMPLATE: { + /* stretchy row layout with combined dynamic/static widget width*/ + NK_ASSERT(layout->row.index < layout->row.columns); + NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); + item_width = layout->row.templates[layout->row.index]; + item_offset = layout->row.item_offset; + item_spacing = (float)layout->row.index * spacing.x; + if (modify) layout->row.item_offset += item_width; + } break; + default: NK_ASSERT(0); break; + }; + + /* set the bounds of the newly allocated widget */ + bounds->w = item_width; + bounds->h = layout->row.height - spacing.y; + bounds->y = layout->at_y - (float)*layout->offset_y; + bounds->x = layout->at_x + item_offset + item_spacing + padding.x; + if (((bounds->x + bounds->w) > layout->max_x) && modify) + layout->max_x = bounds->x + bounds->w; + bounds->x -= (float)*layout->offset_x; +} + +NK_INTERN void +nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx) +{ + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + /* check if the end of the row has been hit and begin new row if so */ + win = ctx->current; + layout = win->layout; + if (layout->row.index >= layout->row.columns) + nk_panel_alloc_row(ctx, win); + + /* calculate widget position and size */ + nk_layout_widget_space(bounds, ctx, win, nk_true); + layout->row.index++; +} + +NK_INTERN void +nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx) +{ + float y; + int index; + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + y = layout->at_y; + index = layout->row.index; + if (layout->row.index >= layout->row.columns) { + layout->at_y += layout->row.height; + layout->row.index = 0; + } + nk_layout_widget_space(bounds, ctx, win, nk_false); + layout->at_y = y; + layout->row.index = index; +} + +NK_INTERN int +nk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type, + struct nk_image *img, const char *title, enum nk_collapse_states *state) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_style *style; + struct nk_command_buffer *out; + const struct nk_input *in; + const struct nk_style_button *button; + enum nk_symbol_type symbol; + float row_height; + + struct nk_vec2 item_spacing; + struct nk_rect header = {0,0,0,0}; + struct nk_rect sym = {0,0,0,0}; + struct nk_text text; + + nk_flags ws = 0; + enum nk_widget_layout_states widget_state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + /* cache some data */ + win = ctx->current; + layout = win->layout; + out = &win->buffer; + style = &ctx->style; + item_spacing = style->window.spacing; + + /* calculate header bounds and draw background */ + row_height = style->font->height + 2 * style->tab.padding.y; + nk_layout_set_min_row_height(ctx, row_height); + nk_layout_row_dynamic(ctx, row_height, 1); + nk_layout_reset_min_row_height(ctx); + + widget_state = nk_widget(&header, ctx); + if (type == NK_TREE_TAB) { + const struct nk_style_item *background = &style->tab.background; + if (background->type == NK_STYLE_ITEM_IMAGE) { + nk_draw_image(out, header, &background->data.image, nk_white); + text.background = nk_rgba(0,0,0,0); + } else { + text.background = background->data.color; + nk_fill_rect(out, header, 0, style->tab.border_color); + nk_fill_rect(out, nk_shrink_rect(header, style->tab.border), + style->tab.rounding, background->data.color); + } + } else text.background = style->window.background; + + /* update node state */ + in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0; + in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0; + if (nk_button_behavior(&ws, header, in, NK_BUTTON_DEFAULT)) + *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED; + + /* select correct button style */ + if (*state == NK_MAXIMIZED) { + symbol = style->tab.sym_maximize; + if (type == NK_TREE_TAB) + button = &style->tab.tab_maximize_button; + else button = &style->tab.node_maximize_button; + } else { + symbol = style->tab.sym_minimize; + if (type == NK_TREE_TAB) + button = &style->tab.tab_minimize_button; + else button = &style->tab.node_minimize_button; + } + + {/* draw triangle button */ + sym.w = sym.h = style->font->height; + sym.y = header.y + style->tab.padding.y; + sym.x = header.x + style->tab.padding.x; + nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT, + button, 0, style->font); + + if (img) { + /* draw optional image icon */ + sym.x = sym.x + sym.w + 4 * item_spacing.x; + nk_draw_image(&win->buffer, sym, img, nk_white); + sym.w = style->font->height + style->tab.spacing.x;} + } + + {/* draw label */ + struct nk_rect label; + header.w = NK_MAX(header.w, sym.w + item_spacing.x); + label.x = sym.x + sym.w + item_spacing.x; + label.y = sym.y; + label.w = header.w - (sym.w + item_spacing.y + style->tab.indent); + label.h = style->font->height; + text.text = style->tab.text; + text.padding = nk_vec2(0,0); + nk_widget_text(out, label, title, nk_strlen(title), &text, + NK_TEXT_LEFT, style->font);} + + /* increase x-axis cursor widget position pointer */ + if (*state == NK_MAXIMIZED) { + layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent; + layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent); + layout->bounds.w -= (style->tab.indent + style->window.padding.x); + layout->row.tree_depth++; + return nk_true; + } else return nk_false; +} + +NK_INTERN int +nk_tree_base(struct nk_context *ctx, enum nk_tree_type type, + struct nk_image *img, const char *title, enum nk_collapse_states initial_state, + const char *hash, int len, int line) +{ + struct nk_window *win = ctx->current; + int title_len = 0; + nk_hash tree_hash = 0; + nk_uint *state = 0; + + /* retrieve tree state from internal widget state tables */ + if (!hash) { + title_len = (int)nk_strlen(title); + tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line); + } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line); + state = nk_find_value(win, tree_hash); + if (!state) { + state = nk_add_value(ctx, win, tree_hash, 0); + *state = initial_state; + } + return nk_tree_state_base(ctx, type, img, title, (enum nk_collapse_states*)state); +} + +NK_API int +nk_tree_state_push(struct nk_context *ctx, enum nk_tree_type type, + const char *title, enum nk_collapse_states *state) +{return nk_tree_state_base(ctx, type, 0, title, state);} + +NK_API int +nk_tree_state_image_push(struct nk_context *ctx, enum nk_tree_type type, + struct nk_image img, const char *title, enum nk_collapse_states *state) +{return nk_tree_state_base(ctx, type, &img, title, state);} + +NK_API void +nk_tree_state_pop(struct nk_context *ctx) +{ + struct nk_window *win = 0; + struct nk_panel *layout = 0; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + layout->at_x -= ctx->style.tab.indent + ctx->style.window.padding.x; + layout->bounds.w += ctx->style.tab.indent + ctx->style.window.padding.x; + NK_ASSERT(layout->row.tree_depth); + layout->row.tree_depth--; +} + +NK_API int +nk_tree_push_hashed(struct nk_context *ctx, enum nk_tree_type type, + const char *title, enum nk_collapse_states initial_state, + const char *hash, int len, int line) +{return nk_tree_base(ctx, type, 0, title, initial_state, hash, len, line);} + +NK_API int +nk_tree_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type, + struct nk_image img, const char *title, enum nk_collapse_states initial_state, + const char *hash, int len,int seed) +{return nk_tree_base(ctx, type, &img, title, initial_state, hash, len, seed);} + +NK_API void +nk_tree_pop(struct nk_context *ctx) +{nk_tree_state_pop(ctx);} + +/*---------------------------------------------------------------- + * + * WIDGETS + * + * --------------------------------------------------------------*/ +NK_API struct nk_rect +nk_widget_bounds(struct nk_context *ctx) +{ + struct nk_rect bounds; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return nk_rect(0,0,0,0); + nk_layout_peek(&bounds, ctx); + return bounds; +} + +NK_API struct nk_vec2 +nk_widget_position(struct nk_context *ctx) +{ + struct nk_rect bounds; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return nk_vec2(0,0); + + nk_layout_peek(&bounds, ctx); + return nk_vec2(bounds.x, bounds.y); +} + +NK_API struct nk_vec2 +nk_widget_size(struct nk_context *ctx) +{ + struct nk_rect bounds; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return nk_vec2(0,0); + + nk_layout_peek(&bounds, ctx); + return nk_vec2(bounds.w, bounds.h); +} + +NK_API float +nk_widget_width(struct nk_context *ctx) +{ + struct nk_rect bounds; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return 0; + + nk_layout_peek(&bounds, ctx); + return bounds.w; +} + +NK_API float +nk_widget_height(struct nk_context *ctx) +{ + struct nk_rect bounds; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return 0; + + nk_layout_peek(&bounds, ctx); + return bounds.h; +} + +NK_API int +nk_widget_is_hovered(struct nk_context *ctx) +{ + struct nk_rect c, v; + struct nk_rect bounds; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current || ctx->active != ctx->current) + return 0; + + c = ctx->current->layout->clip; + c.x = (float)((int)c.x); + c.y = (float)((int)c.y); + c.w = (float)((int)c.w); + c.h = (float)((int)c.h); + + nk_layout_peek(&bounds, ctx); + nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); + if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) + return 0; + return nk_input_is_mouse_hovering_rect(&ctx->input, bounds); +} + +NK_API int +nk_widget_is_mouse_clicked(struct nk_context *ctx, enum nk_buttons btn) +{ + struct nk_rect c, v; + struct nk_rect bounds; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current || ctx->active != ctx->current) + return 0; + + c = ctx->current->layout->clip; + c.x = (float)((int)c.x); + c.y = (float)((int)c.y); + c.w = (float)((int)c.w); + c.h = (float)((int)c.h); + + nk_layout_peek(&bounds, ctx); + nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); + if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) + return 0; + return nk_input_mouse_clicked(&ctx->input, btn, bounds); +} + +NK_API int +nk_widget_has_mouse_click_down(struct nk_context *ctx, enum nk_buttons btn, int down) +{ + struct nk_rect c, v; + struct nk_rect bounds; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current || ctx->active != ctx->current) + return 0; + + c = ctx->current->layout->clip; + c.x = (float)((int)c.x); + c.y = (float)((int)c.y); + c.w = (float)((int)c.w); + c.h = (float)((int)c.h); + + nk_layout_peek(&bounds, ctx); + nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); + if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) + return 0; + return nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down); +} + +NK_API enum nk_widget_layout_states +nk_widget(struct nk_rect *bounds, const struct nk_context *ctx) +{ + struct nk_rect c, v; + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return NK_WIDGET_INVALID; + + /* allocate space and check if the widget needs to be updated and drawn */ + nk_panel_alloc_space(bounds, ctx); + win = ctx->current; + layout = win->layout; + in = &ctx->input; + c = layout->clip; + + /* if one of these triggers you forgot to add an `if` condition around either + a window, group, popup, combobox or contextual menu `begin` and `end` block. + Example: + if (nk_begin(...) {...} nk_end(...); or + if (nk_group_begin(...) { nk_group_end(...);} */ + NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED)); + NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN)); + NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED)); + + /* need to convert to int here to remove floating point errors */ + bounds->x = (float)((int)bounds->x); + bounds->y = (float)((int)bounds->y); + bounds->w = (float)((int)bounds->w); + bounds->h = (float)((int)bounds->h); + + c.x = (float)((int)c.x); + c.y = (float)((int)c.y); + c.w = (float)((int)c.w); + c.h = (float)((int)c.h); + + nk_unify(&v, &c, bounds->x, bounds->y, bounds->x + bounds->w, bounds->y + bounds->h); + if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h)) + return NK_WIDGET_INVALID; + if (!NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, v.x, v.y, v.w, v.h)) + return NK_WIDGET_ROM; + return NK_WIDGET_VALID; +} + +NK_API enum nk_widget_layout_states +nk_widget_fitting(struct nk_rect *bounds, struct nk_context *ctx, + struct nk_vec2 item_padding) +{ + /* update the bounds to stand without padding */ + struct nk_window *win; + struct nk_style *style; + struct nk_panel *layout; + enum nk_widget_layout_states state; + struct nk_vec2 panel_padding; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return NK_WIDGET_INVALID; + + win = ctx->current; + style = &ctx->style; + layout = win->layout; + state = nk_widget(bounds, ctx); + + panel_padding = nk_panel_get_padding(style, layout->type); + if (layout->row.index == 1) { + bounds->w += panel_padding.x; + bounds->x -= panel_padding.x; + } else bounds->x -= item_padding.x; + + if (layout->row.index == layout->row.columns) + bounds->w += panel_padding.x; + else bounds->w += item_padding.x; + return state; +} + +/*---------------------------------------------------------------- + * + * MISC + * + * --------------------------------------------------------------*/ +NK_API void +nk_spacing(struct nk_context *ctx, int cols) +{ + struct nk_window *win; + struct nk_panel *layout; + struct nk_rect none; + int i, index, rows; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + /* spacing over row boundaries */ + win = ctx->current; + layout = win->layout; + index = (layout->row.index + cols) % layout->row.columns; + rows = (layout->row.index + cols) / layout->row.columns; + if (rows) { + for (i = 0; i < rows; ++i) + nk_panel_alloc_row(ctx, win); + cols = index; + } + /* non table layout need to allocate space */ + if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED && + layout->row.type != NK_LAYOUT_STATIC_FIXED) { + for (i = 0; i < cols; ++i) + nk_panel_alloc_space(&none, ctx); + } + layout->row.index = index; +} + +/*---------------------------------------------------------------- + * + * TEXT + * + * --------------------------------------------------------------*/ +NK_API void +nk_text_colored(struct nk_context *ctx, const char *str, int len, + nk_flags alignment, struct nk_color color) +{ + struct nk_window *win; + const struct nk_style *style; + + struct nk_vec2 item_padding; + struct nk_rect bounds; + struct nk_text text; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) return; + + win = ctx->current; + style = &ctx->style; + nk_panel_alloc_space(&bounds, ctx); + item_padding = style->text.padding; + + text.padding.x = item_padding.x; + text.padding.y = item_padding.y; + text.background = style->window.background; + text.text = color; + nk_widget_text(&win->buffer, bounds, str, len, &text, alignment, style->font); +} + +NK_API void +nk_text_wrap_colored(struct nk_context *ctx, const char *str, + int len, struct nk_color color) +{ + struct nk_window *win; + const struct nk_style *style; + + struct nk_vec2 item_padding; + struct nk_rect bounds; + struct nk_text text; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) return; + + win = ctx->current; + style = &ctx->style; + nk_panel_alloc_space(&bounds, ctx); + item_padding = style->text.padding; + + text.padding.x = item_padding.x; + text.padding.y = item_padding.y; + text.background = style->window.background; + text.text = color; + nk_widget_text_wrap(&win->buffer, bounds, str, len, &text, style->font); +} + +#ifdef NK_INCLUDE_STANDARD_VARARGS +NK_API void +nk_labelf_colored(struct nk_context *ctx, nk_flags flags, + struct nk_color color, const char *fmt, ...) +{ + char buf[256]; + va_list args; + va_start(args, fmt); + nk_strfmt(buf, NK_LEN(buf), fmt, args); + nk_label_colored(ctx, buf, flags, color); + va_end(args); +} + +NK_API void +nk_labelf_colored_wrap(struct nk_context *ctx, struct nk_color color, + const char *fmt, ...) +{ + char buf[256]; + va_list args; + va_start(args, fmt); + nk_strfmt(buf, NK_LEN(buf), fmt, args); + nk_label_colored_wrap(ctx, buf, color); + va_end(args); +} + +NK_API void +nk_labelf(struct nk_context *ctx, nk_flags flags, const char *fmt, ...) +{ + char buf[256]; + va_list args; + va_start(args, fmt); + nk_strfmt(buf, NK_LEN(buf), fmt, args); + nk_label(ctx, buf, flags); + va_end(args); +} + +NK_API void +nk_labelf_wrap(struct nk_context *ctx, const char *fmt,...) +{ + char buf[256]; + va_list args; + va_start(args, fmt); + nk_strfmt(buf, NK_LEN(buf), fmt, args); + nk_label_wrap(ctx, buf); + va_end(args); +} + +NK_API void +nk_value_bool(struct nk_context *ctx, const char *prefix, int value) +{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, ((value) ? "true": "false"));} + +NK_API void +nk_value_int(struct nk_context *ctx, const char *prefix, int value) +{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %d", prefix, value);} + +NK_API void +nk_value_uint(struct nk_context *ctx, const char *prefix, unsigned int value) +{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %u", prefix, value);} + +NK_API void +nk_value_float(struct nk_context *ctx, const char *prefix, float value) +{ + double double_value = (double)value; + nk_labelf(ctx, NK_TEXT_LEFT, "%s: %.3f", prefix, double_value); +} + +NK_API void +nk_value_color_byte(struct nk_context *ctx, const char *p, struct nk_color c) +{nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%d, %d, %d, %d)", p, c.r, c.g, c.b, c.a);} + +NK_API void +nk_value_color_float(struct nk_context *ctx, const char *p, struct nk_color color) +{ + double c[4]; nk_color_dv(c, color); + nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%.2f, %.2f, %.2f, %.2f)", + p, c[0], c[1], c[2], c[3]); +} + +NK_API void +nk_value_color_hex(struct nk_context *ctx, const char *prefix, struct nk_color color) +{ + char hex[16]; + nk_color_hex_rgba(hex, color); + nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, hex); +} +#endif + +NK_API void +nk_text(struct nk_context *ctx, const char *str, int len, nk_flags alignment) +{ + NK_ASSERT(ctx); + if (!ctx) return; + nk_text_colored(ctx, str, len, alignment, ctx->style.text.color); +} + +NK_API void +nk_text_wrap(struct nk_context *ctx, const char *str, int len) +{ + NK_ASSERT(ctx); + if (!ctx) return; + nk_text_wrap_colored(ctx, str, len, ctx->style.text.color); +} + +NK_API void +nk_label(struct nk_context *ctx, const char *str, nk_flags alignment) +{nk_text(ctx, str, nk_strlen(str), alignment);} + +NK_API void +nk_label_colored(struct nk_context *ctx, const char *str, nk_flags align, + struct nk_color color) +{nk_text_colored(ctx, str, nk_strlen(str), align, color);} + +NK_API void +nk_label_wrap(struct nk_context *ctx, const char *str) +{nk_text_wrap(ctx, str, nk_strlen(str));} + +NK_API void +nk_label_colored_wrap(struct nk_context *ctx, const char *str, struct nk_color color) +{nk_text_wrap_colored(ctx, str, nk_strlen(str), color);} + +NK_API void +nk_image(struct nk_context *ctx, struct nk_image img) +{ + struct nk_window *win; + struct nk_rect bounds; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) return; + + win = ctx->current; + if (!nk_widget(&bounds, ctx)) return; + nk_draw_image(&win->buffer, bounds, &img, nk_white); +} + +/*---------------------------------------------------------------- + * + * BUTTON + * + * --------------------------------------------------------------*/ +NK_API void +nk_button_set_behavior(struct nk_context *ctx, enum nk_button_behavior behavior) +{ + NK_ASSERT(ctx); + if (!ctx) return; + ctx->button_behavior = behavior; +} + +NK_API int +nk_button_push_behavior(struct nk_context *ctx, enum nk_button_behavior behavior) +{ + struct nk_config_stack_button_behavior *button_stack; + struct nk_config_stack_button_behavior_element *element; + + NK_ASSERT(ctx); + if (!ctx) return 0; + + button_stack = &ctx->stacks.button_behaviors; + NK_ASSERT(button_stack->head < (int)NK_LEN(button_stack->elements)); + if (button_stack->head >= (int)NK_LEN(button_stack->elements)) + return 0; + + element = &button_stack->elements[button_stack->head++]; + element->address = &ctx->button_behavior; + element->old_value = ctx->button_behavior; + ctx->button_behavior = behavior; + return 1; +} + +NK_API int +nk_button_pop_behavior(struct nk_context *ctx) +{ + struct nk_config_stack_button_behavior *button_stack; + struct nk_config_stack_button_behavior_element *element; + + NK_ASSERT(ctx); + if (!ctx) return 0; + + button_stack = &ctx->stacks.button_behaviors; + NK_ASSERT(button_stack->head > 0); + if (button_stack->head < 1) + return 0; + + element = &button_stack->elements[--button_stack->head]; + *element->address = element->old_value; + return 1; +} + +NK_API int +nk_button_text_styled(struct nk_context *ctx, + const struct nk_style_button *style, const char *title, int len) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + + struct nk_rect bounds; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(style); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!style || !ctx || !ctx->current || !ctx->current->layout) return 0; + + win = ctx->current; + layout = win->layout; + state = nk_widget(&bounds, ctx); + + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + return nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds, + title, len, style->text_alignment, ctx->button_behavior, + style, in, ctx->style.font); +} + +NK_API int +nk_button_text(struct nk_context *ctx, const char *title, int len) +{ + NK_ASSERT(ctx); + if (!ctx) return 0; + return nk_button_text_styled(ctx, &ctx->style.button, title, len); +} + +NK_API int nk_button_label_styled(struct nk_context *ctx, + const struct nk_style_button *style, const char *title) +{return nk_button_text_styled(ctx, style, title, nk_strlen(title));} + +NK_API int nk_button_label(struct nk_context *ctx, const char *title) +{return nk_button_text(ctx, title, nk_strlen(title));} + +NK_API int +nk_button_color(struct nk_context *ctx, struct nk_color color) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + struct nk_style_button button; + + int ret = 0; + struct nk_rect bounds; + struct nk_rect content; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + layout = win->layout; + + state = nk_widget(&bounds, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + + button = ctx->style.button; + button.normal = nk_style_item_color(color); + button.hover = nk_style_item_color(color); + button.active = nk_style_item_color(color); + ret = nk_do_button(&ctx->last_widget_state, &win->buffer, bounds, + &button, in, ctx->button_behavior, &content); + nk_draw_button(&win->buffer, &bounds, ctx->last_widget_state, &button); + return ret; +} + +NK_API int +nk_button_symbol_styled(struct nk_context *ctx, + const struct nk_style_button *style, enum nk_symbol_type symbol) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + + struct nk_rect bounds; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + layout = win->layout; + state = nk_widget(&bounds, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + return nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, bounds, + symbol, ctx->button_behavior, style, in, ctx->style.font); +} + +NK_API int +nk_button_symbol(struct nk_context *ctx, enum nk_symbol_type symbol) +{ + NK_ASSERT(ctx); + if (!ctx) return 0; + return nk_button_symbol_styled(ctx, &ctx->style.button, symbol); +} + +NK_API int +nk_button_image_styled(struct nk_context *ctx, const struct nk_style_button *style, + struct nk_image img) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + + struct nk_rect bounds; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + layout = win->layout; + + state = nk_widget(&bounds, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + return nk_do_button_image(&ctx->last_widget_state, &win->buffer, bounds, + img, ctx->button_behavior, style, in); +} + +NK_API int +nk_button_image(struct nk_context *ctx, struct nk_image img) +{ + NK_ASSERT(ctx); + if (!ctx) return 0; + return nk_button_image_styled(ctx, &ctx->style.button, img); +} + +NK_API int +nk_button_symbol_text_styled(struct nk_context *ctx, + const struct nk_style_button *style, enum nk_symbol_type symbol, + const char *text, int len, nk_flags align) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + + struct nk_rect bounds; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + layout = win->layout; + + state = nk_widget(&bounds, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + return nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds, + symbol, text, len, align, ctx->button_behavior, + style, ctx->style.font, in); +} + +NK_API int +nk_button_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol, + const char* text, int len, nk_flags align) +{ + NK_ASSERT(ctx); + if (!ctx) return 0; + return nk_button_symbol_text_styled(ctx, &ctx->style.button, symbol, text, len, align); +} + +NK_API int nk_button_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol, + const char *label, nk_flags align) +{return nk_button_symbol_text(ctx, symbol, label, nk_strlen(label), align);} + +NK_API int nk_button_symbol_label_styled(struct nk_context *ctx, + const struct nk_style_button *style, enum nk_symbol_type symbol, + const char *title, nk_flags align) +{return nk_button_symbol_text_styled(ctx, style, symbol, title, nk_strlen(title), align);} + +NK_API int +nk_button_image_text_styled(struct nk_context *ctx, + const struct nk_style_button *style, struct nk_image img, const char *text, + int len, nk_flags align) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + + struct nk_rect bounds; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + layout = win->layout; + + state = nk_widget(&bounds, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + return nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, + bounds, img, text, len, align, ctx->button_behavior, + style, ctx->style.font, in); +} + +NK_API int +nk_button_image_text(struct nk_context *ctx, struct nk_image img, + const char *text, int len, nk_flags align) +{return nk_button_image_text_styled(ctx, &ctx->style.button,img, text, len, align);} + + +NK_API int nk_button_image_label(struct nk_context *ctx, struct nk_image img, + const char *label, nk_flags align) +{return nk_button_image_text(ctx, img, label, nk_strlen(label), align);} + +NK_API int nk_button_image_label_styled(struct nk_context *ctx, + const struct nk_style_button *style, struct nk_image img, + const char *label, nk_flags text_alignment) +{return nk_button_image_text_styled(ctx, style, img, label, nk_strlen(label), text_alignment);} + +/*---------------------------------------------------------------- + * + * SELECTABLE + * + * --------------------------------------------------------------*/ +NK_API int +nk_selectable_text(struct nk_context *ctx, const char *str, int len, + nk_flags align, int *value) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + const struct nk_style *style; + + enum nk_widget_layout_states state; + struct nk_rect bounds; + + NK_ASSERT(ctx); + NK_ASSERT(value); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout || !value) + return 0; + + win = ctx->current; + layout = win->layout; + style = &ctx->style; + + state = nk_widget(&bounds, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + return nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds, + str, len, align, value, &style->selectable, in, style->font); +} + +NK_API int +nk_selectable_image_text(struct nk_context *ctx, struct nk_image img, + const char *str, int len, nk_flags align, int *value) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + const struct nk_style *style; + + enum nk_widget_layout_states state; + struct nk_rect bounds; + + NK_ASSERT(ctx); + NK_ASSERT(value); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout || !value) + return 0; + + win = ctx->current; + layout = win->layout; + style = &ctx->style; + + state = nk_widget(&bounds, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + return nk_do_selectable_image(&ctx->last_widget_state, &win->buffer, bounds, + str, len, align, value, &img, &style->selectable, in, style->font); +} + +NK_API int nk_select_text(struct nk_context *ctx, const char *str, int len, + nk_flags align, int value) +{nk_selectable_text(ctx, str, len, align, &value);return value;} + +NK_API int nk_selectable_label(struct nk_context *ctx, const char *str, nk_flags align, int *value) +{return nk_selectable_text(ctx, str, nk_strlen(str), align, value);} + +NK_API int nk_selectable_image_label(struct nk_context *ctx,struct nk_image img, + const char *str, nk_flags align, int *value) +{return nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, value);} + +NK_API int nk_select_label(struct nk_context *ctx, const char *str, nk_flags align, int value) +{nk_selectable_text(ctx, str, nk_strlen(str), align, &value);return value;} + +NK_API int nk_select_image_label(struct nk_context *ctx, struct nk_image img, + const char *str, nk_flags align, int value) +{nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, &value);return value;} + +NK_API int nk_select_image_text(struct nk_context *ctx, struct nk_image img, + const char *str, int len, nk_flags align, int value) +{nk_selectable_image_text(ctx, img, str, len, align, &value);return value;} + +/*---------------------------------------------------------------- + * + * CHECKBOX + * + * --------------------------------------------------------------*/ +NK_API int +nk_check_text(struct nk_context *ctx, const char *text, int len, int active) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + const struct nk_style *style; + + struct nk_rect bounds; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return active; + + win = ctx->current; + style = &ctx->style; + layout = win->layout; + + state = nk_widget(&bounds, ctx); + if (!state) return active; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active, + text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font); + return active; +} + +NK_API unsigned int +nk_check_flags_text(struct nk_context *ctx, const char *text, int len, + unsigned int flags, unsigned int value) +{ + int old_active; + NK_ASSERT(ctx); + NK_ASSERT(text); + if (!ctx || !text) return flags; + old_active = (int)((flags & value) & value); + if (nk_check_text(ctx, text, len, old_active)) + flags |= value; + else flags &= ~value; + return flags; +} + +NK_API int +nk_checkbox_text(struct nk_context *ctx, const char *text, int len, int *active) +{ + int old_val; + NK_ASSERT(ctx); + NK_ASSERT(text); + NK_ASSERT(active); + if (!ctx || !text || !active) return 0; + old_val = *active; + *active = nk_check_text(ctx, text, len, *active); + return old_val != *active; +} + +NK_API int +nk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len, + unsigned int *flags, unsigned int value) +{ + int active; + NK_ASSERT(ctx); + NK_ASSERT(text); + NK_ASSERT(flags); + if (!ctx || !text || !flags) return 0; + + active = (int)((*flags & value) & value); + if (nk_checkbox_text(ctx, text, len, &active)) { + if (active) *flags |= value; + else *flags &= ~value; + return 1; + } + return 0; +} + +NK_API int nk_check_label(struct nk_context *ctx, const char *label, int active) +{return nk_check_text(ctx, label, nk_strlen(label), active);} + +NK_API unsigned int nk_check_flags_label(struct nk_context *ctx, const char *label, + unsigned int flags, unsigned int value) +{return nk_check_flags_text(ctx, label, nk_strlen(label), flags, value);} + +NK_API int nk_checkbox_label(struct nk_context *ctx, const char *label, int *active) +{return nk_checkbox_text(ctx, label, nk_strlen(label), active);} + +NK_API int nk_checkbox_flags_label(struct nk_context *ctx, const char *label, + unsigned int *flags, unsigned int value) +{return nk_checkbox_flags_text(ctx, label, nk_strlen(label), flags, value);} + +/*---------------------------------------------------------------- + * + * OPTION + * + * --------------------------------------------------------------*/ +NK_API int +nk_option_text(struct nk_context *ctx, const char *text, int len, int is_active) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + const struct nk_style *style; + + struct nk_rect bounds; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return is_active; + + win = ctx->current; + style = &ctx->style; + layout = win->layout; + + state = nk_widget(&bounds, ctx); + if (!state) return state; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active, + text, len, NK_TOGGLE_OPTION, &style->option, in, style->font); + return is_active; +} + +NK_API int +nk_radio_text(struct nk_context *ctx, const char *text, int len, int *active) +{ + int old_value; + NK_ASSERT(ctx); + NK_ASSERT(text); + NK_ASSERT(active); + if (!ctx || !text || !active) return 0; + old_value = *active; + *active = nk_option_text(ctx, text, len, old_value); + return old_value != *active; +} + +NK_API int +nk_option_label(struct nk_context *ctx, const char *label, int active) +{return nk_option_text(ctx, label, nk_strlen(label), active);} + +NK_API int +nk_radio_label(struct nk_context *ctx, const char *label, int *active) +{return nk_radio_text(ctx, label, nk_strlen(label), active);} + +/*---------------------------------------------------------------- + * + * SLIDER + * + * --------------------------------------------------------------*/ +NK_API int +nk_slider_float(struct nk_context *ctx, float min_value, float *value, float max_value, + float value_step) +{ + struct nk_window *win; + struct nk_panel *layout; + struct nk_input *in; + const struct nk_style *style; + + int ret = 0; + float old_value; + struct nk_rect bounds; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + NK_ASSERT(value); + if (!ctx || !ctx->current || !ctx->current->layout || !value) + return ret; + + win = ctx->current; + style = &ctx->style; + layout = win->layout; + + state = nk_widget(&bounds, ctx); + if (!state) return ret; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + + old_value = *value; + *value = nk_do_slider(&ctx->last_widget_state, &win->buffer, bounds, min_value, + old_value, max_value, value_step, &style->slider, in, style->font); + return (old_value > *value || old_value < *value); +} + +NK_API float +nk_slide_float(struct nk_context *ctx, float min, float val, float max, float step) +{ + nk_slider_float(ctx, min, &val, max, step); return val; +} + +NK_API int +nk_slide_int(struct nk_context *ctx, int min, int val, int max, int step) +{ + float value = (float)val; + nk_slider_float(ctx, (float)min, &value, (float)max, (float)step); + return (int)value; +} + +NK_API int +nk_slider_int(struct nk_context *ctx, int min, int *val, int max, int step) +{ + int ret; + float value = (float)*val; + ret = nk_slider_float(ctx, (float)min, &value, (float)max, (float)step); + *val = (int)value; + return ret; +} + +/*---------------------------------------------------------------- + * + * PROGRESSBAR + * + * --------------------------------------------------------------*/ +NK_API int +nk_progress(struct nk_context *ctx, nk_size *cur, nk_size max, int is_modifyable) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_style *style; + const struct nk_input *in; + + struct nk_rect bounds; + enum nk_widget_layout_states state; + nk_size old_value; + + NK_ASSERT(ctx); + NK_ASSERT(cur); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout || !cur) + return 0; + + win = ctx->current; + style = &ctx->style; + layout = win->layout; + state = nk_widget(&bounds, ctx); + if (!state) return 0; + + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + old_value = *cur; + *cur = nk_do_progress(&ctx->last_widget_state, &win->buffer, bounds, + *cur, max, is_modifyable, &style->progress, in); + return (*cur != old_value); +} + +NK_API nk_size nk_prog(struct nk_context *ctx, nk_size cur, nk_size max, int modifyable) +{nk_progress(ctx, &cur, max, modifyable);return cur;} + +/*---------------------------------------------------------------- + * + * EDIT + * + * --------------------------------------------------------------*/ +NK_API void +nk_edit_focus(struct nk_context *ctx, nk_flags flags) +{ + nk_hash hash; + struct nk_window *win; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + + win = ctx->current; + hash = win->edit.seq; + win->edit.active = nk_true; + win->edit.name = hash; + if (flags & NK_EDIT_ALWAYS_INSERT_MODE) + win->edit.mode = NK_TEXT_EDIT_MODE_INSERT; +} + +NK_API void +nk_edit_unfocus(struct nk_context *ctx) +{ + struct nk_window *win; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + + win = ctx->current; + win->edit.active = nk_false; + win->edit.name = 0; +} + +NK_API nk_flags +nk_edit_string(struct nk_context *ctx, nk_flags flags, + char *memory, int *len, int max, nk_plugin_filter filter) +{ + nk_hash hash; + nk_flags state; + struct nk_text_edit *edit; + struct nk_window *win; + + NK_ASSERT(ctx); + NK_ASSERT(memory); + NK_ASSERT(len); + if (!ctx || !memory || !len) + return 0; + + filter = (!filter) ? nk_filter_default: filter; + win = ctx->current; + hash = win->edit.seq; + edit = &ctx->text_edit; + nk_textedit_clear_state(&ctx->text_edit, (flags & NK_EDIT_MULTILINE)? + NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE, filter); + + if (win->edit.active && hash == win->edit.name) { + if (flags & NK_EDIT_NO_CURSOR) + edit->cursor = nk_utf_len(memory, *len); + else edit->cursor = win->edit.cursor; + if (!(flags & NK_EDIT_SELECTABLE)) { + edit->select_start = win->edit.cursor; + edit->select_end = win->edit.cursor; + } else { + edit->select_start = win->edit.sel_start; + edit->select_end = win->edit.sel_end; + } + edit->mode = win->edit.mode; + edit->scrollbar.x = (float)win->edit.scrollbar.x; + edit->scrollbar.y = (float)win->edit.scrollbar.y; + edit->active = nk_true; + } else edit->active = nk_false; + + max = NK_MAX(1, max); + *len = NK_MIN(*len, max-1); + nk_str_init_fixed(&edit->string, memory, (nk_size)max); + edit->string.buffer.allocated = (nk_size)*len; + edit->string.len = nk_utf_len(memory, *len); + state = nk_edit_buffer(ctx, flags, edit, filter); + *len = (int)edit->string.buffer.allocated; + + if (edit->active) { + win->edit.cursor = edit->cursor; + win->edit.sel_start = edit->select_start; + win->edit.sel_end = edit->select_end; + win->edit.mode = edit->mode; + win->edit.scrollbar.x = (nk_ushort)edit->scrollbar.x; + win->edit.scrollbar.y = (nk_ushort)edit->scrollbar.y; + } + return state; +} + +NK_API nk_flags +nk_edit_buffer(struct nk_context *ctx, nk_flags flags, + struct nk_text_edit *edit, nk_plugin_filter filter) +{ + struct nk_window *win; + struct nk_style *style; + struct nk_input *in; + + enum nk_widget_layout_states state; + struct nk_rect bounds; + + nk_flags ret_flags = 0; + unsigned char prev_state; + nk_hash hash; + + /* make sure correct values */ + NK_ASSERT(ctx); + NK_ASSERT(edit); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + style = &ctx->style; + state = nk_widget(&bounds, ctx); + if (!state) return state; + in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + + /* check if edit is currently hot item */ + hash = win->edit.seq++; + if (win->edit.active && hash == win->edit.name) { + if (flags & NK_EDIT_NO_CURSOR) + edit->cursor = edit->string.len; + if (!(flags & NK_EDIT_SELECTABLE)) { + edit->select_start = edit->cursor; + edit->select_end = edit->cursor; + } + if (flags & NK_EDIT_CLIPBOARD) + edit->clip = ctx->clip; + } + + filter = (!filter) ? nk_filter_default: filter; + prev_state = (unsigned char)edit->active; + in = (flags & NK_EDIT_READ_ONLY) ? 0: in; + ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags, + filter, edit, &style->edit, in, style->font); + + if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) + ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT]; + if (edit->active && prev_state != edit->active) { + /* current edit is now hot */ + win->edit.active = nk_true; + win->edit.name = hash; + } else if (prev_state && !edit->active) { + /* current edit is now cold */ + win->edit.active = nk_false; + } + return ret_flags; +} + +NK_API nk_flags +nk_edit_string_zero_terminated(struct nk_context *ctx, nk_flags flags, + char *buffer, int max, nk_plugin_filter filter) +{ + nk_flags result; + int len = nk_strlen(buffer); + result = nk_edit_string(ctx, flags, buffer, &len, max, filter); + buffer[NK_MIN(NK_MAX(max-1,0), len)] = '\0'; + return result; +} + +/*---------------------------------------------------------------- + * + * PROPERTY + * + * --------------------------------------------------------------*/ +NK_INTERN struct nk_property_variant +nk_property_variant_int(int value, int min_value, int max_value, int step) +{ + struct nk_property_variant result; + result.kind = NK_PROPERTY_INT; + result.value.i = value; + result.min_value.i = min_value; + result.max_value.i = max_value; + result.step.i = step; + return result; +} + +NK_INTERN struct nk_property_variant +nk_property_variant_float(float value, float min_value, float max_value, float step) +{ + struct nk_property_variant result; + result.kind = NK_PROPERTY_FLOAT; + result.value.f = value; + result.min_value.f = min_value; + result.max_value.f = max_value; + result.step.f = step; + return result; +} + +NK_INTERN struct nk_property_variant +nk_property_variant_double(double value, double min_value, double max_value, + double step) +{ + struct nk_property_variant result; + result.kind = NK_PROPERTY_DOUBLE; + result.value.d = value; + result.min_value.d = min_value; + result.max_value.d = max_value; + result.step.d = step; + return result; +} + +NK_INTERN void +nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant, + float inc_per_pixel, const enum nk_property_filter filter) +{ + struct nk_window *win; + struct nk_panel *layout; + struct nk_input *in; + const struct nk_style *style; + + struct nk_rect bounds; + enum nk_widget_layout_states s; + + int *state = 0; + nk_hash hash = 0; + char *buffer = 0; + int *len = 0; + int *cursor = 0; + int *select_begin = 0; + int *select_end = 0; + int old_state; + + char dummy_buffer[NK_MAX_NUMBER_BUFFER]; + int dummy_state = NK_PROPERTY_DEFAULT; + int dummy_length = 0; + int dummy_cursor = 0; + int dummy_select_begin = 0; + int dummy_select_end = 0; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + style = &ctx->style; + s = nk_widget(&bounds, ctx); + if (!s) return; + + /* calculate hash from name */ + if (name[0] == '#') { + hash = nk_murmur_hash(name, (int)nk_strlen(name), win->property.seq++); + name++; /* special number hash */ + } else hash = nk_murmur_hash(name, (int)nk_strlen(name), 42); + + /* check if property is currently hot item */ + if (win->property.active && hash == win->property.name) { + buffer = win->property.buffer; + len = &win->property.length; + cursor = &win->property.cursor; + state = &win->property.state; + select_begin = &win->property.select_start; + select_end = &win->property.select_end; + } else { + buffer = dummy_buffer; + len = &dummy_length; + cursor = &dummy_cursor; + state = &dummy_state; + select_begin = &dummy_select_begin; + select_end = &dummy_select_end; + } + + /* execute property widget */ + old_state = *state; + ctx->text_edit.clip = ctx->clip; + in = ((s == NK_WIDGET_ROM && !win->property.active) || + layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name, + variant, inc_per_pixel, buffer, len, state, cursor, select_begin, + select_end, &style->property, filter, in, style->font, &ctx->text_edit, + ctx->button_behavior); + + if (in && *state != NK_PROPERTY_DEFAULT && !win->property.active) { + /* current property is now hot */ + win->property.active = 1; + NK_MEMCPY(win->property.buffer, buffer, (nk_size)*len); + win->property.length = *len; + win->property.cursor = *cursor; + win->property.state = *state; + win->property.name = hash; + win->property.select_start = *select_begin; + win->property.select_end = *select_end; + if (*state == NK_PROPERTY_DRAG) { + ctx->input.mouse.grab = nk_true; + ctx->input.mouse.grabbed = nk_true; + } + } + /* check if previously active property is now inactive */ + if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) { + if (old_state == NK_PROPERTY_DRAG) { + ctx->input.mouse.grab = nk_false; + ctx->input.mouse.grabbed = nk_false; + ctx->input.mouse.ungrab = nk_true; + } + win->property.select_start = 0; + win->property.select_end = 0; + win->property.active = 0; + } +} + +NK_API void +nk_property_int(struct nk_context *ctx, const char *name, + int min, int *val, int max, int step, float inc_per_pixel) +{ + struct nk_property_variant variant; + NK_ASSERT(ctx); + NK_ASSERT(name); + NK_ASSERT(val); + + if (!ctx || !ctx->current || !name || !val) return; + variant = nk_property_variant_int(*val, min, max, step); + nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT); + *val = variant.value.i; +} + +NK_API void +nk_property_float(struct nk_context *ctx, const char *name, + float min, float *val, float max, float step, float inc_per_pixel) +{ + struct nk_property_variant variant; + NK_ASSERT(ctx); + NK_ASSERT(name); + NK_ASSERT(val); + + if (!ctx || !ctx->current || !name || !val) return; + variant = nk_property_variant_float(*val, min, max, step); + nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); + *val = variant.value.f; +} + +NK_API void +nk_property_double(struct nk_context *ctx, const char *name, + double min, double *val, double max, double step, float inc_per_pixel) +{ + struct nk_property_variant variant; + NK_ASSERT(ctx); + NK_ASSERT(name); + NK_ASSERT(val); + + if (!ctx || !ctx->current || !name || !val) return; + variant = nk_property_variant_double(*val, min, max, step); + nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); + *val = variant.value.d; +} + +NK_API int +nk_propertyi(struct nk_context *ctx, const char *name, int min, int val, + int max, int step, float inc_per_pixel) +{ + struct nk_property_variant variant; + NK_ASSERT(ctx); + NK_ASSERT(name); + + if (!ctx || !ctx->current || !name) return val; + variant = nk_property_variant_int(val, min, max, step); + nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT); + val = variant.value.i; + return val; +} + +NK_API float +nk_propertyf(struct nk_context *ctx, const char *name, float min, + float val, float max, float step, float inc_per_pixel) +{ + struct nk_property_variant variant; + NK_ASSERT(ctx); + NK_ASSERT(name); + + if (!ctx || !ctx->current || !name) return val; + variant = nk_property_variant_float(val, min, max, step); + nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); + val = variant.value.f; + return val; +} + +NK_API double +nk_propertyd(struct nk_context *ctx, const char *name, double min, + double val, double max, double step, float inc_per_pixel) +{ + struct nk_property_variant variant; + NK_ASSERT(ctx); + NK_ASSERT(name); + + if (!ctx || !ctx->current || !name) return val; + variant = nk_property_variant_double(val, min, max, step); + nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); + val = variant.value.d; + return val; +} + +/*---------------------------------------------------------------- + * + * COLOR PICKER + * + * --------------------------------------------------------------*/ +NK_API int +nk_color_pick(struct nk_context * ctx, struct nk_color *color, + enum nk_color_format fmt) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_style *config; + const struct nk_input *in; + + enum nk_widget_layout_states state; + struct nk_rect bounds; + + NK_ASSERT(ctx); + NK_ASSERT(color); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout || !color) + return 0; + + win = ctx->current; + config = &ctx->style; + layout = win->layout; + state = nk_widget(&bounds, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + return nk_do_color_picker(&ctx->last_widget_state, &win->buffer, color, fmt, bounds, + nk_vec2(0,0), in, config->font); +} + +NK_API struct nk_color +nk_color_picker(struct nk_context *ctx, struct nk_color color, + enum nk_color_format fmt) +{ + nk_color_pick(ctx, &color, fmt); + return color; +} + +/* ------------------------------------------------------------- + * + * CHART + * + * --------------------------------------------------------------*/ +NK_API int +nk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type, + struct nk_color color, struct nk_color highlight, + int count, float min_value, float max_value) +{ + struct nk_window *win; + struct nk_chart *chart; + const struct nk_style *config; + const struct nk_style_chart *style; + + const struct nk_style_item *background; + struct nk_rect bounds = {0, 0, 0, 0}; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + + if (!ctx || !ctx->current || !ctx->current->layout) return 0; + if (!nk_widget(&bounds, ctx)) { + chart = &ctx->current->layout->chart; + nk_zero(chart, sizeof(*chart)); + return 0; + } + + win = ctx->current; + config = &ctx->style; + chart = &win->layout->chart; + style = &config->chart; + + /* setup basic generic chart */ + nk_zero(chart, sizeof(*chart)); + chart->x = bounds.x + style->padding.x; + chart->y = bounds.y + style->padding.y; + chart->w = bounds.w - 2 * style->padding.x; + chart->h = bounds.h - 2 * style->padding.y; + chart->w = NK_MAX(chart->w, 2 * style->padding.x); + chart->h = NK_MAX(chart->h, 2 * style->padding.y); + + /* add first slot into chart */ + {struct nk_chart_slot *slot = &chart->slots[chart->slot++]; + slot->type = type; + slot->count = count; + slot->color = color; + slot->highlight = highlight; + slot->min = NK_MIN(min_value, max_value); + slot->max = NK_MAX(min_value, max_value); + slot->range = slot->max - slot->min;} + + /* draw chart background */ + background = &style->background; + if (background->type == NK_STYLE_ITEM_IMAGE) { + nk_draw_image(&win->buffer, bounds, &background->data.image, nk_white); + } else { + nk_fill_rect(&win->buffer, bounds, style->rounding, style->border_color); + nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border), + style->rounding, style->background.data.color); + } + return 1; +} + +NK_API int +nk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type, + int count, float min_value, float max_value) +{return nk_chart_begin_colored(ctx, type, ctx->style.chart.color, ctx->style.chart.selected_color, count, min_value, max_value);} + +NK_API void +nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type, + struct nk_color color, struct nk_color highlight, + int count, float min_value, float max_value) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT); + if (!ctx || !ctx->current || !ctx->current->layout) return; + if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return; + + /* add another slot into the graph */ + {struct nk_chart *chart = &ctx->current->layout->chart; + struct nk_chart_slot *slot = &chart->slots[chart->slot++]; + slot->type = type; + slot->count = count; + slot->color = color; + slot->highlight = highlight; + slot->min = NK_MIN(min_value, max_value); + slot->max = NK_MAX(min_value, max_value); + slot->range = slot->max - slot->min;} +} + +NK_API void +nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type, + int count, float min_value, float max_value) +{nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color, ctx->style.chart.selected_color, count, min_value, max_value);} + +NK_INTERN nk_flags +nk_chart_push_line(struct nk_context *ctx, struct nk_window *win, + struct nk_chart *g, float value, int slot) +{ + struct nk_panel *layout = win->layout; + const struct nk_input *i = &ctx->input; + struct nk_command_buffer *out = &win->buffer; + + nk_flags ret = 0; + struct nk_vec2 cur; + struct nk_rect bounds; + struct nk_color color; + float step; + float range; + float ratio; + + NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); + step = g->w / (float)g->slots[slot].count; + range = g->slots[slot].max - g->slots[slot].min; + ratio = (value - g->slots[slot].min) / range; + + if (g->slots[slot].index == 0) { + /* first data point does not have a connection */ + g->slots[slot].last.x = g->x; + g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h; + + bounds.x = g->slots[slot].last.x - 2; + bounds.y = g->slots[slot].last.y - 2; + bounds.w = bounds.h = 4; + + color = g->slots[slot].color; + if (!(layout->flags & NK_WINDOW_ROM) && + NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){ + ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0; + ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down && + i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; + color = g->slots[slot].highlight; + } + nk_fill_rect(out, bounds, 0, color); + g->slots[slot].index += 1; + return ret; + } + + /* draw a line between the last data point and the new one */ + color = g->slots[slot].color; + cur.x = g->x + (float)(step * (float)g->slots[slot].index); + cur.y = (g->y + g->h) - (ratio * (float)g->h); + nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color); + + bounds.x = cur.x - 3; + bounds.y = cur.y - 3; + bounds.w = bounds.h = 6; + + /* user selection of current data point */ + if (!(layout->flags & NK_WINDOW_ROM)) { + if (nk_input_is_mouse_hovering_rect(i, bounds)) { + ret = NK_CHART_HOVERING; + ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down && + i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; + color = g->slots[slot].highlight; + } + } + nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color); + + /* save current data point position */ + g->slots[slot].last.x = cur.x; + g->slots[slot].last.y = cur.y; + g->slots[slot].index += 1; + return ret; +} + +NK_INTERN nk_flags +nk_chart_push_column(const struct nk_context *ctx, struct nk_window *win, + struct nk_chart *chart, float value, int slot) +{ + struct nk_command_buffer *out = &win->buffer; + const struct nk_input *in = &ctx->input; + struct nk_panel *layout = win->layout; + + float ratio; + nk_flags ret = 0; + struct nk_color color; + struct nk_rect item = {0,0,0,0}; + + NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); + if (chart->slots[slot].index >= chart->slots[slot].count) + return nk_false; + if (chart->slots[slot].count) { + float padding = (float)(chart->slots[slot].count-1); + item.w = (chart->w - padding) / (float)(chart->slots[slot].count); + } + + /* calculate bounds of current bar chart entry */ + color = chart->slots[slot].color;; + item.h = chart->h * NK_ABS((value/chart->slots[slot].range)); + if (value >= 0) { + ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range); + item.y = (chart->y + chart->h) - chart->h * ratio; + } else { + ratio = (value - chart->slots[slot].max) / chart->slots[slot].range; + item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h; + } + item.x = chart->x + ((float)chart->slots[slot].index * item.w); + item.x = item.x + ((float)chart->slots[slot].index); + + /* user chart bar selection */ + if (!(layout->flags & NK_WINDOW_ROM) && + NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) { + ret = NK_CHART_HOVERING; + ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down && + in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; + color = chart->slots[slot].highlight; + } + nk_fill_rect(out, item, 0, color); + chart->slots[slot].index += 1; + return ret; +} + +NK_API nk_flags +nk_chart_push_slot(struct nk_context *ctx, float value, int slot) +{ + nk_flags flags; + struct nk_window *win; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); + NK_ASSERT(slot < ctx->current->layout->chart.slot); + if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false; + if (slot >= ctx->current->layout->chart.slot) return nk_false; + + win = ctx->current; + if (win->layout->chart.slot < slot) return nk_false; + switch (win->layout->chart.slots[slot].type) { + case NK_CHART_LINES: + flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break; + case NK_CHART_COLUMN: + flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break; + default: + case NK_CHART_MAX: + flags = 0; + } + return flags; +} + +NK_API nk_flags +nk_chart_push(struct nk_context *ctx, float value) +{return nk_chart_push_slot(ctx, value, 0);} + +NK_API void +nk_chart_end(struct nk_context *ctx) +{ + struct nk_window *win; + struct nk_chart *chart; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return; + + win = ctx->current; + chart = &win->layout->chart; + NK_MEMSET(chart, 0, sizeof(*chart)); + return; +} + +NK_API void +nk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values, + int count, int offset) +{ + int i = 0; + float min_value; + float max_value; + + NK_ASSERT(ctx); + NK_ASSERT(values); + if (!ctx || !values || !count) return; + + min_value = values[offset]; + max_value = values[offset]; + for (i = 0; i < count; ++i) { + min_value = NK_MIN(values[i + offset], min_value); + max_value = NK_MAX(values[i + offset], max_value); + } + + if (nk_chart_begin(ctx, type, count, min_value, max_value)) { + for (i = 0; i < count; ++i) + nk_chart_push(ctx, values[i + offset]); + nk_chart_end(ctx); + } +} + +NK_API void +nk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata, + float(*value_getter)(void* user, int index), int count, int offset) +{ + int i = 0; + float min_value; + float max_value; + + NK_ASSERT(ctx); + NK_ASSERT(value_getter); + if (!ctx || !value_getter || !count) return; + + max_value = min_value = value_getter(userdata, offset); + for (i = 0; i < count; ++i) { + float value = value_getter(userdata, i + offset); + min_value = NK_MIN(value, min_value); + max_value = NK_MAX(value, max_value); + } + + if (nk_chart_begin(ctx, type, count, min_value, max_value)) { + for (i = 0; i < count; ++i) + nk_chart_push(ctx, value_getter(userdata, i + offset)); + nk_chart_end(ctx); + } +} + +/* ------------------------------------------------------------- + * + * GROUP + * + * --------------------------------------------------------------*/ +NK_API int +nk_group_scrolled_offset_begin(struct nk_context *ctx, + nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags) +{ + struct nk_rect bounds; + struct nk_window panel; + struct nk_window *win; + + win = ctx->current; + nk_panel_alloc_space(&bounds, ctx); + {const struct nk_rect *c = &win->layout->clip; + if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) && + !(flags & NK_WINDOW_MOVABLE)) { + return 0; + }} + if (win->flags & NK_WINDOW_ROM) + flags |= NK_WINDOW_ROM; + + /* initialize a fake window to create the panel from */ + nk_zero(&panel, sizeof(panel)); + panel.bounds = bounds; + panel.flags = flags; + panel.scrollbar.x = *x_offset; + panel.scrollbar.y = *y_offset; + panel.buffer = win->buffer; + panel.layout = (struct nk_panel*)nk_create_panel(ctx); + ctx->current = &panel; + nk_panel_begin(ctx, (flags & NK_WINDOW_TITLE) ? title: 0, NK_PANEL_GROUP); + + win->buffer = panel.buffer; + win->buffer.clip = panel.layout->clip; + panel.layout->offset_x = x_offset; + panel.layout->offset_y = y_offset; + panel.layout->parent = win->layout; + win->layout = panel.layout; + + ctx->current = win; + if ((panel.layout->flags & NK_WINDOW_CLOSED) || + (panel.layout->flags & NK_WINDOW_MINIMIZED)) + { + nk_flags f = panel.layout->flags; + nk_group_scrolled_end(ctx); + if (f & NK_WINDOW_CLOSED) + return NK_WINDOW_CLOSED; + if (f & NK_WINDOW_MINIMIZED) + return NK_WINDOW_MINIMIZED; + } + return 1; +} + +NK_API void +nk_group_scrolled_end(struct nk_context *ctx) +{ + struct nk_window *win; + struct nk_panel *parent; + struct nk_panel *g; + + struct nk_rect clip; + struct nk_window pan; + struct nk_vec2 panel_padding; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return; + + /* make sure nk_group_begin was called correctly */ + NK_ASSERT(ctx->current); + win = ctx->current; + NK_ASSERT(win->layout); + g = win->layout; + NK_ASSERT(g->parent); + parent = g->parent; + + /* dummy window */ + nk_zero_struct(pan); + panel_padding = nk_panel_get_padding(&ctx->style, NK_PANEL_GROUP); + pan.bounds.y = g->bounds.y - (g->header_height + g->menu.h); + pan.bounds.x = g->bounds.x - panel_padding.x; + pan.bounds.w = g->bounds.w + 2 * panel_padding.x; + pan.bounds.h = g->bounds.h + g->header_height + g->menu.h; + if (g->flags & NK_WINDOW_BORDER) { + pan.bounds.x -= g->border; + pan.bounds.y -= g->border; + pan.bounds.w += 2*g->border; + pan.bounds.h += 2*g->border; + } + if (!(g->flags & NK_WINDOW_NO_SCROLLBAR)) { + pan.bounds.w += ctx->style.window.scrollbar_size.x; + pan.bounds.h += ctx->style.window.scrollbar_size.y; + } + pan.scrollbar.x = *g->offset_x; + pan.scrollbar.y = *g->offset_y; + pan.flags = g->flags; + pan.buffer = win->buffer; + pan.layout = g; + pan.parent = win; + ctx->current = &pan; + + /* make sure group has correct clipping rectangle */ + nk_unify(&clip, &parent->clip, pan.bounds.x, pan.bounds.y, + pan.bounds.x + pan.bounds.w, pan.bounds.y + pan.bounds.h + panel_padding.x); + nk_push_scissor(&pan.buffer, clip); + nk_end(ctx); + + win->buffer = pan.buffer; + nk_push_scissor(&win->buffer, parent->clip); + ctx->current = win; + win->layout = parent; + g->bounds = pan.bounds; + return; +} + +NK_API int +nk_group_scrolled_begin(struct nk_context *ctx, + struct nk_scroll *scroll, const char *title, nk_flags flags) +{return nk_group_scrolled_offset_begin(ctx, &scroll->x, &scroll->y, title, flags);} + +NK_API int +nk_group_begin(struct nk_context *ctx, const char *title, nk_flags flags) +{ + int title_len; + nk_hash title_hash; + struct nk_window *win; + nk_uint *x_offset; + nk_uint *y_offset; + + NK_ASSERT(ctx); + NK_ASSERT(title); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout || !title) + return 0; + + /* find persistent group scrollbar value */ + win = ctx->current; + title_len = (int)nk_strlen(title); + title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP); + x_offset = nk_find_value(win, title_hash); + if (!x_offset) { + x_offset = nk_add_value(ctx, win, title_hash, 0); + y_offset = nk_add_value(ctx, win, title_hash+1, 0); + + NK_ASSERT(x_offset); + NK_ASSERT(y_offset); + if (!x_offset || !y_offset) return 0; + *x_offset = *y_offset = 0; + } else y_offset = nk_find_value(win, title_hash+1); + return nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags); +} + +NK_API void +nk_group_end(struct nk_context *ctx) +{nk_group_scrolled_end(ctx);} + +NK_API int +nk_list_view_begin(struct nk_context *ctx, struct nk_list_view *view, + const char *title, nk_flags flags, int row_height, int row_count) +{ + int title_len; + nk_hash title_hash; + nk_uint *x_offset; + nk_uint *y_offset; + + int result; + struct nk_window *win; + struct nk_panel *layout; + const struct nk_style *style; + struct nk_vec2 item_spacing; + + NK_ASSERT(ctx); + NK_ASSERT(view); + NK_ASSERT(title); + if (!ctx || !view || !title) return 0; + + win = ctx->current; + style = &ctx->style; + item_spacing = style->window.spacing; + row_height += NK_MAX(0, (int)item_spacing.y); + + /* find persistent list view scrollbar offset */ + title_len = (int)nk_strlen(title); + title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP); + x_offset = nk_find_value(win, title_hash); + if (!x_offset) { + x_offset = nk_add_value(ctx, win, title_hash, 0); + y_offset = nk_add_value(ctx, win, title_hash+1, 0); + + NK_ASSERT(x_offset); + NK_ASSERT(y_offset); + if (!x_offset || !y_offset) return 0; + *x_offset = *y_offset = 0; + } else y_offset = nk_find_value(win, title_hash+1); + view->scroll_value = *y_offset; + view->scroll_pointer = y_offset; + + *y_offset = 0; + result = nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags); + win = ctx->current; + layout = win->layout; + + view->total_height = row_height * NK_MAX(row_count,1); + view->begin = (int)NK_MAX(((float)view->scroll_value / (float)row_height), 0.0f); + view->count = (int)NK_MAX(nk_iceilf((layout->clip.h)/(float)row_height), 0); + view->end = view->begin + view->count; + view->ctx = ctx; + return result; +} + +NK_API void +nk_list_view_end(struct nk_list_view *view) +{ + struct nk_context *ctx; + struct nk_window *win; + struct nk_panel *layout; + + NK_ASSERT(view); + NK_ASSERT(view->ctx); + NK_ASSERT(view->scroll_pointer); + if (!view || !view->ctx) return; + + ctx = view->ctx; + win = ctx->current; + layout = win->layout; + layout->at_y = layout->bounds.y + (float)view->total_height; + *view->scroll_pointer = *view->scroll_pointer + view->scroll_value; + nk_group_end(view->ctx); +} + +/* -------------------------------------------------------------- + * + * POPUP + * + * --------------------------------------------------------------*/ +NK_API int +nk_popup_begin(struct nk_context *ctx, enum nk_popup_type type, + const char *title, nk_flags flags, struct nk_rect rect) +{ + struct nk_window *popup; + struct nk_window *win; + struct nk_panel *panel; + + int title_len; + nk_hash title_hash; + nk_size allocated; + + NK_ASSERT(ctx); + NK_ASSERT(title); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + panel = win->layout; + NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP) && "popups are not allowed to have popups"); + (void)panel; + title_len = (int)nk_strlen(title); + title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_POPUP); + + popup = win->popup.win; + if (!popup) { + popup = (struct nk_window*)nk_create_window(ctx); + popup->parent = win; + win->popup.win = popup; + win->popup.active = 0; + win->popup.type = NK_PANEL_POPUP; + } + + /* make sure we have correct popup */ + if (win->popup.name != title_hash) { + if (!win->popup.active) { + nk_zero(popup, sizeof(*popup)); + win->popup.name = title_hash; + win->popup.active = 1; + win->popup.type = NK_PANEL_POPUP; + } else return 0; + } + + /* popup position is local to window */ + ctx->current = popup; + rect.x += win->layout->clip.x; + rect.y += win->layout->clip.y; + + /* setup popup data */ + popup->parent = win; + popup->bounds = rect; + popup->seq = ctx->seq; + popup->layout = (struct nk_panel*)nk_create_panel(ctx); + popup->flags = flags; + popup->flags |= NK_WINDOW_BORDER; + if (type == NK_POPUP_DYNAMIC) + popup->flags |= NK_WINDOW_DYNAMIC; + + popup->buffer = win->buffer; + nk_start_popup(ctx, win); + allocated = ctx->memory.allocated; + nk_push_scissor(&popup->buffer, nk_null_rect); + + if (nk_panel_begin(ctx, title, NK_PANEL_POPUP)) { + /* popup is running therefore invalidate parent panels */ + struct nk_panel *root; + root = win->layout; + while (root) { + root->flags |= NK_WINDOW_ROM; + root->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM; + root = root->parent; + } + win->popup.active = 1; + popup->layout->offset_x = &popup->scrollbar.x; + popup->layout->offset_y = &popup->scrollbar.y; + popup->layout->parent = win->layout; + return 1; + } else { + /* popup was closed/is invalid so cleanup */ + struct nk_panel *root; + root = win->layout; + while (root) { + root->flags |= NK_WINDOW_REMOVE_ROM; + root = root->parent; + } + win->popup.buf.active = 0; + win->popup.active = 0; + ctx->memory.allocated = allocated; + ctx->current = win; + nk_free_panel(ctx, popup->layout); + popup->layout = 0; + return 0; + } +} + +NK_INTERN int +nk_nonblock_begin(struct nk_context *ctx, + nk_flags flags, struct nk_rect body, struct nk_rect header, + enum nk_panel_type panel_type) +{ + struct nk_window *popup; + struct nk_window *win; + struct nk_panel *panel; + int is_active = nk_true; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + /* popups cannot have popups */ + win = ctx->current; + panel = win->layout; + NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP)); + (void)panel; + popup = win->popup.win; + if (!popup) { + /* create window for nonblocking popup */ + popup = (struct nk_window*)nk_create_window(ctx); + popup->parent = win; + win->popup.win = popup; + win->popup.type = panel_type; + nk_command_buffer_init(&popup->buffer, &ctx->memory, NK_CLIPPING_ON); + } else { + /* close the popup if user pressed outside or in the header */ + int pressed, in_body, in_header; + pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT); + in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body); + in_header = nk_input_is_mouse_hovering_rect(&ctx->input, header); + if (pressed && (!in_body || in_header)) + is_active = nk_false; + } + win->popup.header = header; + + if (!is_active) { + /* remove read only mode from all parent panels */ + struct nk_panel *root = win->layout; + while (root) { + root->flags |= NK_WINDOW_REMOVE_ROM; + root = root->parent; + } + return is_active; + } + + popup->bounds = body; + popup->parent = win; + popup->layout = (struct nk_panel*)nk_create_panel(ctx); + popup->flags = flags; + popup->flags |= NK_WINDOW_BORDER; + popup->flags |= NK_WINDOW_DYNAMIC; + popup->seq = ctx->seq; + win->popup.active = 1; + NK_ASSERT(popup->layout); + + nk_start_popup(ctx, win); + popup->buffer = win->buffer; + nk_push_scissor(&popup->buffer, nk_null_rect); + ctx->current = popup; + + nk_panel_begin(ctx, 0, panel_type); + win->buffer = popup->buffer; + popup->layout->parent = win->layout; + popup->layout->offset_x = &popup->scrollbar.x; + popup->layout->offset_y = &popup->scrollbar.y; + + /* set read only mode to all parent panels */ + {struct nk_panel *root; + root = win->layout; + while (root) { + root->flags |= NK_WINDOW_ROM; + root = root->parent; + }} + return is_active; +} + +NK_API void +nk_popup_close(struct nk_context *ctx) +{ + struct nk_window *popup; + NK_ASSERT(ctx); + if (!ctx || !ctx->current) return; + + popup = ctx->current; + NK_ASSERT(popup->parent); + NK_ASSERT(popup->layout->type & NK_PANEL_SET_POPUP); + popup->flags |= NK_WINDOW_HIDDEN; +} + +NK_API void +nk_popup_end(struct nk_context *ctx) +{ + struct nk_window *win; + struct nk_window *popup; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + popup = ctx->current; + if (!popup->parent) return; + win = popup->parent; + if (popup->flags & NK_WINDOW_HIDDEN) { + struct nk_panel *root; + root = win->layout; + while (root) { + root->flags |= NK_WINDOW_REMOVE_ROM; + root = root->parent; + } + win->popup.active = 0; + } + nk_push_scissor(&popup->buffer, nk_null_rect); + nk_end(ctx); + + win->buffer = popup->buffer; + nk_finish_popup(ctx, win); + ctx->current = win; + nk_push_scissor(&win->buffer, win->layout->clip); +} +/* ------------------------------------------------------------- + * + * TOOLTIP + * + * -------------------------------------------------------------- */ +NK_API int +nk_tooltip_begin(struct nk_context *ctx, float width) +{ + struct nk_window *win; + const struct nk_input *in; + struct nk_rect bounds; + int ret; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + /* make sure that no nonblocking popup is currently active */ + win = ctx->current; + in = &ctx->input; + if (win->popup.win && (win->popup.type & NK_PANEL_SET_NONBLOCK)) + return 0; + + bounds.w = width; + bounds.h = nk_null_rect.h; + bounds.x = (in->mouse.pos.x + 1) - win->layout->clip.x; + bounds.y = (in->mouse.pos.y + 1) - win->layout->clip.y; + + ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC, + "__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds); + if (ret) win->layout->flags &= ~(nk_flags)NK_WINDOW_ROM; + win->popup.type = NK_PANEL_TOOLTIP; + ctx->current->layout->type = NK_PANEL_TOOLTIP; + return ret; +} + +NK_API void +nk_tooltip_end(struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + ctx->current->seq--; + nk_popup_close(ctx); + nk_popup_end(ctx); +} + +NK_API void +nk_tooltip(struct nk_context *ctx, const char *text) +{ + const struct nk_style *style; + struct nk_vec2 padding; + + int text_len; + float text_width; + float text_height; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + NK_ASSERT(text); + if (!ctx || !ctx->current || !ctx->current->layout || !text) + return; + + /* fetch configuration data */ + style = &ctx->style; + padding = style->window.padding; + + /* calculate size of the text and tooltip */ + text_len = nk_strlen(text); + text_width = style->font->width(style->font->userdata, + style->font->height, text, text_len); + text_width += (4 * padding.x); + text_height = (style->font->height + 2 * padding.y); + + /* execute tooltip and fill with text */ + if (nk_tooltip_begin(ctx, (float)text_width)) { + nk_layout_row_dynamic(ctx, (float)text_height, 1); + nk_text(ctx, text, text_len, NK_TEXT_LEFT); + nk_tooltip_end(ctx); + } +} +/* ------------------------------------------------------------- + * + * CONTEXTUAL + * + * -------------------------------------------------------------- */ +NK_API int +nk_contextual_begin(struct nk_context *ctx, nk_flags flags, struct nk_vec2 size, + struct nk_rect trigger_bounds) +{ + struct nk_window *win; + struct nk_window *popup; + struct nk_rect body; + + NK_STORAGE const struct nk_rect null_rect = {0,0,0,0}; + int is_clicked = 0; + int is_active = 0; + int is_open = 0; + int ret = 0; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + ++win->popup.con_count; + + /* check if currently active contextual is active */ + popup = win->popup.win; + is_open = (popup && win->popup.type == NK_PANEL_CONTEXTUAL); + is_clicked = nk_input_mouse_clicked(&ctx->input, NK_BUTTON_RIGHT, trigger_bounds); + if (win->popup.active_con && win->popup.con_count != win->popup.active_con) + return 0; + if ((is_clicked && is_open && !is_active) || (!is_open && !is_active && !is_clicked)) + return 0; + + /* calculate contextual position on click */ + win->popup.active_con = win->popup.con_count; + if (is_clicked) { + body.x = ctx->input.mouse.pos.x; + body.y = ctx->input.mouse.pos.y; + } else { + body.x = popup->bounds.x; + body.y = popup->bounds.y; + } + body.w = size.x; + body.h = size.y; + + /* start nonblocking contextual popup */ + ret = nk_nonblock_begin(ctx, flags|NK_WINDOW_NO_SCROLLBAR, body, + null_rect, NK_PANEL_CONTEXTUAL); + if (ret) win->popup.type = NK_PANEL_CONTEXTUAL; + else { + win->popup.active_con = 0; + if (win->popup.win) + win->popup.win->flags = 0; + } + return ret; +} + +NK_API int +nk_contextual_item_text(struct nk_context *ctx, const char *text, int len, + nk_flags alignment) +{ + struct nk_window *win; + const struct nk_input *in; + const struct nk_style *style; + + struct nk_rect bounds; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + style = &ctx->style; + state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); + if (!state) return nk_false; + + in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds, + text, len, alignment, NK_BUTTON_DEFAULT, &style->contextual_button, in, style->font)) { + nk_contextual_close(ctx); + return nk_true; + } + return nk_false; +} + +NK_API int nk_contextual_item_label(struct nk_context *ctx, const char *label, nk_flags align) +{return nk_contextual_item_text(ctx, label, nk_strlen(label), align);} + +NK_API int +nk_contextual_item_image_text(struct nk_context *ctx, struct nk_image img, + const char *text, int len, nk_flags align) +{ + struct nk_window *win; + const struct nk_input *in; + const struct nk_style *style; + + struct nk_rect bounds; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + style = &ctx->style; + state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); + if (!state) return nk_false; + + in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, bounds, + img, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)){ + nk_contextual_close(ctx); + return nk_true; + } + return nk_false; +} + +NK_API int nk_contextual_item_image_label(struct nk_context *ctx, struct nk_image img, + const char *label, nk_flags align) +{return nk_contextual_item_image_text(ctx, img, label, nk_strlen(label), align);} + +NK_API int +nk_contextual_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol, + const char *text, int len, nk_flags align) +{ + struct nk_window *win; + const struct nk_input *in; + const struct nk_style *style; + + struct nk_rect bounds; + enum nk_widget_layout_states state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + style = &ctx->style; + state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); + if (!state) return nk_false; + + in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds, + symbol, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)) { + nk_contextual_close(ctx); + return nk_true; + } + return nk_false; +} + +NK_API int nk_contextual_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol, + const char *text, nk_flags align) +{return nk_contextual_item_symbol_text(ctx, symbol, text, nk_strlen(text), align);} + +NK_API void +nk_contextual_close(struct nk_context *ctx) +{ + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) return; + nk_popup_close(ctx); +} + +NK_API void +nk_contextual_end(struct nk_context *ctx) +{ + struct nk_window *popup; + struct nk_panel *panel; + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + + popup = ctx->current; + panel = popup->layout; + NK_ASSERT(popup->parent); + NK_ASSERT(panel->type & NK_PANEL_SET_POPUP); + if (panel->flags & NK_WINDOW_DYNAMIC) { + /* Close behavior + This is a bit of a hack solution since we do not know before we end our popup + how big it will be. We therefore do not directly know when a + click outside the non-blocking popup must close it at that direct frame. + Instead it will be closed in the next frame.*/ + struct nk_rect body = {0,0,0,0}; + if (panel->at_y < (panel->bounds.y + panel->bounds.h)) { + struct nk_vec2 padding = nk_panel_get_padding(&ctx->style, panel->type); + body = panel->bounds; + body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height); + body.h = (panel->bounds.y + panel->bounds.h) - body.y; + } + {int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT); + int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body); + if (pressed && in_body) + popup->flags |= NK_WINDOW_HIDDEN; + } + } + if (popup->flags & NK_WINDOW_HIDDEN) + popup->seq = 0; + nk_popup_end(ctx); + return; +} +/* ------------------------------------------------------------- + * + * COMBO + * + * --------------------------------------------------------------*/ +NK_INTERN int +nk_combo_begin(struct nk_context *ctx, struct nk_window *win, + struct nk_vec2 size, int is_clicked, struct nk_rect header) +{ + struct nk_window *popup; + int is_open = 0; + int is_active = 0; + struct nk_rect body; + nk_hash hash; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + popup = win->popup.win; + body.x = header.x; + body.w = size.x; + body.y = header.y + header.h-ctx->style.window.combo_border; + body.h = size.y; + + hash = win->popup.combo_count++; + is_open = (popup) ? nk_true:nk_false; + is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_COMBO); + if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || + (!is_open && !is_active && !is_clicked)) return 0; + if (!nk_nonblock_begin(ctx, 0, body, + (is_clicked && is_open)?nk_rect(0,0,0,0):header, NK_PANEL_COMBO)) return 0; + + win->popup.type = NK_PANEL_COMBO; + win->popup.name = hash; + return 1; +} + +NK_API int +nk_combo_begin_text(struct nk_context *ctx, const char *selected, int len, + struct nk_vec2 size) +{ + const struct nk_input *in; + struct nk_window *win; + struct nk_style *style; + + enum nk_widget_layout_states s; + int is_clicked = nk_false; + struct nk_rect header; + const struct nk_style_item *background; + struct nk_text text; + + NK_ASSERT(ctx); + NK_ASSERT(selected); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout || !selected) + return 0; + + win = ctx->current; + style = &ctx->style; + s = nk_widget(&header, ctx); + if (s == NK_WIDGET_INVALID) + return 0; + + in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; + if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) + is_clicked = nk_true; + + /* draw combo box header background and border */ + if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { + background = &style->combo.active; + text.text = style->combo.label_active; + } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { + background = &style->combo.hover; + text.text = style->combo.label_hover; + } else { + background = &style->combo.normal; + text.text = style->combo.label_normal; + } + if (background->type == NK_STYLE_ITEM_IMAGE) { + text.background = nk_rgba(0,0,0,0); + nk_draw_image(&win->buffer, header, &background->data.image, nk_white); + } else { + text.background = background->data.color; + nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); + nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); + } + { + /* print currently selected text item */ + struct nk_rect label; + struct nk_rect button; + struct nk_rect content; + + enum nk_symbol_type sym; + if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) + sym = style->combo.sym_hover; + else if (is_clicked) + sym = style->combo.sym_active; + else sym = style->combo.sym_normal; + + /* calculate button */ + button.w = header.h - 2 * style->combo.button_padding.y; + button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; + button.y = header.y + style->combo.button_padding.y; + button.h = button.w; + + content.x = button.x + style->combo.button.padding.x; + content.y = button.y + style->combo.button.padding.y; + content.w = button.w - 2 * style->combo.button.padding.x; + content.h = button.h - 2 * style->combo.button.padding.y; + + /* draw selected label */ + text.padding = nk_vec2(0,0); + label.x = header.x + style->combo.content_padding.x; + label.y = header.y + style->combo.content_padding.y; + label.w = button.x - (style->combo.content_padding.x + style->combo.spacing.x) - label.x;; + label.h = header.h - 2 * style->combo.content_padding.y; + nk_widget_text(&win->buffer, label, selected, len, &text, + NK_TEXT_LEFT, ctx->style.font); + + /* draw open/close button */ + nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, + &ctx->style.combo.button, sym, style->font); + } + return nk_combo_begin(ctx, win, size, is_clicked, header); +} + +NK_API int nk_combo_begin_label(struct nk_context *ctx, const char *selected, struct nk_vec2 size) +{return nk_combo_begin_text(ctx, selected, nk_strlen(selected), size);} + +NK_API int +nk_combo_begin_color(struct nk_context *ctx, struct nk_color color, struct nk_vec2 size) +{ + struct nk_window *win; + struct nk_style *style; + const struct nk_input *in; + + struct nk_rect header; + int is_clicked = nk_false; + enum nk_widget_layout_states s; + const struct nk_style_item *background; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + style = &ctx->style; + s = nk_widget(&header, ctx); + if (s == NK_WIDGET_INVALID) + return 0; + + in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; + if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) + is_clicked = nk_true; + + /* draw combo box header background and border */ + if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) + background = &style->combo.active; + else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) + background = &style->combo.hover; + else background = &style->combo.normal; + + if (background->type == NK_STYLE_ITEM_IMAGE) { + nk_draw_image(&win->buffer, header, &background->data.image,nk_white); + } else { + nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); + nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); + } + { + struct nk_rect content; + struct nk_rect button; + struct nk_rect bounds; + + enum nk_symbol_type sym; + if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) + sym = style->combo.sym_hover; + else if (is_clicked) + sym = style->combo.sym_active; + else sym = style->combo.sym_normal; + + /* calculate button */ + button.w = header.h - 2 * style->combo.button_padding.y; + button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; + button.y = header.y + style->combo.button_padding.y; + button.h = button.w; + + content.x = button.x + style->combo.button.padding.x; + content.y = button.y + style->combo.button.padding.y; + content.w = button.w - 2 * style->combo.button.padding.x; + content.h = button.h - 2 * style->combo.button.padding.y; + + /* draw color */ + bounds.h = header.h - 4 * style->combo.content_padding.y; + bounds.y = header.y + 2 * style->combo.content_padding.y; + bounds.x = header.x + 2 * style->combo.content_padding.x; + bounds.w = (button.x - (style->combo.content_padding.x + style->combo.spacing.x)) - bounds.x; + nk_fill_rect(&win->buffer, bounds, 0, color); + + /* draw open/close button */ + nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, + &ctx->style.combo.button, sym, style->font); + } + return nk_combo_begin(ctx, win, size, is_clicked, header); +} + +NK_API int +nk_combo_begin_symbol(struct nk_context *ctx, enum nk_symbol_type symbol, struct nk_vec2 size) +{ + struct nk_window *win; + struct nk_style *style; + const struct nk_input *in; + + struct nk_rect header; + int is_clicked = nk_false; + enum nk_widget_layout_states s; + const struct nk_style_item *background; + struct nk_color sym_background; + struct nk_color symbol_color; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + style = &ctx->style; + s = nk_widget(&header, ctx); + if (s == NK_WIDGET_INVALID) + return 0; + + in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; + if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) + is_clicked = nk_true; + + /* draw combo box header background and border */ + if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { + background = &style->combo.active; + symbol_color = style->combo.symbol_active; + } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { + background = &style->combo.hover; + symbol_color = style->combo.symbol_hover; + } else { + background = &style->combo.normal; + symbol_color = style->combo.symbol_hover; + } + + if (background->type == NK_STYLE_ITEM_IMAGE) { + sym_background = nk_rgba(0,0,0,0); + nk_draw_image(&win->buffer, header, &background->data.image, nk_white); + } else { + sym_background = background->data.color; + nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); + nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); + } + { + struct nk_rect bounds = {0,0,0,0}; + struct nk_rect content; + struct nk_rect button; + + enum nk_symbol_type sym; + if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) + sym = style->combo.sym_hover; + else if (is_clicked) + sym = style->combo.sym_active; + else sym = style->combo.sym_normal; + + /* calculate button */ + button.w = header.h - 2 * style->combo.button_padding.y; + button.x = (header.x + header.w - header.h) - style->combo.button_padding.y; + button.y = header.y + style->combo.button_padding.y; + button.h = button.w; + + content.x = button.x + style->combo.button.padding.x; + content.y = button.y + style->combo.button.padding.y; + content.w = button.w - 2 * style->combo.button.padding.x; + content.h = button.h - 2 * style->combo.button.padding.y; + + /* draw symbol */ + bounds.h = header.h - 2 * style->combo.content_padding.y; + bounds.y = header.y + style->combo.content_padding.y; + bounds.x = header.x + style->combo.content_padding.x; + bounds.w = (button.x - style->combo.content_padding.y) - bounds.x; + nk_draw_symbol(&win->buffer, symbol, bounds, sym_background, symbol_color, + 1.0f, style->font); + + /* draw open/close button */ + nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state, + &ctx->style.combo.button, sym, style->font); + } + return nk_combo_begin(ctx, win, size, is_clicked, header); +} + +NK_API int +nk_combo_begin_symbol_text(struct nk_context *ctx, const char *selected, int len, + enum nk_symbol_type symbol, struct nk_vec2 size) +{ + struct nk_window *win; + struct nk_style *style; + struct nk_input *in; + + struct nk_rect header; + int is_clicked = nk_false; + enum nk_widget_layout_states s; + const struct nk_style_item *background; + struct nk_color symbol_color; + struct nk_text text; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + style = &ctx->style; + s = nk_widget(&header, ctx); + if (!s) return 0; + + in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; + if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) + is_clicked = nk_true; + + /* draw combo box header background and border */ + if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { + background = &style->combo.active; + symbol_color = style->combo.symbol_active; + text.text = style->combo.label_active; + } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { + background = &style->combo.hover; + symbol_color = style->combo.symbol_hover; + text.text = style->combo.label_hover; + } else { + background = &style->combo.normal; + symbol_color = style->combo.symbol_normal; + text.text = style->combo.label_normal; + } + if (background->type == NK_STYLE_ITEM_IMAGE) { + text.background = nk_rgba(0,0,0,0); + nk_draw_image(&win->buffer, header, &background->data.image, nk_white); + } else { + text.background = background->data.color; + nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); + nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); + } + { + struct nk_rect content; + struct nk_rect button; + struct nk_rect label; + struct nk_rect image; + + enum nk_symbol_type sym; + if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) + sym = style->combo.sym_hover; + else if (is_clicked) + sym = style->combo.sym_active; + else sym = style->combo.sym_normal; + + /* calculate button */ + button.w = header.h - 2 * style->combo.button_padding.y; + button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; + button.y = header.y + style->combo.button_padding.y; + button.h = button.w; + + content.x = button.x + style->combo.button.padding.x; + content.y = button.y + style->combo.button.padding.y; + content.w = button.w - 2 * style->combo.button.padding.x; + content.h = button.h - 2 * style->combo.button.padding.y; + nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, + &ctx->style.combo.button, sym, style->font); + + /* draw symbol */ + image.x = header.x + style->combo.content_padding.x; + image.y = header.y + style->combo.content_padding.y; + image.h = header.h - 2 * style->combo.content_padding.y; + image.w = image.h; + nk_draw_symbol(&win->buffer, symbol, image, text.background, symbol_color, + 1.0f, style->font); + + /* draw label */ + text.padding = nk_vec2(0,0); + label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x; + label.y = header.y + style->combo.content_padding.y; + label.w = (button.x - style->combo.content_padding.x) - label.x; + label.h = header.h - 2 * style->combo.content_padding.y; + nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font); + } + return nk_combo_begin(ctx, win, size, is_clicked, header); +} + +NK_API int +nk_combo_begin_image(struct nk_context *ctx, struct nk_image img, struct nk_vec2 size) +{ + struct nk_window *win; + struct nk_style *style; + const struct nk_input *in; + + struct nk_rect header; + int is_clicked = nk_false; + enum nk_widget_layout_states s; + const struct nk_style_item *background; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + style = &ctx->style; + s = nk_widget(&header, ctx); + if (s == NK_WIDGET_INVALID) + return 0; + + in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; + if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) + is_clicked = nk_true; + + /* draw combo box header background and border */ + if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) + background = &style->combo.active; + else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) + background = &style->combo.hover; + else background = &style->combo.normal; + + if (background->type == NK_STYLE_ITEM_IMAGE) { + nk_draw_image(&win->buffer, header, &background->data.image, nk_white); + } else { + nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); + nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); + } + { + struct nk_rect bounds = {0,0,0,0}; + struct nk_rect content; + struct nk_rect button; + + enum nk_symbol_type sym; + if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) + sym = style->combo.sym_hover; + else if (is_clicked) + sym = style->combo.sym_active; + else sym = style->combo.sym_normal; + + /* calculate button */ + button.w = header.h - 2 * style->combo.button_padding.y; + button.x = (header.x + header.w - header.h) - style->combo.button_padding.y; + button.y = header.y + style->combo.button_padding.y; + button.h = button.w; + + content.x = button.x + style->combo.button.padding.x; + content.y = button.y + style->combo.button.padding.y; + content.w = button.w - 2 * style->combo.button.padding.x; + content.h = button.h - 2 * style->combo.button.padding.y; + + /* draw image */ + bounds.h = header.h - 2 * style->combo.content_padding.y; + bounds.y = header.y + style->combo.content_padding.y; + bounds.x = header.x + style->combo.content_padding.x; + bounds.w = (button.x - style->combo.content_padding.y) - bounds.x; + nk_draw_image(&win->buffer, bounds, &img, nk_white); + + /* draw open/close button */ + nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state, + &ctx->style.combo.button, sym, style->font); + } + return nk_combo_begin(ctx, win, size, is_clicked, header); +} + +NK_API int +nk_combo_begin_image_text(struct nk_context *ctx, const char *selected, int len, + struct nk_image img, struct nk_vec2 size) +{ + struct nk_window *win; + struct nk_style *style; + struct nk_input *in; + + struct nk_rect header; + int is_clicked = nk_false; + enum nk_widget_layout_states s; + const struct nk_style_item *background; + struct nk_text text; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + style = &ctx->style; + s = nk_widget(&header, ctx); + if (!s) return 0; + + in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; + if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) + is_clicked = nk_true; + + /* draw combo box header background and border */ + if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { + background = &style->combo.active; + text.text = style->combo.label_active; + } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { + background = &style->combo.hover; + text.text = style->combo.label_hover; + } else { + background = &style->combo.normal; + text.text = style->combo.label_normal; + } + if (background->type == NK_STYLE_ITEM_IMAGE) { + text.background = nk_rgba(0,0,0,0); + nk_draw_image(&win->buffer, header, &background->data.image, nk_white); + } else { + text.background = background->data.color; + nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); + nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); + } + { + struct nk_rect content; + struct nk_rect button; + struct nk_rect label; + struct nk_rect image; + + enum nk_symbol_type sym; + if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) + sym = style->combo.sym_hover; + else if (is_clicked) + sym = style->combo.sym_active; + else sym = style->combo.sym_normal; + + /* calculate button */ + button.w = header.h - 2 * style->combo.button_padding.y; + button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; + button.y = header.y + style->combo.button_padding.y; + button.h = button.w; + + content.x = button.x + style->combo.button.padding.x; + content.y = button.y + style->combo.button.padding.y; + content.w = button.w - 2 * style->combo.button.padding.x; + content.h = button.h - 2 * style->combo.button.padding.y; + nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, + &ctx->style.combo.button, sym, style->font); + + /* draw image */ + image.x = header.x + style->combo.content_padding.x; + image.y = header.y + style->combo.content_padding.y; + image.h = header.h - 2 * style->combo.content_padding.y; + image.w = image.h; + nk_draw_image(&win->buffer, image, &img, nk_white); + + /* draw label */ + text.padding = nk_vec2(0,0); + label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x; + label.y = header.y + style->combo.content_padding.y; + label.w = (button.x - style->combo.content_padding.x) - label.x; + label.h = header.h - 2 * style->combo.content_padding.y; + nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font); + } + return nk_combo_begin(ctx, win, size, is_clicked, header); +} + +NK_API int nk_combo_begin_symbol_label(struct nk_context *ctx, + const char *selected, enum nk_symbol_type type, struct nk_vec2 size) +{return nk_combo_begin_symbol_text(ctx, selected, nk_strlen(selected), type, size);} + +NK_API int nk_combo_begin_image_label(struct nk_context *ctx, + const char *selected, struct nk_image img, struct nk_vec2 size) +{return nk_combo_begin_image_text(ctx, selected, nk_strlen(selected), img, size);} + +NK_API int nk_combo_item_text(struct nk_context *ctx, const char *text, int len,nk_flags align) +{return nk_contextual_item_text(ctx, text, len, align);} + +NK_API int nk_combo_item_label(struct nk_context *ctx, const char *label, nk_flags align) +{return nk_contextual_item_label(ctx, label, align);} + +NK_API int nk_combo_item_image_text(struct nk_context *ctx, struct nk_image img, const char *text, + int len, nk_flags alignment) +{return nk_contextual_item_image_text(ctx, img, text, len, alignment);} + +NK_API int nk_combo_item_image_label(struct nk_context *ctx, struct nk_image img, + const char *text, nk_flags alignment) +{return nk_contextual_item_image_label(ctx, img, text, alignment);} + +NK_API int nk_combo_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym, + const char *text, int len, nk_flags alignment) +{return nk_contextual_item_symbol_text(ctx, sym, text, len, alignment);} + +NK_API int nk_combo_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym, + const char *label, nk_flags alignment) +{return nk_contextual_item_symbol_label(ctx, sym, label, alignment);} + +NK_API void nk_combo_end(struct nk_context *ctx) +{nk_contextual_end(ctx);} + +NK_API void nk_combo_close(struct nk_context *ctx) +{nk_contextual_close(ctx);} + +NK_API int +nk_combo(struct nk_context *ctx, const char **items, int count, + int selected, int item_height, struct nk_vec2 size) +{ + int i = 0; + int max_height; + struct nk_vec2 item_spacing; + struct nk_vec2 window_padding; + + NK_ASSERT(ctx); + NK_ASSERT(items); + NK_ASSERT(ctx->current); + if (!ctx || !items ||!count) + return selected; + + item_spacing = ctx->style.window.spacing; + window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); + max_height = count * item_height + count * (int)item_spacing.y; + max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; + size.y = NK_MIN(size.y, (float)max_height); + if (nk_combo_begin_label(ctx, items[selected], size)) { + nk_layout_row_dynamic(ctx, (float)item_height, 1); + for (i = 0; i < count; ++i) { + if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT)) + selected = i; + } + nk_combo_end(ctx); + } + return selected; +} + +NK_API int +nk_combo_separator(struct nk_context *ctx, const char *items_separated_by_separator, + int separator, int selected, int count, int item_height, struct nk_vec2 size) +{ + int i; + int max_height; + struct nk_vec2 item_spacing; + struct nk_vec2 window_padding; + const char *current_item; + const char *iter; + int length = 0; + + NK_ASSERT(ctx); + NK_ASSERT(items_separated_by_separator); + if (!ctx || !items_separated_by_separator) + return selected; + + /* calculate popup window */ + item_spacing = ctx->style.window.spacing; + window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); + max_height = count * item_height + count * (int)item_spacing.y; + max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; + size.y = NK_MIN(size.y, (float)max_height); + + /* find selected item */ + current_item = items_separated_by_separator; + for (i = 0; i < count; ++i) { + iter = current_item; + while (*iter && *iter != separator) iter++; + length = (int)(iter - current_item); + if (i == selected) break; + current_item = iter + 1; + } + + if (nk_combo_begin_text(ctx, current_item, length, size)) { + current_item = items_separated_by_separator; + nk_layout_row_dynamic(ctx, (float)item_height, 1); + for (i = 0; i < count; ++i) { + iter = current_item; + while (*iter && *iter != separator) iter++; + length = (int)(iter - current_item); + if (nk_combo_item_text(ctx, current_item, length, NK_TEXT_LEFT)) + selected = i; + current_item = current_item + length + 1; + } + nk_combo_end(ctx); + } + return selected; +} + +NK_API int +nk_combo_string(struct nk_context *ctx, const char *items_separated_by_zeros, + int selected, int count, int item_height, struct nk_vec2 size) +{return nk_combo_separator(ctx, items_separated_by_zeros, '\0', selected, count, item_height, size);} + +NK_API int +nk_combo_callback(struct nk_context *ctx, void(*item_getter)(void*, int, const char**), + void *userdata, int selected, int count, int item_height, struct nk_vec2 size) +{ + int i; + int max_height; + struct nk_vec2 item_spacing; + struct nk_vec2 window_padding; + const char *item; + + NK_ASSERT(ctx); + NK_ASSERT(item_getter); + if (!ctx || !item_getter) + return selected; + + /* calculate popup window */ + item_spacing = ctx->style.window.spacing; + window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); + max_height = count * item_height + count * (int)item_spacing.y; + max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; + size.y = NK_MIN(size.y, (float)max_height); + + item_getter(userdata, selected, &item); + if (nk_combo_begin_label(ctx, item, size)) { + nk_layout_row_dynamic(ctx, (float)item_height, 1); + for (i = 0; i < count; ++i) { + item_getter(userdata, i, &item); + if (nk_combo_item_label(ctx, item, NK_TEXT_LEFT)) + selected = i; + } + nk_combo_end(ctx); + } + return selected; +} + +NK_API void nk_combobox(struct nk_context *ctx, const char **items, int count, + int *selected, int item_height, struct nk_vec2 size) +{*selected = nk_combo(ctx, items, count, *selected, item_height, size);} + +NK_API void nk_combobox_string(struct nk_context *ctx, const char *items_separated_by_zeros, + int *selected, int count, int item_height, struct nk_vec2 size) +{*selected = nk_combo_string(ctx, items_separated_by_zeros, *selected, count, item_height, size);} + +NK_API void nk_combobox_separator(struct nk_context *ctx, const char *items_separated_by_separator, + int separator,int *selected, int count, int item_height, struct nk_vec2 size) +{*selected = nk_combo_separator(ctx, items_separated_by_separator, separator, + *selected, count, item_height, size);} + +NK_API void nk_combobox_callback(struct nk_context *ctx, + void(*item_getter)(void* data, int id, const char **out_text), + void *userdata, int *selected, int count, int item_height, struct nk_vec2 size) +{*selected = nk_combo_callback(ctx, item_getter, userdata, *selected, count, item_height, size);} + +/* + * ------------------------------------------------------------- + * + * MENU + * + * -------------------------------------------------------------- + */ +NK_INTERN int +nk_menu_begin(struct nk_context *ctx, struct nk_window *win, + const char *id, int is_clicked, struct nk_rect header, struct nk_vec2 size) +{ + int is_open = 0; + int is_active = 0; + struct nk_rect body; + struct nk_window *popup; + nk_hash hash = nk_murmur_hash(id, (int)nk_strlen(id), NK_PANEL_MENU); + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + body.x = header.x; + body.w = size.x; + body.y = header.y + header.h; + body.h = size.y; + + popup = win->popup.win; + is_open = popup ? nk_true : nk_false; + is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU); + if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || + (!is_open && !is_active && !is_clicked)) return 0; + if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU)) + return 0; + + win->popup.type = NK_PANEL_MENU; + win->popup.name = hash; + return 1; +} + +NK_API int +nk_menu_begin_text(struct nk_context *ctx, const char *title, int len, + nk_flags align, struct nk_vec2 size) +{ + struct nk_window *win; + const struct nk_input *in; + struct nk_rect header; + int is_clicked = nk_false; + nk_flags state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + state = nk_widget(&header, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || win->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, header, + title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font)) + is_clicked = nk_true; + return nk_menu_begin(ctx, win, title, is_clicked, header, size); +} + +NK_API int nk_menu_begin_label(struct nk_context *ctx, + const char *text, nk_flags align, struct nk_vec2 size) +{return nk_menu_begin_text(ctx, text, nk_strlen(text), align, size);} + +NK_API int +nk_menu_begin_image(struct nk_context *ctx, const char *id, struct nk_image img, + struct nk_vec2 size) +{ + struct nk_window *win; + struct nk_rect header; + const struct nk_input *in; + int is_clicked = nk_false; + nk_flags state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + state = nk_widget(&header, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + if (nk_do_button_image(&ctx->last_widget_state, &win->buffer, header, + img, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in)) + is_clicked = nk_true; + return nk_menu_begin(ctx, win, id, is_clicked, header, size); +} + +NK_API int +nk_menu_begin_symbol(struct nk_context *ctx, const char *id, + enum nk_symbol_type sym, struct nk_vec2 size) +{ + struct nk_window *win; + const struct nk_input *in; + struct nk_rect header; + int is_clicked = nk_false; + nk_flags state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + state = nk_widget(&header, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + if (nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, header, + sym, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font)) + is_clicked = nk_true; + return nk_menu_begin(ctx, win, id, is_clicked, header, size); +} + +NK_API int +nk_menu_begin_image_text(struct nk_context *ctx, const char *title, int len, + nk_flags align, struct nk_image img, struct nk_vec2 size) +{ + struct nk_window *win; + struct nk_rect header; + const struct nk_input *in; + int is_clicked = nk_false; + nk_flags state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + state = nk_widget(&header, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, + header, img, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, + ctx->style.font, in)) + is_clicked = nk_true; + return nk_menu_begin(ctx, win, title, is_clicked, header, size); +} + +NK_API int nk_menu_begin_image_label(struct nk_context *ctx, + const char *title, nk_flags align, struct nk_image img, struct nk_vec2 size) +{return nk_menu_begin_image_text(ctx, title, nk_strlen(title), align, img, size);} + +NK_API int +nk_menu_begin_symbol_text(struct nk_context *ctx, const char *title, int len, + nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size) +{ + struct nk_window *win; + struct nk_rect header; + const struct nk_input *in; + int is_clicked = nk_false; + nk_flags state; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + state = nk_widget(&header, ctx); + if (!state) return 0; + + in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, + header, sym, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, + ctx->style.font, in)) is_clicked = nk_true; + return nk_menu_begin(ctx, win, title, is_clicked, header, size); +} + +NK_API int nk_menu_begin_symbol_label(struct nk_context *ctx, + const char *title, nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size ) +{return nk_menu_begin_symbol_text(ctx, title, nk_strlen(title), align,sym,size);} + +NK_API int nk_menu_item_text(struct nk_context *ctx, const char *title, int len, nk_flags align) +{return nk_contextual_item_text(ctx, title, len, align);} + +NK_API int nk_menu_item_label(struct nk_context *ctx, const char *label, nk_flags align) +{return nk_contextual_item_label(ctx, label, align);} + +NK_API int nk_menu_item_image_label(struct nk_context *ctx, struct nk_image img, + const char *label, nk_flags align) +{return nk_contextual_item_image_label(ctx, img, label, align);} + +NK_API int nk_menu_item_image_text(struct nk_context *ctx, struct nk_image img, + const char *text, int len, nk_flags align) +{return nk_contextual_item_image_text(ctx, img, text, len, align);} + +NK_API int nk_menu_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym, + const char *text, int len, nk_flags align) +{return nk_contextual_item_symbol_text(ctx, sym, text, len, align);} + +NK_API int nk_menu_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym, + const char *label, nk_flags align) +{return nk_contextual_item_symbol_label(ctx, sym, label, align);} + +NK_API void nk_menu_close(struct nk_context *ctx) +{nk_contextual_close(ctx);} + +NK_API void +nk_menu_end(struct nk_context *ctx) +{nk_contextual_end(ctx);} + +#endif diff --git a/src/external/glfw/deps/nuklear_glfw_gl2.h b/src/external/glfw/deps/nuklear_glfw_gl2.h new file mode 100644 index 00000000..965af5fe --- /dev/null +++ b/src/external/glfw/deps/nuklear_glfw_gl2.h @@ -0,0 +1,372 @@ +/* + * Nuklear - v1.32.0 - public domain + * no warrenty implied; use at your own risk. + * authored from 2015-2017 by Micha Mettke + */ +/* + * ============================================================== + * + * API + * + * =============================================================== + */ +#ifndef NK_GLFW_GL2_H_ +#define NK_GLFW_GL2_H_ + +#include + +enum nk_glfw_init_state{ + NK_GLFW3_DEFAULT = 0, + NK_GLFW3_INSTALL_CALLBACKS +}; +NK_API struct nk_context* nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state); +NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas); +NK_API void nk_glfw3_font_stash_end(void); + +NK_API void nk_glfw3_new_frame(void); +NK_API void nk_glfw3_render(enum nk_anti_aliasing); +NK_API void nk_glfw3_shutdown(void); + +NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint); +NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff); + +#endif + +/* + * ============================================================== + * + * IMPLEMENTATION + * + * =============================================================== + */ +#ifdef NK_GLFW_GL2_IMPLEMENTATION + +#ifndef NK_GLFW_TEXT_MAX +#define NK_GLFW_TEXT_MAX 256 +#endif +#ifndef NK_GLFW_DOUBLE_CLICK_LO +#define NK_GLFW_DOUBLE_CLICK_LO 0.02 +#endif +#ifndef NK_GLFW_DOUBLE_CLICK_HI +#define NK_GLFW_DOUBLE_CLICK_HI 0.2 +#endif + +struct nk_glfw_device { + struct nk_buffer cmds; + struct nk_draw_null_texture null; + GLuint font_tex; +}; + +struct nk_glfw_vertex { + float position[2]; + float uv[2]; + nk_byte col[4]; +}; + +static struct nk_glfw { + GLFWwindow *win; + int width, height; + int display_width, display_height; + struct nk_glfw_device ogl; + struct nk_context ctx; + struct nk_font_atlas atlas; + struct nk_vec2 fb_scale; + unsigned int text[NK_GLFW_TEXT_MAX]; + int text_len; + struct nk_vec2 scroll; + double last_button_click; +} glfw; + +NK_INTERN void +nk_glfw3_device_upload_atlas(const void *image, int width, int height) +{ + struct nk_glfw_device *dev = &glfw.ogl; + glGenTextures(1, &dev->font_tex); + glBindTexture(GL_TEXTURE_2D, dev->font_tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, image); +} + +NK_API void +nk_glfw3_render(enum nk_anti_aliasing AA) +{ + /* setup global state */ + struct nk_glfw_device *dev = &glfw.ogl; + glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_SCISSOR_TEST); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /* setup viewport/project */ + glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0.0f, glfw.width, glfw.height, 0.0f, -1.0f, 1.0f); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + { + GLsizei vs = sizeof(struct nk_glfw_vertex); + size_t vp = offsetof(struct nk_glfw_vertex, position); + size_t vt = offsetof(struct nk_glfw_vertex, uv); + size_t vc = offsetof(struct nk_glfw_vertex, col); + + /* convert from command queue into draw list and draw to screen */ + const struct nk_draw_command *cmd; + const nk_draw_index *offset = NULL; + struct nk_buffer vbuf, ebuf; + + /* fill convert configuration */ + struct nk_convert_config config; + static const struct nk_draw_vertex_layout_element vertex_layout[] = { + {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)}, + {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)}, + {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)}, + {NK_VERTEX_LAYOUT_END} + }; + NK_MEMSET(&config, 0, sizeof(config)); + config.vertex_layout = vertex_layout; + config.vertex_size = sizeof(struct nk_glfw_vertex); + config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex); + config.null = dev->null; + config.circle_segment_count = 22; + config.curve_segment_count = 22; + config.arc_segment_count = 22; + config.global_alpha = 1.0f; + config.shape_AA = AA; + config.line_AA = AA; + + /* convert shapes into vertexes */ + nk_buffer_init_default(&vbuf); + nk_buffer_init_default(&ebuf); + nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config); + + /* setup vertex buffer pointer */ + {const void *vertices = nk_buffer_memory_const(&vbuf); + glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp)); + glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt)); + glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));} + + /* iterate over and execute each draw command */ + offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf); + nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) + { + if (!cmd->elem_count) continue; + glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); + glScissor( + (GLint)(cmd->clip_rect.x * glfw.fb_scale.x), + (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y), + (GLint)(cmd->clip_rect.w * glfw.fb_scale.x), + (GLint)(cmd->clip_rect.h * glfw.fb_scale.y)); + glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); + offset += cmd->elem_count; + } + nk_clear(&glfw.ctx); + nk_buffer_free(&vbuf); + nk_buffer_free(&ebuf); + } + + /* default OpenGL state */ + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, 0); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glPopAttrib(); +} + +NK_API void +nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint) +{ + (void)win; + if (glfw.text_len < NK_GLFW_TEXT_MAX) + glfw.text[glfw.text_len++] = codepoint; +} + +NK_API void +nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff) +{ + (void)win; (void)xoff; + glfw.scroll.x += (float)xoff; + glfw.scroll.y += (float)yoff; +} + +NK_API void +nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + double x, y; + if (button != GLFW_MOUSE_BUTTON_LEFT) return; + glfwGetCursorPos(window, &x, &y); + if (action == GLFW_PRESS) { + double dt = glfwGetTime() - glfw.last_button_click; + if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) + nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_true); + glfw.last_button_click = glfwGetTime(); + } else nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_false); +} + +NK_INTERN void +nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) +{ + const char *text = glfwGetClipboardString(glfw.win); + if (text) nk_textedit_paste(edit, text, nk_strlen(text)); + (void)usr; +} + +NK_INTERN void +nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len) +{ + char *str = 0; + (void)usr; + if (!len) return; + str = (char*)malloc((size_t)len+1); + if (!str) return; + NK_MEMCPY(str, text, (size_t)len); + str[len] = '\0'; + glfwSetClipboardString(glfw.win, str); + free(str); +} + +NK_API struct nk_context* +nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state) +{ + glfw.win = win; + if (init_state == NK_GLFW3_INSTALL_CALLBACKS) { + glfwSetScrollCallback(win, nk_gflw3_scroll_callback); + glfwSetCharCallback(win, nk_glfw3_char_callback); + glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback); + } + nk_init_default(&glfw.ctx, 0); + glfw.ctx.clip.copy = nk_glfw3_clipbard_copy; + glfw.ctx.clip.paste = nk_glfw3_clipbard_paste; + glfw.ctx.clip.userdata = nk_handle_ptr(0); + nk_buffer_init_default(&glfw.ogl.cmds); + return &glfw.ctx; +} + +NK_API void +nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas) +{ + nk_font_atlas_init_default(&glfw.atlas); + nk_font_atlas_begin(&glfw.atlas); + *atlas = &glfw.atlas; +} + +NK_API void +nk_glfw3_font_stash_end(void) +{ + const void *image; int w, h; + image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); + nk_glfw3_device_upload_atlas(image, w, h); + nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null); + if (glfw.atlas.default_font) + nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle); +} + +NK_API void +nk_glfw3_new_frame(void) +{ + int i; + double x, y; + struct nk_context *ctx = &glfw.ctx; + struct GLFWwindow *win = glfw.win; + + glfwGetWindowSize(win, &glfw.width, &glfw.height); + glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height); + glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width; + glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height; + + nk_input_begin(ctx); + for (i = 0; i < glfw.text_len; ++i) + nk_input_unicode(ctx, glfw.text[i]); + + /* optional grabbing behavior */ + if (ctx->input.mouse.grab) + glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + else if (ctx->input.mouse.ungrab) + glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + + nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS|| + glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS); + + if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || + glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) { + nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_V) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); + } else { + nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); + nk_input_key(ctx, NK_KEY_COPY, 0); + nk_input_key(ctx, NK_KEY_PASTE, 0); + nk_input_key(ctx, NK_KEY_CUT, 0); + nk_input_key(ctx, NK_KEY_SHIFT, 0); + } + + glfwGetCursorPos(win, &x, &y); + nk_input_motion(ctx, (int)x, (int)y); + if (ctx->input.mouse.grabbed) { + glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y); + ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; + ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; + } + + nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); + nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); + nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); + nk_input_scroll(ctx, glfw.scroll); + nk_input_end(&glfw.ctx); + glfw.text_len = 0; + glfw.scroll = nk_vec2(0,0); +} + +NK_API +void nk_glfw3_shutdown(void) +{ + struct nk_glfw_device *dev = &glfw.ogl; + nk_font_atlas_clear(&glfw.atlas); + nk_free(&glfw.ctx); + glDeleteTextures(1, &dev->font_tex); + nk_buffer_free(&dev->cmds); + NK_MEMSET(&glfw, 0, sizeof(glfw)); +} + +#endif diff --git a/src/external/glfw/deps/stb_image_write.h b/src/external/glfw/deps/stb_image_write.h new file mode 100644 index 00000000..4319c0de --- /dev/null +++ b/src/external/glfw/deps/stb_image_write.h @@ -0,0 +1,1048 @@ +/* stb_image_write - v1.02 - public domain - http://nothings.org/stb/stb_image_write.h + writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + + Before #including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + + in the file that you want to have the implementation. + + Will probably not work correctly with strict-aliasing optimizations. + +ABOUT: + + This header file is a library for writing images to C stdio. It could be + adapted to write to memory or a general streaming interface; let me know. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation. This library is designed + for source code compactness and simplicity, not optimal image file size + or run-time performance. + +BUILDING: + + You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. + You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace + malloc,realloc,free. + You can define STBIW_MEMMOVE() to replace memmove() + +USAGE: + + There are four functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + + There are also four equivalent functions that use an arbitrary write function. You are + expected to open/close your file-equivalent before and after calling these: + + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + + where the callback is: + void stbi_write_func(void *context, void *data, int size); + + You can define STBI_WRITE_NO_STDIO to disable the file variant of these + functions, so the library will not use stdio.h at all. However, this will + also disable HDR writing, because it requires stdio for formatted output. + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP format expands Y to RGB in the file format and does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) + + HDR expects linear float data. Since the format is always 32-bit rgb(e) + data, alpha (if provided) is discarded, and for monochrome data it is + replicated across all three channels. + + TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed + data, set the global variable 'stbi_write_tga_with_rle' to 0. + +CREDITS: + + PNG/BMP/TGA + Sean Barrett + HDR + Baldur Karlsson + TGA monochrome: + Jean-Sebastien Guay + misc enhancements: + Tim Kelsey + TGA RLE + Alan Hickman + initial file IO callback implementation + Emmanuel Julien + bugfixes: + github:Chribba + Guillaume Chereau + github:jry2 + github:romigrou + Sergio Gonzalez + Jonas Karlsson + Filip Wasil + Thatcher Ulrich + +LICENSE + +This software is dual-licensed to the public domain and under the following +license: you are granted a perpetual, irrevocable license to copy, modify, +publish, and distribute this file as you see fit. + +*/ + +#ifndef INCLUDE_STB_IMAGE_WRITE_H +#define INCLUDE_STB_IMAGE_WRITE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STB_IMAGE_WRITE_STATIC +#define STBIWDEF static +#else +#define STBIWDEF extern +extern int stbi_write_tga_with_rle; +#endif + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); +#endif + +typedef void stbi_write_func(void *context, void *data, int size); + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + +#ifdef __cplusplus +} +#endif + +#endif//INCLUDE_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif + #ifndef _CRT_NONSTDC_NO_DEPRECATE + #define _CRT_NONSTDC_NO_DEPRECATE + #endif +#endif + +#ifndef STBI_WRITE_NO_STDIO +#include +#endif // STBI_WRITE_NO_STDIO + +#include +#include +#include +#include + +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) +// ok +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." +#endif + +#ifndef STBIW_MALLOC +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_FREE(p) free(p) +#endif + +#ifndef STBIW_REALLOC_SIZED +#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#endif + + +#ifndef STBIW_MEMMOVE +#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#endif + + +#ifndef STBIW_ASSERT +#include +#define STBIW_ASSERT(x) assert(x) +#endif + +#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) + +typedef struct +{ + stbi_write_func *func; + void *context; +} stbi__write_context; + +// initialize a callback-based context +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) +{ + s->func = c; + s->context = context; +} + +#ifndef STBI_WRITE_NO_STDIO + +static void stbi__stdio_write(void *context, void *data, int size) +{ + fwrite(data,1,size,(FILE*) context); +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); + return f != NULL; +} + +static void stbi__end_write_file(stbi__write_context *s) +{ + fclose((FILE *)s->context); +} + +#endif // !STBI_WRITE_NO_STDIO + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_tga_with_rle = 1; +#else +int stbi_write_tga_with_rle = 1; +#endif + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context,&x,1); + break; } + case '2': { int x = va_arg(v,int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x>>8); + s->func(s->context,b,2); + break; } + case '4': { stbiw_uint32 x = va_arg(v,int); + unsigned char b[4]; + b[0]=STBIW_UCHAR(x); + b[1]=STBIW_UCHAR(x>>8); + b[2]=STBIW_UCHAR(x>>16); + b[3]=STBIW_UCHAR(x>>24); + s->func(s->context,b,4); + break; } + default: + STBIW_ASSERT(0); + return; + } + } +} + +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) +{ + unsigned char arr[3]; + arr[0] = a, arr[1] = b, arr[2] = c; + s->func(s->context, arr, 3); +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + s->func(s->context, &d[comp - 1], 1); + + switch (comp) { + case 1: + s->func(s->context,d,1); + break; + case 2: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + s->func(s->context, d, 1); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + s->func(s->context, &d[comp - 1], 1); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ + stbiw_uint32 zero = 0; + int i,j, j_end; + + if (y <= 0) + return; + + if (vdir < 0) + j_end = -1, j = y-1; + else + j_end = y, j = 0; + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) +{ + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) +{ + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif //!STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) +{ + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp-1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i,j,k; + + stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + + for (j = y - 1; j >= 0; --j) { + unsigned char *row = (unsigned char *) data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + s->func(s->context, &header, 1); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + s->func(s->context, &header, 1); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } + } + return 1; +} + +int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR writer +// by Baldur Karlsson +#ifndef STBI_WRITE_NO_STDIO + +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + +void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +{ + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); + + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } +} + +void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +{ + unsigned char lengthbyte = STBIW_UCHAR(length+128); + STBIW_ASSERT(length+128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); +} + +void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +{ + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); +} + +void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +{ + unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; + unsigned char rgbe[4]; + float linear[3]; + int x; + + scanlineheader[2] = (width&0xff00)>>8; + scanlineheader[3] = (width&0x00ff); + + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x=0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c,r; + /* encode into scratch buffer */ + for (x=0; x < width; x++) { + switch(ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width*0] = rgbe[0]; + scratch[x + width*1] = rgbe[1]; + scratch[x + width*2] = rgbe[2]; + scratch[x + width*3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c=0; c < 4; c++) { + unsigned char *comp = &scratch[width*c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r+2 < width) { + if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) + break; + ++r; + } + if (r+2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r-x; + if (len > 128) len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r-x; + if (len > 127) len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } + } + } + } +} + +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) +{ + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + s->func(s->context, buffer, len); + + for(i=0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x); + STBIW_FREE(scratch); + return 1; + } +} + +int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +} + +int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif // STBI_WRITE_NO_STDIO + + +////////////////////////////////////////////////////////////////////////////// +// +// PNG writer +// + +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() +#define stbiw__sbraw(a) ((int *) (a) - 2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] + +#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) +#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbiw__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbiw__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +// default huffman tables +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) +#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) + +#define stbiw__ZHASH 16384 + +unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ + static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; + static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; + static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; + static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); + if (quality < 5) quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1,1); // BFINAL = 1 + stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) best=d,bestloc=hlist[j]; + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int) (data+i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbiw__zlib_huff(j+257); + if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); + if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0,1); + + for (i=0; i < stbiw__ZHASH; ++i) + (void) stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + + { + // compute adler32 on input + unsigned int s1=1, s2=0; + int blocklen = (int) (data_len % 5552); + j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; + s1 %= 65521, s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *) stbiw__sbraw(out); +} + +static unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ + static unsigned int crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + int i; + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); + if (pb <= pc) return STBIW_UCHAR(b); + return STBIW_UCHAR(c); +} + +unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int i,j,k,p,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = j ? mapping : firstmap; + int best = 0, bestval = 0x7fffffff; + for (p=0; p < 2; ++p) { + for (k= p?best:0; k < 5; ++k) { + int type = mymap[k],est=0; + unsigned char *z = pixels + stride_bytes*j; + for (i=0; i < n; ++i) + switch (type) { + case 0: line_buffer[i] = z[i]; break; + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; + case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + for (i=n; i < x*n; ++i) { + switch (type) { + case 0: line_buffer[i] = z[i]; break; + case 1: line_buffer[i] = z[i] - z[i-n]; break; + case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; + case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break; + case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break; + case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } + } + if (p) break; + for (i=0; i < x*n; ++i) + est += abs((signed char) line_buffer[i]); + if (est < bestval) { bestval = est; best = k; } + } + } + // when we get here, best contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) best; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + f = fopen(filename, "wb"); + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.02 (2016-04-02) + avoid allocating large structures on the stack + 1.01 (2016-01-16) + STBIW_REALLOC_SIZED: support allocators with no realloc support + avoid race-condition in crc initialization + minor compile issues + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ diff --git a/src/external/glfw/deps/tinycthread.c b/src/external/glfw/deps/tinycthread.c new file mode 100644 index 00000000..f9cea2ed --- /dev/null +++ b/src/external/glfw/deps/tinycthread.c @@ -0,0 +1,594 @@ +/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- +Copyright (c) 2012 Marcus Geelnard + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +/* 2013-01-06 Camilla Löwy + * + * Added casts from time_t to DWORD to avoid warnings on VC++. + * Fixed time retrieval on POSIX systems. + */ + +#include "tinycthread.h" +#include + +/* Platform specific includes */ +#if defined(_TTHREAD_POSIX_) + #include + #include + #include + #include + #include +#elif defined(_TTHREAD_WIN32_) + #include + #include +#endif + +/* Standard, good-to-have defines */ +#ifndef NULL + #define NULL (void*)0 +#endif +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +int mtx_init(mtx_t *mtx, int type) +{ +#if defined(_TTHREAD_WIN32_) + mtx->mAlreadyLocked = FALSE; + mtx->mRecursive = type & mtx_recursive; + InitializeCriticalSection(&mtx->mHandle); + return thrd_success; +#else + int ret; + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + if (type & mtx_recursive) + { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + ret = pthread_mutex_init(mtx, &attr); + pthread_mutexattr_destroy(&attr); + return ret == 0 ? thrd_success : thrd_error; +#endif +} + +void mtx_destroy(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + DeleteCriticalSection(&mtx->mHandle); +#else + pthread_mutex_destroy(mtx); +#endif +} + +int mtx_lock(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + EnterCriticalSection(&mtx->mHandle); + if (!mtx->mRecursive) + { + while(mtx->mAlreadyLocked) Sleep(1000); /* Simulate deadlock... */ + mtx->mAlreadyLocked = TRUE; + } + return thrd_success; +#else + return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; +#endif +} + +int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + /* FIXME! */ + (void)mtx; + (void)ts; + return thrd_error; +} + +int mtx_trylock(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; + if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) + { + LeaveCriticalSection(&mtx->mHandle); + ret = thrd_busy; + } + return ret; +#else + return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; +#endif +} + +int mtx_unlock(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + mtx->mAlreadyLocked = FALSE; + LeaveCriticalSection(&mtx->mHandle); + return thrd_success; +#else + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;; +#endif +} + +#if defined(_TTHREAD_WIN32_) +#define _CONDITION_EVENT_ONE 0 +#define _CONDITION_EVENT_ALL 1 +#endif + +int cnd_init(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + cond->mWaitersCount = 0; + + /* Init critical section */ + InitializeCriticalSection(&cond->mWaitersCountLock); + + /* Init events */ + cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) + { + cond->mEvents[_CONDITION_EVENT_ALL] = NULL; + return thrd_error; + } + cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) + { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + cond->mEvents[_CONDITION_EVENT_ONE] = NULL; + return thrd_error; + } + + return thrd_success; +#else + return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; +#endif +} + +void cnd_destroy(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) + { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + } + if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) + { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); + } + DeleteCriticalSection(&cond->mWaitersCountLock); +#else + pthread_cond_destroy(cond); +#endif +} + +int cnd_signal(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + int haveWaiters; + + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we have any waiting threads, send them a signal */ + if(haveWaiters) + { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) + { + return thrd_error; + } + } + + return thrd_success; +#else + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +#endif +} + +int cnd_broadcast(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + int haveWaiters; + + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we have any waiting threads, send them a signal */ + if(haveWaiters) + { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) + { + return thrd_error; + } + } + + return thrd_success; +#else + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +#endif +} + +#if defined(_TTHREAD_WIN32_) +static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) +{ + int result, lastWaiter; + + /* Increment number of waiters */ + EnterCriticalSection(&cond->mWaitersCountLock); + ++ cond->mWaitersCount; + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* Release the mutex while waiting for the condition (will decrease + the number of waiters when done)... */ + mtx_unlock(mtx); + + /* Wait for either event to become signaled due to cnd_signal() or + cnd_broadcast() being called */ + result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); + if (result == WAIT_TIMEOUT) + { + return thrd_timeout; + } + else if (result == (int)WAIT_FAILED) + { + return thrd_error; + } + + /* Check if we are the last waiter */ + EnterCriticalSection(&cond->mWaitersCountLock); + -- cond->mWaitersCount; + lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && + (cond->mWaitersCount == 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we are the last waiter to be notified to stop waiting, reset the event */ + if (lastWaiter) + { + if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) + { + return thrd_error; + } + } + + /* Re-acquire the mutex */ + mtx_lock(mtx); + + return thrd_success; +} +#endif + +int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + return _cnd_timedwait_win32(cond, mtx, INFINITE); +#else + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; +#endif +} + +int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ +#if defined(_TTHREAD_WIN32_) + struct timespec now; + if (clock_gettime(CLOCK_REALTIME, &now) == 0) + { + DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 + + (ts->tv_nsec - now.tv_nsec + 500000) / 1000000); + return _cnd_timedwait_win32(cond, mtx, delta); + } + else + return thrd_error; +#else + int ret; + ret = pthread_cond_timedwait(cond, mtx, ts); + if (ret == ETIMEDOUT) + { + return thrd_timeout; + } + return ret == 0 ? thrd_success : thrd_error; +#endif +} + + +/** Information to pass to the new thread (what to run). */ +typedef struct { + thrd_start_t mFunction; /**< Pointer to the function to be executed. */ + void * mArg; /**< Function argument for the thread function. */ +} _thread_start_info; + +/* Thread wrapper function. */ +#if defined(_TTHREAD_WIN32_) +static unsigned WINAPI _thrd_wrapper_function(void * aArg) +#elif defined(_TTHREAD_POSIX_) +static void * _thrd_wrapper_function(void * aArg) +#endif +{ + thrd_start_t fun; + void *arg; + int res; +#if defined(_TTHREAD_POSIX_) + void *pres; +#endif + + /* Get thread startup information */ + _thread_start_info *ti = (_thread_start_info *) aArg; + fun = ti->mFunction; + arg = ti->mArg; + + /* The thread is responsible for freeing the startup information */ + free((void *)ti); + + /* Call the actual client thread function */ + res = fun(arg); + +#if defined(_TTHREAD_WIN32_) + return res; +#else + pres = malloc(sizeof(int)); + if (pres != NULL) + { + *(int*)pres = res; + } + return pres; +#endif +} + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + /* Fill out the thread startup information (passed to the thread wrapper, + which will eventually free it) */ + _thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info)); + if (ti == NULL) + { + return thrd_nomem; + } + ti->mFunction = func; + ti->mArg = arg; + + /* Create the thread */ +#if defined(_TTHREAD_WIN32_) + *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); +#elif defined(_TTHREAD_POSIX_) + if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) + { + *thr = 0; + } +#endif + + /* Did we fail to create the thread? */ + if(!*thr) + { + free(ti); + return thrd_error; + } + + return thrd_success; +} + +thrd_t thrd_current(void) +{ +#if defined(_TTHREAD_WIN32_) + return GetCurrentThread(); +#else + return pthread_self(); +#endif +} + +int thrd_detach(thrd_t thr) +{ + /* FIXME! */ + (void)thr; + return thrd_error; +} + +int thrd_equal(thrd_t thr0, thrd_t thr1) +{ +#if defined(_TTHREAD_WIN32_) + return thr0 == thr1; +#else + return pthread_equal(thr0, thr1); +#endif +} + +void thrd_exit(int res) +{ +#if defined(_TTHREAD_WIN32_) + ExitThread(res); +#else + void *pres = malloc(sizeof(int)); + if (pres != NULL) + { + *(int*)pres = res; + } + pthread_exit(pres); +#endif +} + +int thrd_join(thrd_t thr, int *res) +{ +#if defined(_TTHREAD_WIN32_) + if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) + { + return thrd_error; + } + if (res != NULL) + { + DWORD dwRes; + GetExitCodeThread(thr, &dwRes); + *res = dwRes; + } +#elif defined(_TTHREAD_POSIX_) + void *pres; + int ires = 0; + if (pthread_join(thr, &pres) != 0) + { + return thrd_error; + } + if (pres != NULL) + { + ires = *(int*)pres; + free(pres); + } + if (res != NULL) + { + *res = ires; + } +#endif + return thrd_success; +} + +int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) +{ + struct timespec now; +#if defined(_TTHREAD_WIN32_) + DWORD delta; +#else + long delta; +#endif + + /* Get the current time */ + if (clock_gettime(CLOCK_REALTIME, &now) != 0) + return -2; // FIXME: Some specific error code? + +#if defined(_TTHREAD_WIN32_) + /* Delta in milliseconds */ + delta = (DWORD) ((time_point->tv_sec - now.tv_sec) * 1000 + + (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); + if (delta > 0) + { + Sleep(delta); + } +#else + /* Delta in microseconds */ + delta = (time_point->tv_sec - now.tv_sec) * 1000000L + + (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; + + /* On some systems, the usleep argument must be < 1000000 */ + while (delta > 999999L) + { + usleep(999999); + delta -= 999999L; + } + if (delta > 0L) + { + usleep((useconds_t)delta); + } +#endif + + /* We don't support waking up prematurely (yet) */ + if (remaining) + { + remaining->tv_sec = 0; + remaining->tv_nsec = 0; + } + return 0; +} + +void thrd_yield(void) +{ +#if defined(_TTHREAD_WIN32_) + Sleep(0); +#else + sched_yield(); +#endif +} + +int tss_create(tss_t *key, tss_dtor_t dtor) +{ +#if defined(_TTHREAD_WIN32_) + /* FIXME: The destructor function is not supported yet... */ + if (dtor != NULL) + { + return thrd_error; + } + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) + { + return thrd_error; + } +#else + if (pthread_key_create(key, dtor) != 0) + { + return thrd_error; + } +#endif + return thrd_success; +} + +void tss_delete(tss_t key) +{ +#if defined(_TTHREAD_WIN32_) + TlsFree(key); +#else + pthread_key_delete(key); +#endif +} + +void *tss_get(tss_t key) +{ +#if defined(_TTHREAD_WIN32_) + return TlsGetValue(key); +#else + return pthread_getspecific(key); +#endif +} + +int tss_set(tss_t key, void *val) +{ +#if defined(_TTHREAD_WIN32_) + if (TlsSetValue(key, val) == 0) + { + return thrd_error; + } +#else + if (pthread_setspecific(key, val) != 0) + { + return thrd_error; + } +#endif + return thrd_success; +} + +#if defined(_TTHREAD_EMULATE_CLOCK_GETTIME_) +int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) +{ +#if defined(_TTHREAD_WIN32_) + struct _timeb tb; + _ftime(&tb); + ts->tv_sec = (time_t)tb.time; + ts->tv_nsec = 1000000L * (long)tb.millitm; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + ts->tv_sec = (time_t)tv.tv_sec; + ts->tv_nsec = 1000L * (long)tv.tv_usec; +#endif + return 0; +} +#endif // _TTHREAD_EMULATE_CLOCK_GETTIME_ + diff --git a/src/external/glfw/deps/tinycthread.h b/src/external/glfw/deps/tinycthread.h new file mode 100644 index 00000000..42958c39 --- /dev/null +++ b/src/external/glfw/deps/tinycthread.h @@ -0,0 +1,443 @@ +/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- +Copyright (c) 2012 Marcus Geelnard + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef _TINYCTHREAD_H_ +#define _TINYCTHREAD_H_ + +/** +* @file +* @mainpage TinyCThread API Reference +* +* @section intro_sec Introduction +* TinyCThread is a minimal, portable implementation of basic threading +* classes for C. +* +* They closely mimic the functionality and naming of the C11 standard, and +* should be easily replaceable with the corresponding standard variants. +* +* @section port_sec Portability +* The Win32 variant uses the native Win32 API for implementing the thread +* classes, while for other systems, the POSIX threads API (pthread) is used. +* +* @section misc_sec Miscellaneous +* The following special keywords are available: #_Thread_local. +* +* For more detailed information, browse the different sections of this +* documentation. A good place to start is: +* tinycthread.h. +*/ + +/* Which platform are we on? */ +#if !defined(_TTHREAD_PLATFORM_DEFINED_) + #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) + #define _TTHREAD_WIN32_ + #else + #define _TTHREAD_POSIX_ + #endif + #define _TTHREAD_PLATFORM_DEFINED_ +#endif + +/* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ +#if defined(_TTHREAD_POSIX_) + #undef _FEATURES_H + #if !defined(_GNU_SOURCE) + #define _GNU_SOURCE + #endif + #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) + #undef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309L + #endif + #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) + #undef _XOPEN_SOURCE + #define _XOPEN_SOURCE 500 + #endif +#endif + +/* Generic includes */ +#include + +/* Platform specific includes */ +#if defined(_TTHREAD_POSIX_) + #include + #include +#elif defined(_TTHREAD_WIN32_) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #define __UNDEF_LEAN_AND_MEAN + #endif + #include + #ifdef __UNDEF_LEAN_AND_MEAN + #undef WIN32_LEAN_AND_MEAN + #undef __UNDEF_LEAN_AND_MEAN + #endif +#endif + +/* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC, + it's quite likely that libc does not support it either. Hence, fall back to + the only other supported time specifier: CLOCK_REALTIME (and if that fails, + we're probably emulating clock_gettime anyway, so anything goes). */ +#ifndef TIME_UTC + #ifdef CLOCK_REALTIME + #define TIME_UTC CLOCK_REALTIME + #else + #define TIME_UTC 0 + #endif +#endif + +/* Workaround for missing clock_gettime (most Windows compilers, afaik) */ +#if defined(_TTHREAD_WIN32_) || defined(__APPLE_CC__) +#define _TTHREAD_EMULATE_CLOCK_GETTIME_ +/* Emulate struct timespec */ +#if defined(_TTHREAD_WIN32_) +struct _ttherad_timespec { + time_t tv_sec; + long tv_nsec; +}; +#define timespec _ttherad_timespec +#endif + +/* Emulate clockid_t */ +typedef int _tthread_clockid_t; +#define clockid_t _tthread_clockid_t + +/* Emulate clock_gettime */ +int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); +#define clock_gettime _tthread_clock_gettime +#ifndef CLOCK_REALTIME + #define CLOCK_REALTIME 0 +#endif +#endif + + +/** TinyCThread version (major number). */ +#define TINYCTHREAD_VERSION_MAJOR 1 +/** TinyCThread version (minor number). */ +#define TINYCTHREAD_VERSION_MINOR 1 +/** TinyCThread version (full version). */ +#define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) + +/** +* @def _Thread_local +* Thread local storage keyword. +* A variable that is declared with the @c _Thread_local keyword makes the +* value of the variable local to each thread (known as thread-local storage, +* or TLS). Example usage: +* @code +* // This variable is local to each thread. +* _Thread_local int variable; +* @endcode +* @note The @c _Thread_local keyword is a macro that maps to the corresponding +* compiler directive (e.g. @c __declspec(thread)). +* @note This directive is currently not supported on Mac OS X (it will give +* a compiler error), since compile-time TLS is not supported in the Mac OS X +* executable format. Also, some older versions of MinGW (before GCC 4.x) do +* not support this directive. +* @hideinitializer +*/ + +/* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */ +#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) + #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) + #define _Thread_local __thread + #else + #define _Thread_local __declspec(thread) + #endif +#endif + +/* Macros */ +#define TSS_DTOR_ITERATIONS 0 + +/* Function return values */ +#define thrd_error 0 /**< The requested operation failed */ +#define thrd_success 1 /**< The requested operation succeeded */ +#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ +#define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ +#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ + +/* Mutex types */ +#define mtx_plain 1 +#define mtx_timed 2 +#define mtx_try 4 +#define mtx_recursive 8 + +/* Mutex */ +#if defined(_TTHREAD_WIN32_) +typedef struct { + CRITICAL_SECTION mHandle; /* Critical section handle */ + int mAlreadyLocked; /* TRUE if the mutex is already locked */ + int mRecursive; /* TRUE if the mutex is recursive */ +} mtx_t; +#else +typedef pthread_mutex_t mtx_t; +#endif + +/** Create a mutex object. +* @param mtx A mutex object. +* @param type Bit-mask that must have one of the following six values: +* @li @c mtx_plain for a simple non-recursive mutex +* @li @c mtx_timed for a non-recursive mutex that supports timeout +* @li @c mtx_try for a non-recursive mutex that supports test and return +* @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) +* @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) +* @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int mtx_init(mtx_t *mtx, int type); + +/** Release any resources used by the given mutex. +* @param mtx A mutex object. +*/ +void mtx_destroy(mtx_t *mtx); + +/** Lock the given mutex. +* Blocks until the given mutex can be locked. If the mutex is non-recursive, and +* the calling thread already has a lock on the mutex, this call will block +* forever. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int mtx_lock(mtx_t *mtx); + +/** NOT YET IMPLEMENTED. +*/ +int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); + +/** Try to lock the given mutex. +* The specified mutex shall support either test and return or timeout. If the +* mutex is already locked, the function returns without blocking. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_busy if the resource +* requested is already in use, or @ref thrd_error if the request could not be +* honored. +*/ +int mtx_trylock(mtx_t *mtx); + +/** Unlock the given mutex. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int mtx_unlock(mtx_t *mtx); + +/* Condition variable */ +#if defined(_TTHREAD_WIN32_) +typedef struct { + HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ + unsigned int mWaitersCount; /* Count of the number of waiters. */ + CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ +} cnd_t; +#else +typedef pthread_cond_t cnd_t; +#endif + +/** Create a condition variable object. +* @param cond A condition variable object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_init(cnd_t *cond); + +/** Release any resources used by the given condition variable. +* @param cond A condition variable object. +*/ +void cnd_destroy(cnd_t *cond); + +/** Signal a condition variable. +* Unblocks one of the threads that are blocked on the given condition variable +* at the time of the call. If no threads are blocked on the condition variable +* at the time of the call, the function does nothing and return success. +* @param cond A condition variable object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_signal(cnd_t *cond); + +/** Broadcast a condition variable. +* Unblocks all of the threads that are blocked on the given condition variable +* at the time of the call. If no threads are blocked on the condition variable +* at the time of the call, the function does nothing and return success. +* @param cond A condition variable object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_broadcast(cnd_t *cond); + +/** Wait for a condition variable to become signaled. +* The function atomically unlocks the given mutex and endeavors to block until +* the given condition variable is signaled by a call to cnd_signal or to +* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex +* before it returns. +* @param cond A condition variable object. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_wait(cnd_t *cond, mtx_t *mtx); + +/** Wait for a condition variable to become signaled. +* The function atomically unlocks the given mutex and endeavors to block until +* the given condition variable is signaled by a call to cnd_signal or to +* cnd_broadcast, or until after the specified time. When the calling thread +* becomes unblocked it locks the mutex before it returns. +* @param cond A condition variable object. +* @param mtx A mutex object. +* @param xt A point in time at which the request will time out (absolute time). +* @return @ref thrd_success upon success, or @ref thrd_timeout if the time +* specified in the call was reached without acquiring the requested resource, or +* @ref thrd_error if the request could not be honored. +*/ +int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); + +/* Thread */ +#if defined(_TTHREAD_WIN32_) +typedef HANDLE thrd_t; +#else +typedef pthread_t thrd_t; +#endif + +/** Thread start function. +* Any thread that is started with the @ref thrd_create() function must be +* started through a function of this type. +* @param arg The thread argument (the @c arg argument of the corresponding +* @ref thrd_create() call). +* @return The thread return value, which can be obtained by another thread +* by using the @ref thrd_join() function. +*/ +typedef int (*thrd_start_t)(void *arg); + +/** Create a new thread. +* @param thr Identifier of the newly created thread. +* @param func A function pointer to the function that will be executed in +* the new thread. +* @param arg An argument to the thread function. +* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could +* be allocated for the thread requested, or @ref thrd_error if the request +* could not be honored. +* @note A thread’s identifier may be reused for a different thread once the +* original thread has exited and either been detached or joined to another +* thread. +*/ +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); + +/** Identify the calling thread. +* @return The identifier of the calling thread. +*/ +thrd_t thrd_current(void); + +/** NOT YET IMPLEMENTED. +*/ +int thrd_detach(thrd_t thr); + +/** Compare two thread identifiers. +* The function determines if two thread identifiers refer to the same thread. +* @return Zero if the two thread identifiers refer to different threads. +* Otherwise a nonzero value is returned. +*/ +int thrd_equal(thrd_t thr0, thrd_t thr1); + +/** Terminate execution of the calling thread. +* @param res Result code of the calling thread. +*/ +void thrd_exit(int res); + +/** Wait for a thread to terminate. +* The function joins the given thread with the current thread by blocking +* until the other thread has terminated. +* @param thr The thread to join with. +* @param res If this pointer is not NULL, the function will store the result +* code of the given thread in the integer pointed to by @c res. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int thrd_join(thrd_t thr, int *res); + +/** Put the calling thread to sleep. +* Suspend execution of the calling thread. +* @param time_point A point in time at which the thread will resume (absolute time). +* @param remaining If non-NULL, this parameter will hold the remaining time until +* time_point upon return. This will typically be zero, but if +* the thread was woken up by a signal that is not ignored before +* time_point was reached @c remaining will hold a positive +* time. +* @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. +*/ +int thrd_sleep(const struct timespec *time_point, struct timespec *remaining); + +/** Yield execution to another thread. +* Permit other threads to run, even if the current thread would ordinarily +* continue to run. +*/ +void thrd_yield(void); + +/* Thread local storage */ +#if defined(_TTHREAD_WIN32_) +typedef DWORD tss_t; +#else +typedef pthread_key_t tss_t; +#endif + +/** Destructor function for a thread-specific storage. +* @param val The value of the destructed thread-specific storage. +*/ +typedef void (*tss_dtor_t)(void *val); + +/** Create a thread-specific storage. +* @param key The unique key identifier that will be set if the function is +* successful. +* @param dtor Destructor function. This can be NULL. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +* @note The destructor function is not supported under Windows. If @c dtor is +* not NULL when calling this function under Windows, the function will fail +* and return @ref thrd_error. +*/ +int tss_create(tss_t *key, tss_dtor_t dtor); + +/** Delete a thread-specific storage. +* The function releases any resources used by the given thread-specific +* storage. +* @param key The key that shall be deleted. +*/ +void tss_delete(tss_t key); + +/** Get the value for a thread-specific storage. +* @param key The thread-specific storage identifier. +* @return The value for the current thread held in the given thread-specific +* storage. +*/ +void *tss_get(tss_t key); + +/** Set the value for a thread-specific storage. +* @param key The thread-specific storage identifier. +* @param val The value of the thread-specific storage to set for the current +* thread. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int tss_set(tss_t key, void *val); + + +#endif /* _TINYTHREAD_H_ */ + diff --git a/src/external/glfw/deps/vs2008/stdint.h b/src/external/glfw/deps/vs2008/stdint.h new file mode 100644 index 00000000..d02608a5 --- /dev/null +++ b/src/external/glfw/deps/vs2008/stdint.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/src/external/glfw/deps/vulkan/vk_platform.h b/src/external/glfw/deps/vulkan/vk_platform.h new file mode 100644 index 00000000..0fa62ee2 --- /dev/null +++ b/src/external/glfw/deps/vulkan/vk_platform.h @@ -0,0 +1,120 @@ +// +// File: vk_platform.h +// +/* +** Copyright (c) 2014-2015 The Khronos Group Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + + +#ifndef VK_PLATFORM_H_ +#define VK_PLATFORM_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/* +*************************************************************************************************** +* Platform-specific directives and type declarations +*************************************************************************************************** +*/ + +/* Platform-specific calling convention macros. + * + * Platforms should define these so that Vulkan clients call Vulkan commands + * with the same calling conventions that the Vulkan implementation expects. + * + * VKAPI_ATTR - Placed before the return type in function declarations. + * Useful for C++11 and GCC/Clang-style function attribute syntax. + * VKAPI_CALL - Placed after the return type in function declarations. + * Useful for MSVC-style calling convention syntax. + * VKAPI_PTR - Placed between the '(' and '*' in function pointer types. + * + * Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); + * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); + */ +#if defined(_WIN32) + // On Windows, Vulkan commands use the stdcall convention + #define VKAPI_ATTR + #define VKAPI_CALL __stdcall + #define VKAPI_PTR VKAPI_CALL +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 + #error "Vulkan isn't supported for the 'armeabi' NDK ABI" +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) + // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" + // calling convention, i.e. float parameters are passed in registers. This + // is true even if the rest of the application passes floats on the stack, + // as it does by default when compiling for the armeabi-v7a NDK ABI. + #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) + #define VKAPI_CALL + #define VKAPI_PTR VKAPI_ATTR +#else + // On other platforms, use the default calling convention + #define VKAPI_ATTR + #define VKAPI_CALL + #define VKAPI_PTR +#endif + +#include + +#if !defined(VK_NO_STDINT_H) + #if defined(_MSC_VER) && (_MSC_VER < 1600) + typedef signed __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef signed __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef signed __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; + #else + #include + #endif +#endif // !defined(VK_NO_STDINT_H) + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +// Platform-specific headers required by platform window system extensions. +// These are enabled prior to #including "vulkan.h". The same enable then +// controls inclusion of the extension interfaces in vulkan.h. + +#ifdef VK_USE_PLATFORM_ANDROID_KHR +#include +#endif + +#ifdef VK_USE_PLATFORM_MIR_KHR +#include +#endif + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +#include +#endif + +#ifdef VK_USE_PLATFORM_WIN32_KHR +#include +#endif + +#ifdef VK_USE_PLATFORM_XLIB_KHR +#include +#endif + +#ifdef VK_USE_PLATFORM_XCB_KHR +#include +#endif + +#endif diff --git a/src/external/glfw/deps/vulkan/vulkan.h b/src/external/glfw/deps/vulkan/vulkan.h new file mode 100644 index 00000000..81dedf77 --- /dev/null +++ b/src/external/glfw/deps/vulkan/vulkan.h @@ -0,0 +1,4763 @@ +#ifndef VULKAN_H_ +#define VULKAN_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2015-2017 The Khronos Group Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#define VK_VERSION_1_0 1 +#include "vk_platform.h" + +#define VK_MAKE_VERSION(major, minor, patch) \ + (((major) << 22) | ((minor) << 12) | (patch)) + +// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. +//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) + +// Vulkan 1.0 version number +#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0) + +#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) +#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) +#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) +// Version of this file +#define VK_HEADER_VERSION 39 + + +#define VK_NULL_HANDLE 0 + + + +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; + + +#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; +#else + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#endif +#endif + + + +typedef uint32_t VkFlags; +typedef uint32_t VkBool32; +typedef uint64_t VkDeviceSize; +typedef uint32_t VkSampleMask; + +VK_DEFINE_HANDLE(VkInstance) +VK_DEFINE_HANDLE(VkPhysicalDevice) +VK_DEFINE_HANDLE(VkDevice) +VK_DEFINE_HANDLE(VkQueue) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) +VK_DEFINE_HANDLE(VkCommandBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) + +#define VK_LOD_CLAMP_NONE 1000.0f +#define VK_REMAINING_MIP_LEVELS (~0U) +#define VK_REMAINING_ARRAY_LAYERS (~0U) +#define VK_WHOLE_SIZE (~0ULL) +#define VK_ATTACHMENT_UNUSED (~0U) +#define VK_TRUE 1 +#define VK_FALSE 0 +#define VK_QUEUE_FAMILY_IGNORED (~0U) +#define VK_SUBPASS_EXTERNAL (~0U) +#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 +#define VK_UUID_SIZE 16 +#define VK_MAX_MEMORY_TYPES 32 +#define VK_MAX_MEMORY_HEAPS 16 +#define VK_MAX_EXTENSION_NAME_SIZE 256 +#define VK_MAX_DESCRIPTION_SIZE 256 + + +typedef enum VkPipelineCacheHeaderVersion { + VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, + VK_PIPELINE_CACHE_HEADER_VERSION_BEGIN_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, + VK_PIPELINE_CACHE_HEADER_VERSION_END_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, + VK_PIPELINE_CACHE_HEADER_VERSION_RANGE_SIZE = (VK_PIPELINE_CACHE_HEADER_VERSION_ONE - VK_PIPELINE_CACHE_HEADER_VERSION_ONE + 1), + VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCacheHeaderVersion; + +typedef enum VkResult { + VK_SUCCESS = 0, + VK_NOT_READY = 1, + VK_TIMEOUT = 2, + VK_EVENT_SET = 3, + VK_EVENT_RESET = 4, + VK_INCOMPLETE = 5, + VK_ERROR_OUT_OF_HOST_MEMORY = -1, + VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, + VK_ERROR_INITIALIZATION_FAILED = -3, + VK_ERROR_DEVICE_LOST = -4, + VK_ERROR_MEMORY_MAP_FAILED = -5, + VK_ERROR_LAYER_NOT_PRESENT = -6, + VK_ERROR_EXTENSION_NOT_PRESENT = -7, + VK_ERROR_FEATURE_NOT_PRESENT = -8, + VK_ERROR_INCOMPATIBLE_DRIVER = -9, + VK_ERROR_TOO_MANY_OBJECTS = -10, + VK_ERROR_FORMAT_NOT_SUPPORTED = -11, + VK_ERROR_FRAGMENTED_POOL = -12, + VK_ERROR_SURFACE_LOST_KHR = -1000000000, + VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, + VK_SUBOPTIMAL_KHR = 1000001003, + VK_ERROR_OUT_OF_DATE_KHR = -1000001004, + VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, + VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, + VK_ERROR_INVALID_SHADER_NV = -1000012000, + VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000, + VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL, + VK_RESULT_END_RANGE = VK_INCOMPLETE, + VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1), + VK_RESULT_MAX_ENUM = 0x7FFFFFFF +} VkResult; + +typedef enum VkStructureType { + VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, + VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, + VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, + VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, + VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, + VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, + VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, + VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, + VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, + VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, + VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, + VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, + VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, + VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000, + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, + VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, + VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, + VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, + VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, + VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, + VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, + VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, + VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001, + VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008, + VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, + VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, + VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001, + VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002, + VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003, + VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004, + VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = 1000090000, + VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000, + VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001, + VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002, + VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, + VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO, + VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO, + VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1), + VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkStructureType; + +typedef enum VkSystemAllocationScope { + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, + VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, + VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, + VK_SYSTEM_ALLOCATION_SCOPE_BEGIN_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND, + VK_SYSTEM_ALLOCATION_SCOPE_END_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE, + VK_SYSTEM_ALLOCATION_SCOPE_RANGE_SIZE = (VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND + 1), + VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF +} VkSystemAllocationScope; + +typedef enum VkInternalAllocationType { + VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, + VK_INTERNAL_ALLOCATION_TYPE_BEGIN_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, + VK_INTERNAL_ALLOCATION_TYPE_END_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, + VK_INTERNAL_ALLOCATION_TYPE_RANGE_SIZE = (VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE + 1), + VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkInternalAllocationType; + +typedef enum VkFormat { + VK_FORMAT_UNDEFINED = 0, + VK_FORMAT_R4G4_UNORM_PACK8 = 1, + VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, + VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, + VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, + VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, + VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, + VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, + VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, + VK_FORMAT_R8_UNORM = 9, + VK_FORMAT_R8_SNORM = 10, + VK_FORMAT_R8_USCALED = 11, + VK_FORMAT_R8_SSCALED = 12, + VK_FORMAT_R8_UINT = 13, + VK_FORMAT_R8_SINT = 14, + VK_FORMAT_R8_SRGB = 15, + VK_FORMAT_R8G8_UNORM = 16, + VK_FORMAT_R8G8_SNORM = 17, + VK_FORMAT_R8G8_USCALED = 18, + VK_FORMAT_R8G8_SSCALED = 19, + VK_FORMAT_R8G8_UINT = 20, + VK_FORMAT_R8G8_SINT = 21, + VK_FORMAT_R8G8_SRGB = 22, + VK_FORMAT_R8G8B8_UNORM = 23, + VK_FORMAT_R8G8B8_SNORM = 24, + VK_FORMAT_R8G8B8_USCALED = 25, + VK_FORMAT_R8G8B8_SSCALED = 26, + VK_FORMAT_R8G8B8_UINT = 27, + VK_FORMAT_R8G8B8_SINT = 28, + VK_FORMAT_R8G8B8_SRGB = 29, + VK_FORMAT_B8G8R8_UNORM = 30, + VK_FORMAT_B8G8R8_SNORM = 31, + VK_FORMAT_B8G8R8_USCALED = 32, + VK_FORMAT_B8G8R8_SSCALED = 33, + VK_FORMAT_B8G8R8_UINT = 34, + VK_FORMAT_B8G8R8_SINT = 35, + VK_FORMAT_B8G8R8_SRGB = 36, + VK_FORMAT_R8G8B8A8_UNORM = 37, + VK_FORMAT_R8G8B8A8_SNORM = 38, + VK_FORMAT_R8G8B8A8_USCALED = 39, + VK_FORMAT_R8G8B8A8_SSCALED = 40, + VK_FORMAT_R8G8B8A8_UINT = 41, + VK_FORMAT_R8G8B8A8_SINT = 42, + VK_FORMAT_R8G8B8A8_SRGB = 43, + VK_FORMAT_B8G8R8A8_UNORM = 44, + VK_FORMAT_B8G8R8A8_SNORM = 45, + VK_FORMAT_B8G8R8A8_USCALED = 46, + VK_FORMAT_B8G8R8A8_SSCALED = 47, + VK_FORMAT_B8G8R8A8_UINT = 48, + VK_FORMAT_B8G8R8A8_SINT = 49, + VK_FORMAT_B8G8R8A8_SRGB = 50, + VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, + VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, + VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, + VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, + VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, + VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, + VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, + VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, + VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, + VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, + VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, + VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, + VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, + VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, + VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, + VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, + VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, + VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, + VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, + VK_FORMAT_R16_UNORM = 70, + VK_FORMAT_R16_SNORM = 71, + VK_FORMAT_R16_USCALED = 72, + VK_FORMAT_R16_SSCALED = 73, + VK_FORMAT_R16_UINT = 74, + VK_FORMAT_R16_SINT = 75, + VK_FORMAT_R16_SFLOAT = 76, + VK_FORMAT_R16G16_UNORM = 77, + VK_FORMAT_R16G16_SNORM = 78, + VK_FORMAT_R16G16_USCALED = 79, + VK_FORMAT_R16G16_SSCALED = 80, + VK_FORMAT_R16G16_UINT = 81, + VK_FORMAT_R16G16_SINT = 82, + VK_FORMAT_R16G16_SFLOAT = 83, + VK_FORMAT_R16G16B16_UNORM = 84, + VK_FORMAT_R16G16B16_SNORM = 85, + VK_FORMAT_R16G16B16_USCALED = 86, + VK_FORMAT_R16G16B16_SSCALED = 87, + VK_FORMAT_R16G16B16_UINT = 88, + VK_FORMAT_R16G16B16_SINT = 89, + VK_FORMAT_R16G16B16_SFLOAT = 90, + VK_FORMAT_R16G16B16A16_UNORM = 91, + VK_FORMAT_R16G16B16A16_SNORM = 92, + VK_FORMAT_R16G16B16A16_USCALED = 93, + VK_FORMAT_R16G16B16A16_SSCALED = 94, + VK_FORMAT_R16G16B16A16_UINT = 95, + VK_FORMAT_R16G16B16A16_SINT = 96, + VK_FORMAT_R16G16B16A16_SFLOAT = 97, + VK_FORMAT_R32_UINT = 98, + VK_FORMAT_R32_SINT = 99, + VK_FORMAT_R32_SFLOAT = 100, + VK_FORMAT_R32G32_UINT = 101, + VK_FORMAT_R32G32_SINT = 102, + VK_FORMAT_R32G32_SFLOAT = 103, + VK_FORMAT_R32G32B32_UINT = 104, + VK_FORMAT_R32G32B32_SINT = 105, + VK_FORMAT_R32G32B32_SFLOAT = 106, + VK_FORMAT_R32G32B32A32_UINT = 107, + VK_FORMAT_R32G32B32A32_SINT = 108, + VK_FORMAT_R32G32B32A32_SFLOAT = 109, + VK_FORMAT_R64_UINT = 110, + VK_FORMAT_R64_SINT = 111, + VK_FORMAT_R64_SFLOAT = 112, + VK_FORMAT_R64G64_UINT = 113, + VK_FORMAT_R64G64_SINT = 114, + VK_FORMAT_R64G64_SFLOAT = 115, + VK_FORMAT_R64G64B64_UINT = 116, + VK_FORMAT_R64G64B64_SINT = 117, + VK_FORMAT_R64G64B64_SFLOAT = 118, + VK_FORMAT_R64G64B64A64_UINT = 119, + VK_FORMAT_R64G64B64A64_SINT = 120, + VK_FORMAT_R64G64B64A64_SFLOAT = 121, + VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, + VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, + VK_FORMAT_D16_UNORM = 124, + VK_FORMAT_X8_D24_UNORM_PACK32 = 125, + VK_FORMAT_D32_SFLOAT = 126, + VK_FORMAT_S8_UINT = 127, + VK_FORMAT_D16_UNORM_S8_UINT = 128, + VK_FORMAT_D24_UNORM_S8_UINT = 129, + VK_FORMAT_D32_SFLOAT_S8_UINT = 130, + VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, + VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, + VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, + VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, + VK_FORMAT_BC2_UNORM_BLOCK = 135, + VK_FORMAT_BC2_SRGB_BLOCK = 136, + VK_FORMAT_BC3_UNORM_BLOCK = 137, + VK_FORMAT_BC3_SRGB_BLOCK = 138, + VK_FORMAT_BC4_UNORM_BLOCK = 139, + VK_FORMAT_BC4_SNORM_BLOCK = 140, + VK_FORMAT_BC5_UNORM_BLOCK = 141, + VK_FORMAT_BC5_SNORM_BLOCK = 142, + VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, + VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, + VK_FORMAT_BC7_UNORM_BLOCK = 145, + VK_FORMAT_BC7_SRGB_BLOCK = 146, + VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, + VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, + VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, + VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, + VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, + VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, + VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, + VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, + VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, + VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, + VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, + VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, + VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, + VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, + VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, + VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, + VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, + VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, + VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, + VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, + VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, + VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, + VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, + VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, + VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, + VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, + VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, + VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, + VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, + VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, + VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, + VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, + VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, + VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, + VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, + VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, + VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, + VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, + VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, + VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, + VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, + VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003, + VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004, + VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, + VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, + VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, + VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED, + VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK, + VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1), + VK_FORMAT_MAX_ENUM = 0x7FFFFFFF +} VkFormat; + +typedef enum VkImageType { + VK_IMAGE_TYPE_1D = 0, + VK_IMAGE_TYPE_2D = 1, + VK_IMAGE_TYPE_3D = 2, + VK_IMAGE_TYPE_BEGIN_RANGE = VK_IMAGE_TYPE_1D, + VK_IMAGE_TYPE_END_RANGE = VK_IMAGE_TYPE_3D, + VK_IMAGE_TYPE_RANGE_SIZE = (VK_IMAGE_TYPE_3D - VK_IMAGE_TYPE_1D + 1), + VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkImageType; + +typedef enum VkImageTiling { + VK_IMAGE_TILING_OPTIMAL = 0, + VK_IMAGE_TILING_LINEAR = 1, + VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR, + VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1), + VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF +} VkImageTiling; + +typedef enum VkPhysicalDeviceType { + VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, + VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, + VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, + VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, + VK_PHYSICAL_DEVICE_TYPE_CPU = 4, + VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE = VK_PHYSICAL_DEVICE_TYPE_OTHER, + VK_PHYSICAL_DEVICE_TYPE_END_RANGE = VK_PHYSICAL_DEVICE_TYPE_CPU, + VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE = (VK_PHYSICAL_DEVICE_TYPE_CPU - VK_PHYSICAL_DEVICE_TYPE_OTHER + 1), + VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkPhysicalDeviceType; + +typedef enum VkQueryType { + VK_QUERY_TYPE_OCCLUSION = 0, + VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, + VK_QUERY_TYPE_TIMESTAMP = 2, + VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION, + VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP, + VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1), + VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkQueryType; + +typedef enum VkSharingMode { + VK_SHARING_MODE_EXCLUSIVE = 0, + VK_SHARING_MODE_CONCURRENT = 1, + VK_SHARING_MODE_BEGIN_RANGE = VK_SHARING_MODE_EXCLUSIVE, + VK_SHARING_MODE_END_RANGE = VK_SHARING_MODE_CONCURRENT, + VK_SHARING_MODE_RANGE_SIZE = (VK_SHARING_MODE_CONCURRENT - VK_SHARING_MODE_EXCLUSIVE + 1), + VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSharingMode; + +typedef enum VkImageLayout { + VK_IMAGE_LAYOUT_UNDEFINED = 0, + VK_IMAGE_LAYOUT_GENERAL = 1, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7, + VK_IMAGE_LAYOUT_PREINITIALIZED = 8, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, + VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_END_RANGE = VK_IMAGE_LAYOUT_PREINITIALIZED, + VK_IMAGE_LAYOUT_RANGE_SIZE = (VK_IMAGE_LAYOUT_PREINITIALIZED - VK_IMAGE_LAYOUT_UNDEFINED + 1), + VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF +} VkImageLayout; + +typedef enum VkImageViewType { + VK_IMAGE_VIEW_TYPE_1D = 0, + VK_IMAGE_VIEW_TYPE_2D = 1, + VK_IMAGE_VIEW_TYPE_3D = 2, + VK_IMAGE_VIEW_TYPE_CUBE = 3, + VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, + VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, + VK_IMAGE_VIEW_TYPE_BEGIN_RANGE = VK_IMAGE_VIEW_TYPE_1D, + VK_IMAGE_VIEW_TYPE_END_RANGE = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, + VK_IMAGE_VIEW_TYPE_RANGE_SIZE = (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY - VK_IMAGE_VIEW_TYPE_1D + 1), + VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkImageViewType; + +typedef enum VkComponentSwizzle { + VK_COMPONENT_SWIZZLE_IDENTITY = 0, + VK_COMPONENT_SWIZZLE_ZERO = 1, + VK_COMPONENT_SWIZZLE_ONE = 2, + VK_COMPONENT_SWIZZLE_R = 3, + VK_COMPONENT_SWIZZLE_G = 4, + VK_COMPONENT_SWIZZLE_B = 5, + VK_COMPONENT_SWIZZLE_A = 6, + VK_COMPONENT_SWIZZLE_BEGIN_RANGE = VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_END_RANGE = VK_COMPONENT_SWIZZLE_A, + VK_COMPONENT_SWIZZLE_RANGE_SIZE = (VK_COMPONENT_SWIZZLE_A - VK_COMPONENT_SWIZZLE_IDENTITY + 1), + VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF +} VkComponentSwizzle; + +typedef enum VkVertexInputRate { + VK_VERTEX_INPUT_RATE_VERTEX = 0, + VK_VERTEX_INPUT_RATE_INSTANCE = 1, + VK_VERTEX_INPUT_RATE_BEGIN_RANGE = VK_VERTEX_INPUT_RATE_VERTEX, + VK_VERTEX_INPUT_RATE_END_RANGE = VK_VERTEX_INPUT_RATE_INSTANCE, + VK_VERTEX_INPUT_RATE_RANGE_SIZE = (VK_VERTEX_INPUT_RATE_INSTANCE - VK_VERTEX_INPUT_RATE_VERTEX + 1), + VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF +} VkVertexInputRate; + +typedef enum VkPrimitiveTopology { + VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, + VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, + VK_PRIMITIVE_TOPOLOGY_BEGIN_RANGE = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, + VK_PRIMITIVE_TOPOLOGY_END_RANGE = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, + VK_PRIMITIVE_TOPOLOGY_RANGE_SIZE = (VK_PRIMITIVE_TOPOLOGY_PATCH_LIST - VK_PRIMITIVE_TOPOLOGY_POINT_LIST + 1), + VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF +} VkPrimitiveTopology; + +typedef enum VkPolygonMode { + VK_POLYGON_MODE_FILL = 0, + VK_POLYGON_MODE_LINE = 1, + VK_POLYGON_MODE_POINT = 2, + VK_POLYGON_MODE_BEGIN_RANGE = VK_POLYGON_MODE_FILL, + VK_POLYGON_MODE_END_RANGE = VK_POLYGON_MODE_POINT, + VK_POLYGON_MODE_RANGE_SIZE = (VK_POLYGON_MODE_POINT - VK_POLYGON_MODE_FILL + 1), + VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF +} VkPolygonMode; + +typedef enum VkFrontFace { + VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, + VK_FRONT_FACE_CLOCKWISE = 1, + VK_FRONT_FACE_BEGIN_RANGE = VK_FRONT_FACE_COUNTER_CLOCKWISE, + VK_FRONT_FACE_END_RANGE = VK_FRONT_FACE_CLOCKWISE, + VK_FRONT_FACE_RANGE_SIZE = (VK_FRONT_FACE_CLOCKWISE - VK_FRONT_FACE_COUNTER_CLOCKWISE + 1), + VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF +} VkFrontFace; + +typedef enum VkCompareOp { + VK_COMPARE_OP_NEVER = 0, + VK_COMPARE_OP_LESS = 1, + VK_COMPARE_OP_EQUAL = 2, + VK_COMPARE_OP_LESS_OR_EQUAL = 3, + VK_COMPARE_OP_GREATER = 4, + VK_COMPARE_OP_NOT_EQUAL = 5, + VK_COMPARE_OP_GREATER_OR_EQUAL = 6, + VK_COMPARE_OP_ALWAYS = 7, + VK_COMPARE_OP_BEGIN_RANGE = VK_COMPARE_OP_NEVER, + VK_COMPARE_OP_END_RANGE = VK_COMPARE_OP_ALWAYS, + VK_COMPARE_OP_RANGE_SIZE = (VK_COMPARE_OP_ALWAYS - VK_COMPARE_OP_NEVER + 1), + VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF +} VkCompareOp; + +typedef enum VkStencilOp { + VK_STENCIL_OP_KEEP = 0, + VK_STENCIL_OP_ZERO = 1, + VK_STENCIL_OP_REPLACE = 2, + VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3, + VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, + VK_STENCIL_OP_INVERT = 5, + VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, + VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, + VK_STENCIL_OP_BEGIN_RANGE = VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_END_RANGE = VK_STENCIL_OP_DECREMENT_AND_WRAP, + VK_STENCIL_OP_RANGE_SIZE = (VK_STENCIL_OP_DECREMENT_AND_WRAP - VK_STENCIL_OP_KEEP + 1), + VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF +} VkStencilOp; + +typedef enum VkLogicOp { + VK_LOGIC_OP_CLEAR = 0, + VK_LOGIC_OP_AND = 1, + VK_LOGIC_OP_AND_REVERSE = 2, + VK_LOGIC_OP_COPY = 3, + VK_LOGIC_OP_AND_INVERTED = 4, + VK_LOGIC_OP_NO_OP = 5, + VK_LOGIC_OP_XOR = 6, + VK_LOGIC_OP_OR = 7, + VK_LOGIC_OP_NOR = 8, + VK_LOGIC_OP_EQUIVALENT = 9, + VK_LOGIC_OP_INVERT = 10, + VK_LOGIC_OP_OR_REVERSE = 11, + VK_LOGIC_OP_COPY_INVERTED = 12, + VK_LOGIC_OP_OR_INVERTED = 13, + VK_LOGIC_OP_NAND = 14, + VK_LOGIC_OP_SET = 15, + VK_LOGIC_OP_BEGIN_RANGE = VK_LOGIC_OP_CLEAR, + VK_LOGIC_OP_END_RANGE = VK_LOGIC_OP_SET, + VK_LOGIC_OP_RANGE_SIZE = (VK_LOGIC_OP_SET - VK_LOGIC_OP_CLEAR + 1), + VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF +} VkLogicOp; + +typedef enum VkBlendFactor { + VK_BLEND_FACTOR_ZERO = 0, + VK_BLEND_FACTOR_ONE = 1, + VK_BLEND_FACTOR_SRC_COLOR = 2, + VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3, + VK_BLEND_FACTOR_DST_COLOR = 4, + VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5, + VK_BLEND_FACTOR_SRC_ALPHA = 6, + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7, + VK_BLEND_FACTOR_DST_ALPHA = 8, + VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9, + VK_BLEND_FACTOR_CONSTANT_COLOR = 10, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11, + VK_BLEND_FACTOR_CONSTANT_ALPHA = 12, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13, + VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14, + VK_BLEND_FACTOR_SRC1_COLOR = 15, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, + VK_BLEND_FACTOR_SRC1_ALPHA = 17, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, + VK_BLEND_FACTOR_BEGIN_RANGE = VK_BLEND_FACTOR_ZERO, + VK_BLEND_FACTOR_END_RANGE = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, + VK_BLEND_FACTOR_RANGE_SIZE = (VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA - VK_BLEND_FACTOR_ZERO + 1), + VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF +} VkBlendFactor; + +typedef enum VkBlendOp { + VK_BLEND_OP_ADD = 0, + VK_BLEND_OP_SUBTRACT = 1, + VK_BLEND_OP_REVERSE_SUBTRACT = 2, + VK_BLEND_OP_MIN = 3, + VK_BLEND_OP_MAX = 4, + VK_BLEND_OP_BEGIN_RANGE = VK_BLEND_OP_ADD, + VK_BLEND_OP_END_RANGE = VK_BLEND_OP_MAX, + VK_BLEND_OP_RANGE_SIZE = (VK_BLEND_OP_MAX - VK_BLEND_OP_ADD + 1), + VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF +} VkBlendOp; + +typedef enum VkDynamicState { + VK_DYNAMIC_STATE_VIEWPORT = 0, + VK_DYNAMIC_STATE_SCISSOR = 1, + VK_DYNAMIC_STATE_LINE_WIDTH = 2, + VK_DYNAMIC_STATE_DEPTH_BIAS = 3, + VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4, + VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, + VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, + VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE, + VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1), + VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF +} VkDynamicState; + +typedef enum VkFilter { + VK_FILTER_NEAREST = 0, + VK_FILTER_LINEAR = 1, + VK_FILTER_CUBIC_IMG = 1000015000, + VK_FILTER_BEGIN_RANGE = VK_FILTER_NEAREST, + VK_FILTER_END_RANGE = VK_FILTER_LINEAR, + VK_FILTER_RANGE_SIZE = (VK_FILTER_LINEAR - VK_FILTER_NEAREST + 1), + VK_FILTER_MAX_ENUM = 0x7FFFFFFF +} VkFilter; + +typedef enum VkSamplerMipmapMode { + VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, + VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, + VK_SAMPLER_MIPMAP_MODE_BEGIN_RANGE = VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_MIPMAP_MODE_END_RANGE = VK_SAMPLER_MIPMAP_MODE_LINEAR, + VK_SAMPLER_MIPMAP_MODE_RANGE_SIZE = (VK_SAMPLER_MIPMAP_MODE_LINEAR - VK_SAMPLER_MIPMAP_MODE_NEAREST + 1), + VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerMipmapMode; + +typedef enum VkSamplerAddressMode { + VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, + VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, + VK_SAMPLER_ADDRESS_MODE_BEGIN_RANGE = VK_SAMPLER_ADDRESS_MODE_REPEAT, + VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1), + VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerAddressMode; + +typedef enum VkBorderColor { + VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, + VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, + VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2, + VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3, + VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, + VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, + VK_BORDER_COLOR_BEGIN_RANGE = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, + VK_BORDER_COLOR_END_RANGE = VK_BORDER_COLOR_INT_OPAQUE_WHITE, + VK_BORDER_COLOR_RANGE_SIZE = (VK_BORDER_COLOR_INT_OPAQUE_WHITE - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + 1), + VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF +} VkBorderColor; + +typedef enum VkDescriptorType { + VK_DESCRIPTOR_TYPE_SAMPLER = 0, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, + VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2, + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3, + VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4, + VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, + VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, + VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER, + VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1), + VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorType; + +typedef enum VkAttachmentLoadOp { + VK_ATTACHMENT_LOAD_OP_LOAD = 0, + VK_ATTACHMENT_LOAD_OP_CLEAR = 1, + VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, + VK_ATTACHMENT_LOAD_OP_BEGIN_RANGE = VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_LOAD_OP_END_RANGE = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_RANGE_SIZE = (VK_ATTACHMENT_LOAD_OP_DONT_CARE - VK_ATTACHMENT_LOAD_OP_LOAD + 1), + VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentLoadOp; + +typedef enum VkAttachmentStoreOp { + VK_ATTACHMENT_STORE_OP_STORE = 0, + VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, + VK_ATTACHMENT_STORE_OP_BEGIN_RANGE = VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_STORE_OP_END_RANGE = VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_RANGE_SIZE = (VK_ATTACHMENT_STORE_OP_DONT_CARE - VK_ATTACHMENT_STORE_OP_STORE + 1), + VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentStoreOp; + +typedef enum VkPipelineBindPoint { + VK_PIPELINE_BIND_POINT_GRAPHICS = 0, + VK_PIPELINE_BIND_POINT_COMPUTE = 1, + VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS, + VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE, + VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1), + VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF +} VkPipelineBindPoint; + +typedef enum VkCommandBufferLevel { + VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, + VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, + VK_COMMAND_BUFFER_LEVEL_BEGIN_RANGE = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + VK_COMMAND_BUFFER_LEVEL_END_RANGE = VK_COMMAND_BUFFER_LEVEL_SECONDARY, + VK_COMMAND_BUFFER_LEVEL_RANGE_SIZE = (VK_COMMAND_BUFFER_LEVEL_SECONDARY - VK_COMMAND_BUFFER_LEVEL_PRIMARY + 1), + VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferLevel; + +typedef enum VkIndexType { + VK_INDEX_TYPE_UINT16 = 0, + VK_INDEX_TYPE_UINT32 = 1, + VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16, + VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32, + VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1), + VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkIndexType; + +typedef enum VkSubpassContents { + VK_SUBPASS_CONTENTS_INLINE = 0, + VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, + VK_SUBPASS_CONTENTS_BEGIN_RANGE = VK_SUBPASS_CONTENTS_INLINE, + VK_SUBPASS_CONTENTS_END_RANGE = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, + VK_SUBPASS_CONTENTS_RANGE_SIZE = (VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS - VK_SUBPASS_CONTENTS_INLINE + 1), + VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF +} VkSubpassContents; + +typedef VkFlags VkInstanceCreateFlags; + +typedef enum VkFormatFeatureFlagBits { + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, + VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, + VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, + VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, + VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, + VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, + VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000, + VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000, + VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFormatFeatureFlagBits; +typedef VkFlags VkFormatFeatureFlags; + +typedef enum VkImageUsageFlagBits { + VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, + VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, + VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, + VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, + VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageUsageFlagBits; +typedef VkFlags VkImageUsageFlags; + +typedef enum VkImageCreateFlagBits { + VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, + VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, + VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, + VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, + VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020, + VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageCreateFlagBits; +typedef VkFlags VkImageCreateFlags; + +typedef enum VkSampleCountFlagBits { + VK_SAMPLE_COUNT_1_BIT = 0x00000001, + VK_SAMPLE_COUNT_2_BIT = 0x00000002, + VK_SAMPLE_COUNT_4_BIT = 0x00000004, + VK_SAMPLE_COUNT_8_BIT = 0x00000008, + VK_SAMPLE_COUNT_16_BIT = 0x00000010, + VK_SAMPLE_COUNT_32_BIT = 0x00000020, + VK_SAMPLE_COUNT_64_BIT = 0x00000040, + VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSampleCountFlagBits; +typedef VkFlags VkSampleCountFlags; + +typedef enum VkQueueFlagBits { + VK_QUEUE_GRAPHICS_BIT = 0x00000001, + VK_QUEUE_COMPUTE_BIT = 0x00000002, + VK_QUEUE_TRANSFER_BIT = 0x00000004, + VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, + VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueueFlagBits; +typedef VkFlags VkQueueFlags; + +typedef enum VkMemoryPropertyFlagBits { + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, + VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, + VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryPropertyFlagBits; +typedef VkFlags VkMemoryPropertyFlags; + +typedef enum VkMemoryHeapFlagBits { + VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, + VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryHeapFlagBits; +typedef VkFlags VkMemoryHeapFlags; +typedef VkFlags VkDeviceCreateFlags; +typedef VkFlags VkDeviceQueueCreateFlags; + +typedef enum VkPipelineStageFlagBits { + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, + VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, + VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, + VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, + VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, + VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, + VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000, + VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineStageFlagBits; +typedef VkFlags VkPipelineStageFlags; +typedef VkFlags VkMemoryMapFlags; + +typedef enum VkImageAspectFlagBits { + VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, + VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, + VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, + VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, + VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageAspectFlagBits; +typedef VkFlags VkImageAspectFlags; + +typedef enum VkSparseImageFormatFlagBits { + VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, + VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, + VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, + VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSparseImageFormatFlagBits; +typedef VkFlags VkSparseImageFormatFlags; + +typedef enum VkSparseMemoryBindFlagBits { + VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, + VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSparseMemoryBindFlagBits; +typedef VkFlags VkSparseMemoryBindFlags; + +typedef enum VkFenceCreateFlagBits { + VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, + VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFenceCreateFlagBits; +typedef VkFlags VkFenceCreateFlags; +typedef VkFlags VkSemaphoreCreateFlags; +typedef VkFlags VkEventCreateFlags; +typedef VkFlags VkQueryPoolCreateFlags; + +typedef enum VkQueryPipelineStatisticFlagBits { + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, + VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, + VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, + VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, + VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryPipelineStatisticFlagBits; +typedef VkFlags VkQueryPipelineStatisticFlags; + +typedef enum VkQueryResultFlagBits { + VK_QUERY_RESULT_64_BIT = 0x00000001, + VK_QUERY_RESULT_WAIT_BIT = 0x00000002, + VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, + VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, + VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryResultFlagBits; +typedef VkFlags VkQueryResultFlags; + +typedef enum VkBufferCreateFlagBits { + VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, + VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, + VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkBufferCreateFlagBits; +typedef VkFlags VkBufferCreateFlags; + +typedef enum VkBufferUsageFlagBits { + VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, + VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, + VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, + VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, + VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkBufferUsageFlagBits; +typedef VkFlags VkBufferUsageFlags; +typedef VkFlags VkBufferViewCreateFlags; +typedef VkFlags VkImageViewCreateFlags; +typedef VkFlags VkShaderModuleCreateFlags; +typedef VkFlags VkPipelineCacheCreateFlags; + +typedef enum VkPipelineCreateFlagBits { + VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, + VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, + VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, + VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCreateFlagBits; +typedef VkFlags VkPipelineCreateFlags; +typedef VkFlags VkPipelineShaderStageCreateFlags; + +typedef enum VkShaderStageFlagBits { + VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, + VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, + VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, + VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, + VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, + VK_SHADER_STAGE_ALL = 0x7FFFFFFF, + VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkShaderStageFlagBits; +typedef VkFlags VkPipelineVertexInputStateCreateFlags; +typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; +typedef VkFlags VkPipelineTessellationStateCreateFlags; +typedef VkFlags VkPipelineViewportStateCreateFlags; +typedef VkFlags VkPipelineRasterizationStateCreateFlags; + +typedef enum VkCullModeFlagBits { + VK_CULL_MODE_NONE = 0, + VK_CULL_MODE_FRONT_BIT = 0x00000001, + VK_CULL_MODE_BACK_BIT = 0x00000002, + VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, + VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCullModeFlagBits; +typedef VkFlags VkCullModeFlags; +typedef VkFlags VkPipelineMultisampleStateCreateFlags; +typedef VkFlags VkPipelineDepthStencilStateCreateFlags; +typedef VkFlags VkPipelineColorBlendStateCreateFlags; + +typedef enum VkColorComponentFlagBits { + VK_COLOR_COMPONENT_R_BIT = 0x00000001, + VK_COLOR_COMPONENT_G_BIT = 0x00000002, + VK_COLOR_COMPONENT_B_BIT = 0x00000004, + VK_COLOR_COMPONENT_A_BIT = 0x00000008, + VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkColorComponentFlagBits; +typedef VkFlags VkColorComponentFlags; +typedef VkFlags VkPipelineDynamicStateCreateFlags; +typedef VkFlags VkPipelineLayoutCreateFlags; +typedef VkFlags VkShaderStageFlags; +typedef VkFlags VkSamplerCreateFlags; +typedef VkFlags VkDescriptorSetLayoutCreateFlags; + +typedef enum VkDescriptorPoolCreateFlagBits { + VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, + VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorPoolCreateFlagBits; +typedef VkFlags VkDescriptorPoolCreateFlags; +typedef VkFlags VkDescriptorPoolResetFlags; +typedef VkFlags VkFramebufferCreateFlags; +typedef VkFlags VkRenderPassCreateFlags; + +typedef enum VkAttachmentDescriptionFlagBits { + VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, + VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentDescriptionFlagBits; +typedef VkFlags VkAttachmentDescriptionFlags; +typedef VkFlags VkSubpassDescriptionFlags; + +typedef enum VkAccessFlagBits { + VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, + VK_ACCESS_INDEX_READ_BIT = 0x00000002, + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, + VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, + VK_ACCESS_SHADER_READ_BIT = 0x00000020, + VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, + VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, + VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, + VK_ACCESS_HOST_READ_BIT = 0x00002000, + VK_ACCESS_HOST_WRITE_BIT = 0x00004000, + VK_ACCESS_MEMORY_READ_BIT = 0x00008000, + VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, + VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000, + VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000, + VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkAccessFlagBits; +typedef VkFlags VkAccessFlags; + +typedef enum VkDependencyFlagBits { + VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, + VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDependencyFlagBits; +typedef VkFlags VkDependencyFlags; + +typedef enum VkCommandPoolCreateFlagBits { + VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, + VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, + VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandPoolCreateFlagBits; +typedef VkFlags VkCommandPoolCreateFlags; + +typedef enum VkCommandPoolResetFlagBits { + VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandPoolResetFlagBits; +typedef VkFlags VkCommandPoolResetFlags; + +typedef enum VkCommandBufferUsageFlagBits { + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, + VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, + VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, + VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferUsageFlagBits; +typedef VkFlags VkCommandBufferUsageFlags; + +typedef enum VkQueryControlFlagBits { + VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, + VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryControlFlagBits; +typedef VkFlags VkQueryControlFlags; + +typedef enum VkCommandBufferResetFlagBits { + VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferResetFlagBits; +typedef VkFlags VkCommandBufferResetFlags; + +typedef enum VkStencilFaceFlagBits { + VK_STENCIL_FACE_FRONT_BIT = 0x00000001, + VK_STENCIL_FACE_BACK_BIT = 0x00000002, + VK_STENCIL_FRONT_AND_BACK = 0x00000003, + VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkStencilFaceFlagBits; +typedef VkFlags VkStencilFaceFlags; + +typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( + void* pUserData, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + +typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( + void* pUserData, + void* pOriginal, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkFreeFunction)( + void* pUserData, + void* pMemory); + +typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); + +typedef struct VkApplicationInfo { + VkStructureType sType; + const void* pNext; + const char* pApplicationName; + uint32_t applicationVersion; + const char* pEngineName; + uint32_t engineVersion; + uint32_t apiVersion; +} VkApplicationInfo; + +typedef struct VkInstanceCreateInfo { + VkStructureType sType; + const void* pNext; + VkInstanceCreateFlags flags; + const VkApplicationInfo* pApplicationInfo; + uint32_t enabledLayerCount; + const char* const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char* const* ppEnabledExtensionNames; +} VkInstanceCreateInfo; + +typedef struct VkAllocationCallbacks { + void* pUserData; + PFN_vkAllocationFunction pfnAllocation; + PFN_vkReallocationFunction pfnReallocation; + PFN_vkFreeFunction pfnFree; + PFN_vkInternalAllocationNotification pfnInternalAllocation; + PFN_vkInternalFreeNotification pfnInternalFree; +} VkAllocationCallbacks; + +typedef struct VkPhysicalDeviceFeatures { + VkBool32 robustBufferAccess; + VkBool32 fullDrawIndexUint32; + VkBool32 imageCubeArray; + VkBool32 independentBlend; + VkBool32 geometryShader; + VkBool32 tessellationShader; + VkBool32 sampleRateShading; + VkBool32 dualSrcBlend; + VkBool32 logicOp; + VkBool32 multiDrawIndirect; + VkBool32 drawIndirectFirstInstance; + VkBool32 depthClamp; + VkBool32 depthBiasClamp; + VkBool32 fillModeNonSolid; + VkBool32 depthBounds; + VkBool32 wideLines; + VkBool32 largePoints; + VkBool32 alphaToOne; + VkBool32 multiViewport; + VkBool32 samplerAnisotropy; + VkBool32 textureCompressionETC2; + VkBool32 textureCompressionASTC_LDR; + VkBool32 textureCompressionBC; + VkBool32 occlusionQueryPrecise; + VkBool32 pipelineStatisticsQuery; + VkBool32 vertexPipelineStoresAndAtomics; + VkBool32 fragmentStoresAndAtomics; + VkBool32 shaderTessellationAndGeometryPointSize; + VkBool32 shaderImageGatherExtended; + VkBool32 shaderStorageImageExtendedFormats; + VkBool32 shaderStorageImageMultisample; + VkBool32 shaderStorageImageReadWithoutFormat; + VkBool32 shaderStorageImageWriteWithoutFormat; + VkBool32 shaderUniformBufferArrayDynamicIndexing; + VkBool32 shaderSampledImageArrayDynamicIndexing; + VkBool32 shaderStorageBufferArrayDynamicIndexing; + VkBool32 shaderStorageImageArrayDynamicIndexing; + VkBool32 shaderClipDistance; + VkBool32 shaderCullDistance; + VkBool32 shaderFloat64; + VkBool32 shaderInt64; + VkBool32 shaderInt16; + VkBool32 shaderResourceResidency; + VkBool32 shaderResourceMinLod; + VkBool32 sparseBinding; + VkBool32 sparseResidencyBuffer; + VkBool32 sparseResidencyImage2D; + VkBool32 sparseResidencyImage3D; + VkBool32 sparseResidency2Samples; + VkBool32 sparseResidency4Samples; + VkBool32 sparseResidency8Samples; + VkBool32 sparseResidency16Samples; + VkBool32 sparseResidencyAliased; + VkBool32 variableMultisampleRate; + VkBool32 inheritedQueries; +} VkPhysicalDeviceFeatures; + +typedef struct VkFormatProperties { + VkFormatFeatureFlags linearTilingFeatures; + VkFormatFeatureFlags optimalTilingFeatures; + VkFormatFeatureFlags bufferFeatures; +} VkFormatProperties; + +typedef struct VkExtent3D { + uint32_t width; + uint32_t height; + uint32_t depth; +} VkExtent3D; + +typedef struct VkImageFormatProperties { + VkExtent3D maxExtent; + uint32_t maxMipLevels; + uint32_t maxArrayLayers; + VkSampleCountFlags sampleCounts; + VkDeviceSize maxResourceSize; +} VkImageFormatProperties; + +typedef struct VkPhysicalDeviceLimits { + uint32_t maxImageDimension1D; + uint32_t maxImageDimension2D; + uint32_t maxImageDimension3D; + uint32_t maxImageDimensionCube; + uint32_t maxImageArrayLayers; + uint32_t maxTexelBufferElements; + uint32_t maxUniformBufferRange; + uint32_t maxStorageBufferRange; + uint32_t maxPushConstantsSize; + uint32_t maxMemoryAllocationCount; + uint32_t maxSamplerAllocationCount; + VkDeviceSize bufferImageGranularity; + VkDeviceSize sparseAddressSpaceSize; + uint32_t maxBoundDescriptorSets; + uint32_t maxPerStageDescriptorSamplers; + uint32_t maxPerStageDescriptorUniformBuffers; + uint32_t maxPerStageDescriptorStorageBuffers; + uint32_t maxPerStageDescriptorSampledImages; + uint32_t maxPerStageDescriptorStorageImages; + uint32_t maxPerStageDescriptorInputAttachments; + uint32_t maxPerStageResources; + uint32_t maxDescriptorSetSamplers; + uint32_t maxDescriptorSetUniformBuffers; + uint32_t maxDescriptorSetUniformBuffersDynamic; + uint32_t maxDescriptorSetStorageBuffers; + uint32_t maxDescriptorSetStorageBuffersDynamic; + uint32_t maxDescriptorSetSampledImages; + uint32_t maxDescriptorSetStorageImages; + uint32_t maxDescriptorSetInputAttachments; + uint32_t maxVertexInputAttributes; + uint32_t maxVertexInputBindings; + uint32_t maxVertexInputAttributeOffset; + uint32_t maxVertexInputBindingStride; + uint32_t maxVertexOutputComponents; + uint32_t maxTessellationGenerationLevel; + uint32_t maxTessellationPatchSize; + uint32_t maxTessellationControlPerVertexInputComponents; + uint32_t maxTessellationControlPerVertexOutputComponents; + uint32_t maxTessellationControlPerPatchOutputComponents; + uint32_t maxTessellationControlTotalOutputComponents; + uint32_t maxTessellationEvaluationInputComponents; + uint32_t maxTessellationEvaluationOutputComponents; + uint32_t maxGeometryShaderInvocations; + uint32_t maxGeometryInputComponents; + uint32_t maxGeometryOutputComponents; + uint32_t maxGeometryOutputVertices; + uint32_t maxGeometryTotalOutputComponents; + uint32_t maxFragmentInputComponents; + uint32_t maxFragmentOutputAttachments; + uint32_t maxFragmentDualSrcAttachments; + uint32_t maxFragmentCombinedOutputResources; + uint32_t maxComputeSharedMemorySize; + uint32_t maxComputeWorkGroupCount[3]; + uint32_t maxComputeWorkGroupInvocations; + uint32_t maxComputeWorkGroupSize[3]; + uint32_t subPixelPrecisionBits; + uint32_t subTexelPrecisionBits; + uint32_t mipmapPrecisionBits; + uint32_t maxDrawIndexedIndexValue; + uint32_t maxDrawIndirectCount; + float maxSamplerLodBias; + float maxSamplerAnisotropy; + uint32_t maxViewports; + uint32_t maxViewportDimensions[2]; + float viewportBoundsRange[2]; + uint32_t viewportSubPixelBits; + size_t minMemoryMapAlignment; + VkDeviceSize minTexelBufferOffsetAlignment; + VkDeviceSize minUniformBufferOffsetAlignment; + VkDeviceSize minStorageBufferOffsetAlignment; + int32_t minTexelOffset; + uint32_t maxTexelOffset; + int32_t minTexelGatherOffset; + uint32_t maxTexelGatherOffset; + float minInterpolationOffset; + float maxInterpolationOffset; + uint32_t subPixelInterpolationOffsetBits; + uint32_t maxFramebufferWidth; + uint32_t maxFramebufferHeight; + uint32_t maxFramebufferLayers; + VkSampleCountFlags framebufferColorSampleCounts; + VkSampleCountFlags framebufferDepthSampleCounts; + VkSampleCountFlags framebufferStencilSampleCounts; + VkSampleCountFlags framebufferNoAttachmentsSampleCounts; + uint32_t maxColorAttachments; + VkSampleCountFlags sampledImageColorSampleCounts; + VkSampleCountFlags sampledImageIntegerSampleCounts; + VkSampleCountFlags sampledImageDepthSampleCounts; + VkSampleCountFlags sampledImageStencilSampleCounts; + VkSampleCountFlags storageImageSampleCounts; + uint32_t maxSampleMaskWords; + VkBool32 timestampComputeAndGraphics; + float timestampPeriod; + uint32_t maxClipDistances; + uint32_t maxCullDistances; + uint32_t maxCombinedClipAndCullDistances; + uint32_t discreteQueuePriorities; + float pointSizeRange[2]; + float lineWidthRange[2]; + float pointSizeGranularity; + float lineWidthGranularity; + VkBool32 strictLines; + VkBool32 standardSampleLocations; + VkDeviceSize optimalBufferCopyOffsetAlignment; + VkDeviceSize optimalBufferCopyRowPitchAlignment; + VkDeviceSize nonCoherentAtomSize; +} VkPhysicalDeviceLimits; + +typedef struct VkPhysicalDeviceSparseProperties { + VkBool32 residencyStandard2DBlockShape; + VkBool32 residencyStandard2DMultisampleBlockShape; + VkBool32 residencyStandard3DBlockShape; + VkBool32 residencyAlignedMipSize; + VkBool32 residencyNonResidentStrict; +} VkPhysicalDeviceSparseProperties; + +typedef struct VkPhysicalDeviceProperties { + uint32_t apiVersion; + uint32_t driverVersion; + uint32_t vendorID; + uint32_t deviceID; + VkPhysicalDeviceType deviceType; + char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; + uint8_t pipelineCacheUUID[VK_UUID_SIZE]; + VkPhysicalDeviceLimits limits; + VkPhysicalDeviceSparseProperties sparseProperties; +} VkPhysicalDeviceProperties; + +typedef struct VkQueueFamilyProperties { + VkQueueFlags queueFlags; + uint32_t queueCount; + uint32_t timestampValidBits; + VkExtent3D minImageTransferGranularity; +} VkQueueFamilyProperties; + +typedef struct VkMemoryType { + VkMemoryPropertyFlags propertyFlags; + uint32_t heapIndex; +} VkMemoryType; + +typedef struct VkMemoryHeap { + VkDeviceSize size; + VkMemoryHeapFlags flags; +} VkMemoryHeap; + +typedef struct VkPhysicalDeviceMemoryProperties { + uint32_t memoryTypeCount; + VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]; + uint32_t memoryHeapCount; + VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryProperties; + +typedef struct VkDeviceQueueCreateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueCount; + const float* pQueuePriorities; +} VkDeviceQueueCreateInfo; + +typedef struct VkDeviceCreateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceCreateFlags flags; + uint32_t queueCreateInfoCount; + const VkDeviceQueueCreateInfo* pQueueCreateInfos; + uint32_t enabledLayerCount; + const char* const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char* const* ppEnabledExtensionNames; + const VkPhysicalDeviceFeatures* pEnabledFeatures; +} VkDeviceCreateInfo; + +typedef struct VkExtensionProperties { + char extensionName[VK_MAX_EXTENSION_NAME_SIZE]; + uint32_t specVersion; +} VkExtensionProperties; + +typedef struct VkLayerProperties { + char layerName[VK_MAX_EXTENSION_NAME_SIZE]; + uint32_t specVersion; + uint32_t implementationVersion; + char description[VK_MAX_DESCRIPTION_SIZE]; +} VkLayerProperties; + +typedef struct VkSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + const VkPipelineStageFlags* pWaitDstStageMask; + uint32_t commandBufferCount; + const VkCommandBuffer* pCommandBuffers; + uint32_t signalSemaphoreCount; + const VkSemaphore* pSignalSemaphores; +} VkSubmitInfo; + +typedef struct VkMemoryAllocateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeIndex; +} VkMemoryAllocateInfo; + +typedef struct VkMappedMemoryRange { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMappedMemoryRange; + +typedef struct VkMemoryRequirements { + VkDeviceSize size; + VkDeviceSize alignment; + uint32_t memoryTypeBits; +} VkMemoryRequirements; + +typedef struct VkSparseImageFormatProperties { + VkImageAspectFlags aspectMask; + VkExtent3D imageGranularity; + VkSparseImageFormatFlags flags; +} VkSparseImageFormatProperties; + +typedef struct VkSparseImageMemoryRequirements { + VkSparseImageFormatProperties formatProperties; + uint32_t imageMipTailFirstLod; + VkDeviceSize imageMipTailSize; + VkDeviceSize imageMipTailOffset; + VkDeviceSize imageMipTailStride; +} VkSparseImageMemoryRequirements; + +typedef struct VkSparseMemoryBind { + VkDeviceSize resourceOffset; + VkDeviceSize size; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseMemoryBind; + +typedef struct VkSparseBufferMemoryBindInfo { + VkBuffer buffer; + uint32_t bindCount; + const VkSparseMemoryBind* pBinds; +} VkSparseBufferMemoryBindInfo; + +typedef struct VkSparseImageOpaqueMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseMemoryBind* pBinds; +} VkSparseImageOpaqueMemoryBindInfo; + +typedef struct VkImageSubresource { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t arrayLayer; +} VkImageSubresource; + +typedef struct VkOffset3D { + int32_t x; + int32_t y; + int32_t z; +} VkOffset3D; + +typedef struct VkSparseImageMemoryBind { + VkImageSubresource subresource; + VkOffset3D offset; + VkExtent3D extent; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseImageMemoryBind; + +typedef struct VkSparseImageMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseImageMemoryBind* pBinds; +} VkSparseImageMemoryBindInfo; + +typedef struct VkBindSparseInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + uint32_t bufferBindCount; + const VkSparseBufferMemoryBindInfo* pBufferBinds; + uint32_t imageOpaqueBindCount; + const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; + uint32_t imageBindCount; + const VkSparseImageMemoryBindInfo* pImageBinds; + uint32_t signalSemaphoreCount; + const VkSemaphore* pSignalSemaphores; +} VkBindSparseInfo; + +typedef struct VkFenceCreateInfo { + VkStructureType sType; + const void* pNext; + VkFenceCreateFlags flags; +} VkFenceCreateInfo; + +typedef struct VkSemaphoreCreateInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreCreateFlags flags; +} VkSemaphoreCreateInfo; + +typedef struct VkEventCreateInfo { + VkStructureType sType; + const void* pNext; + VkEventCreateFlags flags; +} VkEventCreateInfo; + +typedef struct VkQueryPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkQueryPoolCreateFlags flags; + VkQueryType queryType; + uint32_t queryCount; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkQueryPoolCreateInfo; + +typedef struct VkBufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkBufferCreateFlags flags; + VkDeviceSize size; + VkBufferUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; +} VkBufferCreateInfo; + +typedef struct VkBufferViewCreateInfo { + VkStructureType sType; + const void* pNext; + VkBufferViewCreateFlags flags; + VkBuffer buffer; + VkFormat format; + VkDeviceSize offset; + VkDeviceSize range; +} VkBufferViewCreateInfo; + +typedef struct VkImageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageCreateFlags flags; + VkImageType imageType; + VkFormat format; + VkExtent3D extent; + uint32_t mipLevels; + uint32_t arrayLayers; + VkSampleCountFlagBits samples; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; + VkImageLayout initialLayout; +} VkImageCreateInfo; + +typedef struct VkSubresourceLayout { + VkDeviceSize offset; + VkDeviceSize size; + VkDeviceSize rowPitch; + VkDeviceSize arrayPitch; + VkDeviceSize depthPitch; +} VkSubresourceLayout; + +typedef struct VkComponentMapping { + VkComponentSwizzle r; + VkComponentSwizzle g; + VkComponentSwizzle b; + VkComponentSwizzle a; +} VkComponentMapping; + +typedef struct VkImageSubresourceRange { + VkImageAspectFlags aspectMask; + uint32_t baseMipLevel; + uint32_t levelCount; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceRange; + +typedef struct VkImageViewCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageViewCreateFlags flags; + VkImage image; + VkImageViewType viewType; + VkFormat format; + VkComponentMapping components; + VkImageSubresourceRange subresourceRange; +} VkImageViewCreateInfo; + +typedef struct VkShaderModuleCreateInfo { + VkStructureType sType; + const void* pNext; + VkShaderModuleCreateFlags flags; + size_t codeSize; + const uint32_t* pCode; +} VkShaderModuleCreateInfo; + +typedef struct VkPipelineCacheCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCacheCreateFlags flags; + size_t initialDataSize; + const void* pInitialData; +} VkPipelineCacheCreateInfo; + +typedef struct VkSpecializationMapEntry { + uint32_t constantID; + uint32_t offset; + size_t size; +} VkSpecializationMapEntry; + +typedef struct VkSpecializationInfo { + uint32_t mapEntryCount; + const VkSpecializationMapEntry* pMapEntries; + size_t dataSize; + const void* pData; +} VkSpecializationInfo; + +typedef struct VkPipelineShaderStageCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineShaderStageCreateFlags flags; + VkShaderStageFlagBits stage; + VkShaderModule module; + const char* pName; + const VkSpecializationInfo* pSpecializationInfo; +} VkPipelineShaderStageCreateInfo; + +typedef struct VkVertexInputBindingDescription { + uint32_t binding; + uint32_t stride; + VkVertexInputRate inputRate; +} VkVertexInputBindingDescription; + +typedef struct VkVertexInputAttributeDescription { + uint32_t location; + uint32_t binding; + VkFormat format; + uint32_t offset; +} VkVertexInputAttributeDescription; + +typedef struct VkPipelineVertexInputStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineVertexInputStateCreateFlags flags; + uint32_t vertexBindingDescriptionCount; + const VkVertexInputBindingDescription* pVertexBindingDescriptions; + uint32_t vertexAttributeDescriptionCount; + const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; +} VkPipelineVertexInputStateCreateInfo; + +typedef struct VkPipelineInputAssemblyStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineInputAssemblyStateCreateFlags flags; + VkPrimitiveTopology topology; + VkBool32 primitiveRestartEnable; +} VkPipelineInputAssemblyStateCreateInfo; + +typedef struct VkPipelineTessellationStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineTessellationStateCreateFlags flags; + uint32_t patchControlPoints; +} VkPipelineTessellationStateCreateInfo; + +typedef struct VkViewport { + float x; + float y; + float width; + float height; + float minDepth; + float maxDepth; +} VkViewport; + +typedef struct VkOffset2D { + int32_t x; + int32_t y; +} VkOffset2D; + +typedef struct VkExtent2D { + uint32_t width; + uint32_t height; +} VkExtent2D; + +typedef struct VkRect2D { + VkOffset2D offset; + VkExtent2D extent; +} VkRect2D; + +typedef struct VkPipelineViewportStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineViewportStateCreateFlags flags; + uint32_t viewportCount; + const VkViewport* pViewports; + uint32_t scissorCount; + const VkRect2D* pScissors; +} VkPipelineViewportStateCreateInfo; + +typedef struct VkPipelineRasterizationStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationStateCreateFlags flags; + VkBool32 depthClampEnable; + VkBool32 rasterizerDiscardEnable; + VkPolygonMode polygonMode; + VkCullModeFlags cullMode; + VkFrontFace frontFace; + VkBool32 depthBiasEnable; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; + float lineWidth; +} VkPipelineRasterizationStateCreateInfo; + +typedef struct VkPipelineMultisampleStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineMultisampleStateCreateFlags flags; + VkSampleCountFlagBits rasterizationSamples; + VkBool32 sampleShadingEnable; + float minSampleShading; + const VkSampleMask* pSampleMask; + VkBool32 alphaToCoverageEnable; + VkBool32 alphaToOneEnable; +} VkPipelineMultisampleStateCreateInfo; + +typedef struct VkStencilOpState { + VkStencilOp failOp; + VkStencilOp passOp; + VkStencilOp depthFailOp; + VkCompareOp compareOp; + uint32_t compareMask; + uint32_t writeMask; + uint32_t reference; +} VkStencilOpState; + +typedef struct VkPipelineDepthStencilStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineDepthStencilStateCreateFlags flags; + VkBool32 depthTestEnable; + VkBool32 depthWriteEnable; + VkCompareOp depthCompareOp; + VkBool32 depthBoundsTestEnable; + VkBool32 stencilTestEnable; + VkStencilOpState front; + VkStencilOpState back; + float minDepthBounds; + float maxDepthBounds; +} VkPipelineDepthStencilStateCreateInfo; + +typedef struct VkPipelineColorBlendAttachmentState { + VkBool32 blendEnable; + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; + VkColorComponentFlags colorWriteMask; +} VkPipelineColorBlendAttachmentState; + +typedef struct VkPipelineColorBlendStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineColorBlendStateCreateFlags flags; + VkBool32 logicOpEnable; + VkLogicOp logicOp; + uint32_t attachmentCount; + const VkPipelineColorBlendAttachmentState* pAttachments; + float blendConstants[4]; +} VkPipelineColorBlendStateCreateInfo; + +typedef struct VkPipelineDynamicStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineDynamicStateCreateFlags flags; + uint32_t dynamicStateCount; + const VkDynamicState* pDynamicStates; +} VkPipelineDynamicStateCreateInfo; + +typedef struct VkGraphicsPipelineCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + const VkPipelineVertexInputStateCreateInfo* pVertexInputState; + const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; + const VkPipelineTessellationStateCreateInfo* pTessellationState; + const VkPipelineViewportStateCreateInfo* pViewportState; + const VkPipelineRasterizationStateCreateInfo* pRasterizationState; + const VkPipelineMultisampleStateCreateInfo* pMultisampleState; + const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; + const VkPipelineColorBlendStateCreateInfo* pColorBlendState; + const VkPipelineDynamicStateCreateInfo* pDynamicState; + VkPipelineLayout layout; + VkRenderPass renderPass; + uint32_t subpass; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkGraphicsPipelineCreateInfo; + +typedef struct VkComputePipelineCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + VkPipelineShaderStageCreateInfo stage; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkComputePipelineCreateInfo; + +typedef struct VkPushConstantRange { + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; +} VkPushConstantRange; + +typedef struct VkPipelineLayoutCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineLayoutCreateFlags flags; + uint32_t setLayoutCount; + const VkDescriptorSetLayout* pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange* pPushConstantRanges; +} VkPipelineLayoutCreateInfo; + +typedef struct VkSamplerCreateInfo { + VkStructureType sType; + const void* pNext; + VkSamplerCreateFlags flags; + VkFilter magFilter; + VkFilter minFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode addressModeU; + VkSamplerAddressMode addressModeV; + VkSamplerAddressMode addressModeW; + float mipLodBias; + VkBool32 anisotropyEnable; + float maxAnisotropy; + VkBool32 compareEnable; + VkCompareOp compareOp; + float minLod; + float maxLod; + VkBorderColor borderColor; + VkBool32 unnormalizedCoordinates; +} VkSamplerCreateInfo; + +typedef struct VkDescriptorSetLayoutBinding { + uint32_t binding; + VkDescriptorType descriptorType; + uint32_t descriptorCount; + VkShaderStageFlags stageFlags; + const VkSampler* pImmutableSamplers; +} VkDescriptorSetLayoutBinding; + +typedef struct VkDescriptorSetLayoutCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorSetLayoutCreateFlags flags; + uint32_t bindingCount; + const VkDescriptorSetLayoutBinding* pBindings; +} VkDescriptorSetLayoutCreateInfo; + +typedef struct VkDescriptorPoolSize { + VkDescriptorType type; + uint32_t descriptorCount; +} VkDescriptorPoolSize; + +typedef struct VkDescriptorPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorPoolCreateFlags flags; + uint32_t maxSets; + uint32_t poolSizeCount; + const VkDescriptorPoolSize* pPoolSizes; +} VkDescriptorPoolCreateInfo; + +typedef struct VkDescriptorSetAllocateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorPool descriptorPool; + uint32_t descriptorSetCount; + const VkDescriptorSetLayout* pSetLayouts; +} VkDescriptorSetAllocateInfo; + +typedef struct VkDescriptorImageInfo { + VkSampler sampler; + VkImageView imageView; + VkImageLayout imageLayout; +} VkDescriptorImageInfo; + +typedef struct VkDescriptorBufferInfo { + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize range; +} VkDescriptorBufferInfo; + +typedef struct VkWriteDescriptorSet { + VkStructureType sType; + const void* pNext; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + const VkDescriptorImageInfo* pImageInfo; + const VkDescriptorBufferInfo* pBufferInfo; + const VkBufferView* pTexelBufferView; +} VkWriteDescriptorSet; + +typedef struct VkCopyDescriptorSet { + VkStructureType sType; + const void* pNext; + VkDescriptorSet srcSet; + uint32_t srcBinding; + uint32_t srcArrayElement; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; +} VkCopyDescriptorSet; + +typedef struct VkFramebufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkFramebufferCreateFlags flags; + VkRenderPass renderPass; + uint32_t attachmentCount; + const VkImageView* pAttachments; + uint32_t width; + uint32_t height; + uint32_t layers; +} VkFramebufferCreateInfo; + +typedef struct VkAttachmentDescription { + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription; + +typedef struct VkAttachmentReference { + uint32_t attachment; + VkImageLayout layout; +} VkAttachmentReference; + +typedef struct VkSubpassDescription { + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t inputAttachmentCount; + const VkAttachmentReference* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference* pColorAttachments; + const VkAttachmentReference* pResolveAttachments; + const VkAttachmentReference* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription; + +typedef struct VkSubpassDependency { + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; +} VkSubpassDependency; + +typedef struct VkRenderPassCreateInfo { + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency* pDependencies; +} VkRenderPassCreateInfo; + +typedef struct VkCommandPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkCommandPoolCreateFlags flags; + uint32_t queueFamilyIndex; +} VkCommandPoolCreateInfo; + +typedef struct VkCommandBufferAllocateInfo { + VkStructureType sType; + const void* pNext; + VkCommandPool commandPool; + VkCommandBufferLevel level; + uint32_t commandBufferCount; +} VkCommandBufferAllocateInfo; + +typedef struct VkCommandBufferInheritanceInfo { + VkStructureType sType; + const void* pNext; + VkRenderPass renderPass; + uint32_t subpass; + VkFramebuffer framebuffer; + VkBool32 occlusionQueryEnable; + VkQueryControlFlags queryFlags; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkCommandBufferInheritanceInfo; + +typedef struct VkCommandBufferBeginInfo { + VkStructureType sType; + const void* pNext; + VkCommandBufferUsageFlags flags; + const VkCommandBufferInheritanceInfo* pInheritanceInfo; +} VkCommandBufferBeginInfo; + +typedef struct VkBufferCopy { + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy; + +typedef struct VkImageSubresourceLayers { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceLayers; + +typedef struct VkImageCopy { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy; + +typedef struct VkImageBlit { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets[2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets[2]; +} VkImageBlit; + +typedef struct VkBufferImageCopy { + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy; + +typedef union VkClearColorValue { + float float32[4]; + int32_t int32[4]; + uint32_t uint32[4]; +} VkClearColorValue; + +typedef struct VkClearDepthStencilValue { + float depth; + uint32_t stencil; +} VkClearDepthStencilValue; + +typedef union VkClearValue { + VkClearColorValue color; + VkClearDepthStencilValue depthStencil; +} VkClearValue; + +typedef struct VkClearAttachment { + VkImageAspectFlags aspectMask; + uint32_t colorAttachment; + VkClearValue clearValue; +} VkClearAttachment; + +typedef struct VkClearRect { + VkRect2D rect; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkClearRect; + +typedef struct VkImageResolve { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve; + +typedef struct VkMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; +} VkMemoryBarrier; + +typedef struct VkBufferMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier; + +typedef struct VkImageMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier; + +typedef struct VkRenderPassBeginInfo { + VkStructureType sType; + const void* pNext; + VkRenderPass renderPass; + VkFramebuffer framebuffer; + VkRect2D renderArea; + uint32_t clearValueCount; + const VkClearValue* pClearValues; +} VkRenderPassBeginInfo; + +typedef struct VkDispatchIndirectCommand { + uint32_t x; + uint32_t y; + uint32_t z; +} VkDispatchIndirectCommand; + +typedef struct VkDrawIndexedIndirectCommand { + uint32_t indexCount; + uint32_t instanceCount; + uint32_t firstIndex; + int32_t vertexOffset; + uint32_t firstInstance; +} VkDrawIndexedIndirectCommand; + +typedef struct VkDrawIndirectCommand { + uint32_t vertexCount; + uint32_t instanceCount; + uint32_t firstVertex; + uint32_t firstInstance; +} VkDrawIndirectCommand; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); +typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); +typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); +typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); +typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); +typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); +typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); +typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); +typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences); +typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); +typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); +typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); +typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); +typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); +typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); +typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); +typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); +typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); +typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); +typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); +typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); +typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); +typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); +typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); +typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); +typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); +typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); +typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); +typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); +typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer); +typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); +typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); +typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); +typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); +typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); +typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); +typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); +typedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); +typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); +typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( + const VkInstanceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkInstance* pInstance); + +VKAPI_ATTR void VKAPI_CALL vkDestroyInstance( + VkInstance instance, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices( + VkInstance instance, + uint32_t* pPhysicalDeviceCount, + VkPhysicalDevice* pPhysicalDevices); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags, + VkImageFormatProperties* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties* pMemoryProperties); + +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr( + VkInstance instance, + const char* pName); + +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr( + VkDevice device, + const char* pName); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice( + VkPhysicalDevice physicalDevice, + const VkDeviceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDevice* pDevice); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDevice( + VkDevice device, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties( + const char* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties( + VkPhysicalDevice physicalDevice, + const char* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( + uint32_t* pPropertyCount, + VkLayerProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkLayerProperties* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue( + VkDevice device, + uint32_t queueFamilyIndex, + uint32_t queueIndex, + VkQueue* pQueue); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit( + VkQueue queue, + uint32_t submitCount, + const VkSubmitInfo* pSubmits, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle( + VkQueue queue); + +VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle( + VkDevice device); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory( + VkDevice device, + const VkMemoryAllocateInfo* pAllocateInfo, + const VkAllocationCallbacks* pAllocator, + VkDeviceMemory* pMemory); + +VKAPI_ATTR void VKAPI_CALL vkFreeMemory( + VkDevice device, + VkDeviceMemory memory, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory( + VkDevice device, + VkDeviceMemory memory, + VkDeviceSize offset, + VkDeviceSize size, + VkMemoryMapFlags flags, + void** ppData); + +VKAPI_ATTR void VKAPI_CALL vkUnmapMemory( + VkDevice device, + VkDeviceMemory memory); + +VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges( + VkDevice device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange* pMemoryRanges); + +VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges( + VkDevice device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange* pMemoryRanges); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment( + VkDevice device, + VkDeviceMemory memory, + VkDeviceSize* pCommittedMemoryInBytes); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory( + VkDevice device, + VkBuffer buffer, + VkDeviceMemory memory, + VkDeviceSize memoryOffset); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory( + VkDevice device, + VkImage image, + VkDeviceMemory memory, + VkDeviceSize memoryOffset); + +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements( + VkDevice device, + VkBuffer buffer, + VkMemoryRequirements* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements( + VkDevice device, + VkImage image, + VkMemoryRequirements* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements( + VkDevice device, + VkImage image, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements* pSparseMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkSampleCountFlagBits samples, + VkImageUsageFlags usage, + VkImageTiling tiling, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse( + VkQueue queue, + uint32_t bindInfoCount, + const VkBindSparseInfo* pBindInfo, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence( + VkDevice device, + const VkFenceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); + +VKAPI_ATTR void VKAPI_CALL vkDestroyFence( + VkDevice device, + VkFence fence, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetFences( + VkDevice device, + uint32_t fenceCount, + const VkFence* pFences); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus( + VkDevice device, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences( + VkDevice device, + uint32_t fenceCount, + const VkFence* pFences, + VkBool32 waitAll, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore( + VkDevice device, + const VkSemaphoreCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSemaphore* pSemaphore); + +VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore( + VkDevice device, + VkSemaphore semaphore, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent( + VkDevice device, + const VkEventCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkEvent* pEvent); + +VKAPI_ATTR void VKAPI_CALL vkDestroyEvent( + VkDevice device, + VkEvent event, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool( + VkDevice device, + const VkQueryPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkQueryPool* pQueryPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool( + VkDevice device, + VkQueryPool queryPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + size_t dataSize, + void* pData, + VkDeviceSize stride, + VkQueryResultFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer( + VkDevice device, + const VkBufferCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBuffer* pBuffer); + +VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer( + VkDevice device, + VkBuffer buffer, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView( + VkDevice device, + const VkBufferViewCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBufferView* pView); + +VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView( + VkDevice device, + VkBufferView bufferView, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage( + VkDevice device, + const VkImageCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkImage* pImage); + +VKAPI_ATTR void VKAPI_CALL vkDestroyImage( + VkDevice device, + VkImage image, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout( + VkDevice device, + VkImage image, + const VkImageSubresource* pSubresource, + VkSubresourceLayout* pLayout); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView( + VkDevice device, + const VkImageViewCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkImageView* pView); + +VKAPI_ATTR void VKAPI_CALL vkDestroyImageView( + VkDevice device, + VkImageView imageView, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule( + VkDevice device, + const VkShaderModuleCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkShaderModule* pShaderModule); + +VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule( + VkDevice device, + VkShaderModule shaderModule, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache( + VkDevice device, + const VkPipelineCacheCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineCache* pPipelineCache); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache( + VkDevice device, + VkPipelineCache pipelineCache, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData( + VkDevice device, + VkPipelineCache pipelineCache, + size_t* pDataSize, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches( + VkDevice device, + VkPipelineCache dstCache, + uint32_t srcCacheCount, + const VkPipelineCache* pSrcCaches); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkGraphicsPipelineCreateInfo* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkComputePipelineCreateInfo* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline( + VkDevice device, + VkPipeline pipeline, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout( + VkDevice device, + const VkPipelineLayoutCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineLayout* pPipelineLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout( + VkDevice device, + VkPipelineLayout pipelineLayout, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler( + VkDevice device, + const VkSamplerCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSampler* pSampler); + +VKAPI_ATTR void VKAPI_CALL vkDestroySampler( + VkDevice device, + VkSampler sampler, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorSetLayout* pSetLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout( + VkDevice device, + VkDescriptorSetLayout descriptorSetLayout, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool( + VkDevice device, + const VkDescriptorPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorPool* pDescriptorPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool( + VkDevice device, + VkDescriptorPool descriptorPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool( + VkDevice device, + VkDescriptorPool descriptorPool, + VkDescriptorPoolResetFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets( + VkDevice device, + const VkDescriptorSetAllocateInfo* pAllocateInfo, + VkDescriptorSet* pDescriptorSets); + +VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets( + VkDevice device, + VkDescriptorPool descriptorPool, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets); + +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets( + VkDevice device, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet* pDescriptorWrites, + uint32_t descriptorCopyCount, + const VkCopyDescriptorSet* pDescriptorCopies); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer( + VkDevice device, + const VkFramebufferCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkFramebuffer* pFramebuffer); + +VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer( + VkDevice device, + VkFramebuffer framebuffer, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass( + VkDevice device, + const VkRenderPassCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass( + VkDevice device, + VkRenderPass renderPass, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity( + VkDevice device, + VkRenderPass renderPass, + VkExtent2D* pGranularity); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool( + VkDevice device, + const VkCommandPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCommandPool* pCommandPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool( + VkDevice device, + VkCommandPool commandPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolResetFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers( + VkDevice device, + const VkCommandBufferAllocateInfo* pAllocateInfo, + VkCommandBuffer* pCommandBuffers); + +VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers( + VkDevice device, + VkCommandPool commandPool, + uint32_t commandBufferCount, + const VkCommandBuffer* pCommandBuffers); + +VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer( + VkCommandBuffer commandBuffer, + const VkCommandBufferBeginInfo* pBeginInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer( + VkCommandBuffer commandBuffer, + VkCommandBufferResetFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewport( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkViewport* pViewports); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetScissor( + VkCommandBuffer commandBuffer, + uint32_t firstScissor, + uint32_t scissorCount, + const VkRect2D* pScissors); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth( + VkCommandBuffer commandBuffer, + float lineWidth); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias( + VkCommandBuffer commandBuffer, + float depthBiasConstantFactor, + float depthBiasClamp, + float depthBiasSlopeFactor); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants( + VkCommandBuffer commandBuffer, + const float blendConstants[4]); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds( + VkCommandBuffer commandBuffer, + float minDepthBounds, + float maxDepthBounds); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t compareMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t writeMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t reference); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t* pDynamicOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkIndexType indexType); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdDraw( + VkCommandBuffer commandBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed( + VkCommandBuffer commandBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatch( + VkCommandBuffer commandBuffer, + uint32_t x, + uint32_t y, + uint32_t z); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer( + VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageBlit* pRegions, + VkFilter filter); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage( + VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer( + VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize dataSize, + const void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer( + VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize size, + uint32_t data); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage( + VkCommandBuffer commandBuffer, + VkImage image, + VkImageLayout imageLayout, + const VkClearColorValue* pColor, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage( + VkCommandBuffer commandBuffer, + VkImage image, + VkImageLayout imageLayout, + const VkClearDepthStencilValue* pDepthStencil, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments( + VkCommandBuffer commandBuffer, + uint32_t attachmentCount, + const VkClearAttachment* pAttachments, + uint32_t rectCount, + const VkClearRect* pRects); + +VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageResolve* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers); + +VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp( + VkCommandBuffer commandBuffer, + VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize stride, + VkQueryResultFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants( + VkCommandBuffer commandBuffer, + VkPipelineLayout layout, + VkShaderStageFlags stageFlags, + uint32_t offset, + uint32_t size, + const void* pValues); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + VkSubpassContents contents); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass( + VkCommandBuffer commandBuffer, + VkSubpassContents contents); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands( + VkCommandBuffer commandBuffer, + uint32_t commandBufferCount, + const VkCommandBuffer* pCommandBuffers); +#endif + +#define VK_KHR_surface 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) + +#define VK_KHR_SURFACE_SPEC_VERSION 25 +#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" +#define VK_COLORSPACE_SRGB_NONLINEAR_KHR VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + + +typedef enum VkColorSpaceKHR { + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, + VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104001, + VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104002, + VK_COLOR_SPACE_SCRGB_LINEAR_EXT = 1000104003, + VK_COLOR_SPACE_SCRGB_NONLINEAR_EXT = 1000104004, + VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104005, + VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104006, + VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104007, + VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104008, + VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104009, + VK_COLOR_SPACE_BT2020_NONLINEAR_EXT = 1000104010, + VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, + VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, + VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1), + VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkColorSpaceKHR; + +typedef enum VkPresentModeKHR { + VK_PRESENT_MODE_IMMEDIATE_KHR = 0, + VK_PRESENT_MODE_MAILBOX_KHR = 1, + VK_PRESENT_MODE_FIFO_KHR = 2, + VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, + VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR, + VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR, + VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1), + VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPresentModeKHR; + + +typedef enum VkSurfaceTransformFlagBitsKHR { + VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, + VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, + VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, + VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, + VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, + VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkSurfaceTransformFlagBitsKHR; +typedef VkFlags VkSurfaceTransformFlagsKHR; + +typedef enum VkCompositeAlphaFlagBitsKHR { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, + VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkCompositeAlphaFlagBitsKHR; +typedef VkFlags VkCompositeAlphaFlagsKHR; + +typedef struct VkSurfaceCapabilitiesKHR { + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; +} VkSurfaceCapabilitiesKHR; + +typedef struct VkSurfaceFormatKHR { + VkFormat format; + VkColorSpaceKHR colorSpace; +} VkSurfaceFormatKHR; + + +typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR( + VkInstance instance, + VkSurfaceKHR surface, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + VkSurfaceKHR surface, + VkBool32* pSupported); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormatKHR* pSurfaceFormats); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pPresentModeCount, + VkPresentModeKHR* pPresentModes); +#endif + +#define VK_KHR_swapchain 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) + +#define VK_KHR_SWAPCHAIN_SPEC_VERSION 68 +#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" + +typedef VkFlags VkSwapchainCreateFlagsKHR; + +typedef struct VkSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainCreateFlagsKHR flags; + VkSurfaceKHR surface; + uint32_t minImageCount; + VkFormat imageFormat; + VkColorSpaceKHR imageColorSpace; + VkExtent2D imageExtent; + uint32_t imageArrayLayers; + VkImageUsageFlags imageUsage; + VkSharingMode imageSharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; + VkSurfaceTransformFlagBitsKHR preTransform; + VkCompositeAlphaFlagBitsKHR compositeAlpha; + VkPresentModeKHR presentMode; + VkBool32 clipped; + VkSwapchainKHR oldSwapchain; +} VkSwapchainCreateInfoKHR; + +typedef struct VkPresentInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + uint32_t swapchainCount; + const VkSwapchainKHR* pSwapchains; + const uint32_t* pImageIndices; + VkResult* pResults; +} VkPresentInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); +typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); +typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( + VkDevice device, + const VkSwapchainCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSwapchainKHR* pSwapchain); + +VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR( + VkDevice device, + VkSwapchainKHR swapchain, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pSwapchainImageCount, + VkImage* pSwapchainImages); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint64_t timeout, + VkSemaphore semaphore, + VkFence fence, + uint32_t* pImageIndex); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR( + VkQueue queue, + const VkPresentInfoKHR* pPresentInfo); +#endif + +#define VK_KHR_display 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) + +#define VK_KHR_DISPLAY_SPEC_VERSION 21 +#define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display" + + +typedef enum VkDisplayPlaneAlphaFlagBitsKHR { + VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, + VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, + VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDisplayPlaneAlphaFlagBitsKHR; +typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; +typedef VkFlags VkDisplayModeCreateFlagsKHR; +typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; + +typedef struct VkDisplayPropertiesKHR { + VkDisplayKHR display; + const char* displayName; + VkExtent2D physicalDimensions; + VkExtent2D physicalResolution; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkBool32 planeReorderPossible; + VkBool32 persistentContent; +} VkDisplayPropertiesKHR; + +typedef struct VkDisplayModeParametersKHR { + VkExtent2D visibleRegion; + uint32_t refreshRate; +} VkDisplayModeParametersKHR; + +typedef struct VkDisplayModePropertiesKHR { + VkDisplayModeKHR displayMode; + VkDisplayModeParametersKHR parameters; +} VkDisplayModePropertiesKHR; + +typedef struct VkDisplayModeCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDisplayModeCreateFlagsKHR flags; + VkDisplayModeParametersKHR parameters; +} VkDisplayModeCreateInfoKHR; + +typedef struct VkDisplayPlaneCapabilitiesKHR { + VkDisplayPlaneAlphaFlagsKHR supportedAlpha; + VkOffset2D minSrcPosition; + VkOffset2D maxSrcPosition; + VkExtent2D minSrcExtent; + VkExtent2D maxSrcExtent; + VkOffset2D minDstPosition; + VkOffset2D maxDstPosition; + VkExtent2D minDstExtent; + VkExtent2D maxDstExtent; +} VkDisplayPlaneCapabilitiesKHR; + +typedef struct VkDisplayPlanePropertiesKHR { + VkDisplayKHR currentDisplay; + uint32_t currentStackIndex; +} VkDisplayPlanePropertiesKHR; + +typedef struct VkDisplaySurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDisplaySurfaceCreateFlagsKHR flags; + VkDisplayModeKHR displayMode; + uint32_t planeIndex; + uint32_t planeStackIndex; + VkSurfaceTransformFlagBitsKHR transform; + float globalAlpha; + VkDisplayPlaneAlphaFlagBitsKHR alphaMode; + VkExtent2D imageExtent; +} VkDisplaySurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPlanePropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR( + VkPhysicalDevice physicalDevice, + uint32_t planeIndex, + uint32_t* pDisplayCount, + VkDisplayKHR* pDisplays); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t* pPropertyCount, + VkDisplayModePropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + const VkDisplayModeCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDisplayModeKHR* pMode); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + VkDisplayModeKHR mode, + uint32_t planeIndex, + VkDisplayPlaneCapabilitiesKHR* pCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR( + VkInstance instance, + const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#define VK_KHR_display_swapchain 1 +#define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9 +#define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain" + +typedef struct VkDisplayPresentInfoKHR { + VkStructureType sType; + const void* pNext; + VkRect2D srcRect; + VkRect2D dstRect; + VkBool32 persistent; +} VkDisplayPresentInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR( + VkDevice device, + uint32_t swapchainCount, + const VkSwapchainCreateInfoKHR* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkSwapchainKHR* pSwapchains); +#endif + +#ifdef VK_USE_PLATFORM_XLIB_KHR +#define VK_KHR_xlib_surface 1 +#include + +#define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface" + +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; + +typedef struct VkXlibSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR( + VkInstance instance, + const VkXlibSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + Display* dpy, + VisualID visualID); +#endif +#endif /* VK_USE_PLATFORM_XLIB_KHR */ + +#ifdef VK_USE_PLATFORM_XCB_KHR +#define VK_KHR_xcb_surface 1 +#include + +#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" + +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; + +typedef struct VkXcbSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR( + VkInstance instance, + const VkXcbSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + xcb_connection_t* connection, + xcb_visualid_t visual_id); +#endif +#endif /* VK_USE_PLATFORM_XCB_KHR */ + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +#define VK_KHR_wayland_surface 1 +#include + +#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 5 +#define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface" + +typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; + +typedef struct VkWaylandSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display* display; + struct wl_surface* surface; +} VkWaylandSurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR( + VkInstance instance, + const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + struct wl_display* display); +#endif +#endif /* VK_USE_PLATFORM_WAYLAND_KHR */ + +#ifdef VK_USE_PLATFORM_MIR_KHR +#define VK_KHR_mir_surface 1 +#include + +#define VK_KHR_MIR_SURFACE_SPEC_VERSION 4 +#define VK_KHR_MIR_SURFACE_EXTENSION_NAME "VK_KHR_mir_surface" + +typedef VkFlags VkMirSurfaceCreateFlagsKHR; + +typedef struct VkMirSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkMirSurfaceCreateFlagsKHR flags; + MirConnection* connection; + MirSurface* mirSurface; +} VkMirSurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateMirSurfaceKHR)(VkInstance instance, const VkMirSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, MirConnection* connection); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateMirSurfaceKHR( + VkInstance instance, + const VkMirSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceMirPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + MirConnection* connection); +#endif +#endif /* VK_USE_PLATFORM_MIR_KHR */ + +#ifdef VK_USE_PLATFORM_ANDROID_KHR +#define VK_KHR_android_surface 1 +#include + +#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 +#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface" + +typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; + +typedef struct VkAndroidSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkAndroidSurfaceCreateFlagsKHR flags; + ANativeWindow* window; +} VkAndroidSurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR( + VkInstance instance, + const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif /* VK_USE_PLATFORM_ANDROID_KHR */ + +#ifdef VK_USE_PLATFORM_WIN32_KHR +#define VK_KHR_win32_surface 1 +#include + +#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 5 +#define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface" + +typedef VkFlags VkWin32SurfaceCreateFlagsKHR; + +typedef struct VkWin32SurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; +} VkWin32SurfaceCreateInfoKHR; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR( + VkInstance instance, + const VkWin32SurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex); +#endif +#endif /* VK_USE_PLATFORM_WIN32_KHR */ + +#define VK_KHR_sampler_mirror_clamp_to_edge 1 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" + + +#define VK_KHR_get_physical_device_properties2 1 +#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1 +#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" + +typedef struct VkPhysicalDeviceFeatures2KHR { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceFeatures features; +} VkPhysicalDeviceFeatures2KHR; + +typedef struct VkPhysicalDeviceProperties2KHR { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceProperties properties; +} VkPhysicalDeviceProperties2KHR; + +typedef struct VkFormatProperties2KHR { + VkStructureType sType; + void* pNext; + VkFormatProperties formatProperties; +} VkFormatProperties2KHR; + +typedef struct VkImageFormatProperties2KHR { + VkStructureType sType; + void* pNext; + VkImageFormatProperties imageFormatProperties; +} VkImageFormatProperties2KHR; + +typedef struct VkPhysicalDeviceImageFormatInfo2KHR { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkImageType type; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkImageCreateFlags flags; +} VkPhysicalDeviceImageFormatInfo2KHR; + +typedef struct VkQueueFamilyProperties2KHR { + VkStructureType sType; + void* pNext; + VkQueueFamilyProperties queueFamilyProperties; +} VkQueueFamilyProperties2KHR; + +typedef struct VkPhysicalDeviceMemoryProperties2KHR { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceMemoryProperties memoryProperties; +} VkPhysicalDeviceMemoryProperties2KHR; + +typedef struct VkSparseImageFormatProperties2KHR { + VkStructureType sType; + void* pNext; + VkSparseImageFormatProperties properties; +} VkSparseImageFormatProperties2KHR; + +typedef struct VkPhysicalDeviceSparseImageFormatInfo2KHR { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkImageType type; + VkSampleCountFlagBits samples; + VkImageUsageFlags usage; + VkImageTiling tiling; +} VkPhysicalDeviceSparseImageFormatInfo2KHR; + + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2KHR* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2KHR* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, VkImageFormatProperties2KHR* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2KHR* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2KHR* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2KHR* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties2KHR* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, + VkImageFormatProperties2KHR* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties2KHR* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties2KHR* pProperties); +#endif + +#define VK_KHR_shader_draw_parameters 1 +#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1 +#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters" + + +#define VK_KHR_maintenance1 1 +#define VK_KHR_MAINTENANCE1_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" + +typedef VkFlags VkCommandPoolTrimFlagsKHR; + +typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlagsKHR flags); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolTrimFlagsKHR flags); +#endif + +#define VK_EXT_debug_report 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) + +#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 4 +#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" +#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT + + +typedef enum VkDebugReportObjectTypeEXT { + VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, + VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, + VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, + VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, + VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, + VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, + VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, + VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, + VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, + VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, + VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, + VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, + VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, + VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28, + VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29, + VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, + VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31, + VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32, + VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1), + VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportObjectTypeEXT; + +typedef enum VkDebugReportErrorEXT { + VK_DEBUG_REPORT_ERROR_NONE_EXT = 0, + VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1, + VK_DEBUG_REPORT_ERROR_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_ERROR_NONE_EXT, + VK_DEBUG_REPORT_ERROR_END_RANGE_EXT = VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, + VK_DEBUG_REPORT_ERROR_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT - VK_DEBUG_REPORT_ERROR_NONE_EXT + 1), + VK_DEBUG_REPORT_ERROR_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportErrorEXT; + + +typedef enum VkDebugReportFlagBitsEXT { + VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, + VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, + VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, + VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, + VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, + VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportFlagBitsEXT; +typedef VkFlags VkDebugReportFlagsEXT; + +typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData); + + +typedef struct VkDebugReportCallbackCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportFlagsEXT flags; + PFN_vkDebugReportCallbackEXT pfnCallback; + void* pUserData; +} VkDebugReportCallbackCreateInfoEXT; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); +typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT( + VkInstance instance, + const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugReportCallbackEXT* pCallback); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT( + VkInstance instance, + VkDebugReportCallbackEXT callback, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( + VkInstance instance, + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage); +#endif + +#define VK_NV_glsl_shader 1 +#define VK_NV_GLSL_SHADER_SPEC_VERSION 1 +#define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" + + +#define VK_IMG_filter_cubic 1 +#define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 +#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" + + +#define VK_AMD_rasterization_order 1 +#define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1 +#define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME "VK_AMD_rasterization_order" + + +typedef enum VkRasterizationOrderAMD { + VK_RASTERIZATION_ORDER_STRICT_AMD = 0, + VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, + VK_RASTERIZATION_ORDER_BEGIN_RANGE_AMD = VK_RASTERIZATION_ORDER_STRICT_AMD, + VK_RASTERIZATION_ORDER_END_RANGE_AMD = VK_RASTERIZATION_ORDER_RELAXED_AMD, + VK_RASTERIZATION_ORDER_RANGE_SIZE_AMD = (VK_RASTERIZATION_ORDER_RELAXED_AMD - VK_RASTERIZATION_ORDER_STRICT_AMD + 1), + VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF +} VkRasterizationOrderAMD; + +typedef struct VkPipelineRasterizationStateRasterizationOrderAMD { + VkStructureType sType; + const void* pNext; + VkRasterizationOrderAMD rasterizationOrder; +} VkPipelineRasterizationStateRasterizationOrderAMD; + + + +#define VK_AMD_shader_trinary_minmax 1 +#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1 +#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax" + + +#define VK_AMD_shader_explicit_vertex_parameter 1 +#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1 +#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter" + + +#define VK_EXT_debug_marker 1 +#define VK_EXT_DEBUG_MARKER_SPEC_VERSION 3 +#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker" + +typedef struct VkDebugMarkerObjectNameInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportObjectTypeEXT objectType; + uint64_t object; + const char* pObjectName; +} VkDebugMarkerObjectNameInfoEXT; + +typedef struct VkDebugMarkerObjectTagInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportObjectTypeEXT objectType; + uint64_t object; + uint64_t tagName; + size_t tagSize; + const void* pTag; +} VkDebugMarkerObjectTagInfoEXT; + +typedef struct VkDebugMarkerMarkerInfoEXT { + VkStructureType sType; + const void* pNext; + const char* pMarkerName; + float color[4]; +} VkDebugMarkerMarkerInfoEXT; + + +typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, VkDebugMarkerObjectTagInfoEXT* pTagInfo); +typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, VkDebugMarkerObjectNameInfoEXT* pNameInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT( + VkDevice device, + VkDebugMarkerObjectTagInfoEXT* pTagInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT( + VkDevice device, + VkDebugMarkerObjectNameInfoEXT* pNameInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT( + VkCommandBuffer commandBuffer, + VkDebugMarkerMarkerInfoEXT* pMarkerInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT( + VkCommandBuffer commandBuffer, + VkDebugMarkerMarkerInfoEXT* pMarkerInfo); +#endif + +#define VK_AMD_gcn_shader 1 +#define VK_AMD_GCN_SHADER_SPEC_VERSION 1 +#define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader" + + +#define VK_NV_dedicated_allocation 1 +#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1 +#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation" + +typedef struct VkDedicatedAllocationImageCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationImageCreateInfoNV; + +typedef struct VkDedicatedAllocationBufferCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationBufferCreateInfoNV; + +typedef struct VkDedicatedAllocationMemoryAllocateInfoNV { + VkStructureType sType; + const void* pNext; + VkImage image; + VkBuffer buffer; +} VkDedicatedAllocationMemoryAllocateInfoNV; + + + +#define VK_AMD_draw_indirect_count 1 +#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 +#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" + +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + +#define VK_AMD_negative_viewport_height 1 +#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1 +#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height" + + +#define VK_AMD_gpu_shader_half_float 1 +#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1 +#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float" + + +#define VK_AMD_shader_ballot 1 +#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1 +#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot" + + +#define VK_IMG_format_pvrtc 1 +#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 +#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" + + +#define VK_NV_external_memory_capabilities 1 +#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities" + + +typedef enum VkExternalMemoryHandleTypeFlagBitsNV { + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkExternalMemoryHandleTypeFlagBitsNV; +typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; + +typedef enum VkExternalMemoryFeatureFlagBitsNV { + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkExternalMemoryFeatureFlagBitsNV; +typedef VkFlags VkExternalMemoryFeatureFlagsNV; + +typedef struct VkExternalImageFormatPropertiesNV { + VkImageFormatProperties imageFormatProperties; + VkExternalMemoryFeatureFlagsNV externalMemoryFeatures; + VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes; +} VkExternalImageFormatPropertiesNV; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType, VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceExternalImageFormatPropertiesNV( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags, + VkExternalMemoryHandleTypeFlagsNV externalHandleType, + VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); +#endif + +#define VK_NV_external_memory 1 +#define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory" + +typedef struct VkExternalMemoryImageCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExternalMemoryImageCreateInfoNV; + +typedef struct VkExportMemoryAllocateInfoNV { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExportMemoryAllocateInfoNV; + + + +#ifdef VK_USE_PLATFORM_WIN32_KHR +#define VK_NV_external_memory_win32 1 +#define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32" + +typedef struct VkImportMemoryWin32HandleInfoNV { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagsNV handleType; + HANDLE handle; +} VkImportMemoryWin32HandleInfoNV; + +typedef struct VkExportMemoryWin32HandleInfoNV { + VkStructureType sType; + const void* pNext; + const SECURITY_ATTRIBUTES* pAttributes; + DWORD dwAccess; +} VkExportMemoryWin32HandleInfoNV; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleNV)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE* pHandle); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleNV( + VkDevice device, + VkDeviceMemory memory, + VkExternalMemoryHandleTypeFlagsNV handleType, + HANDLE* pHandle); +#endif +#endif /* VK_USE_PLATFORM_WIN32_KHR */ + +#ifdef VK_USE_PLATFORM_WIN32_KHR +#define VK_NV_win32_keyed_mutex 1 +#define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 1 +#define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex" + +typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t acquireCount; + const VkDeviceMemory* pAcquireSyncs; + const uint64_t* pAcquireKeys; + const uint32_t* pAcquireTimeoutMilliseconds; + uint32_t releaseCount; + const VkDeviceMemory* pReleaseSyncs; + const uint64_t* pReleaseKeys; +} VkWin32KeyedMutexAcquireReleaseInfoNV; + + +#endif /* VK_USE_PLATFORM_WIN32_KHR */ + +#define VK_EXT_validation_flags 1 +#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1 +#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" + + +typedef enum VkValidationCheckEXT { + VK_VALIDATION_CHECK_ALL_EXT = 0, + VK_VALIDATION_CHECK_BEGIN_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT, + VK_VALIDATION_CHECK_END_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT, + VK_VALIDATION_CHECK_RANGE_SIZE_EXT = (VK_VALIDATION_CHECK_ALL_EXT - VK_VALIDATION_CHECK_ALL_EXT + 1), + VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationCheckEXT; + +typedef struct VkValidationFlagsEXT { + VkStructureType sType; + const void* pNext; + uint32_t disabledValidationCheckCount; + VkValidationCheckEXT* pDisabledValidationChecks; +} VkValidationFlagsEXT; + + + +#ifdef VK_USE_PLATFORM_VI_NN +#define VK_NN_vi_surface 1 +#define VK_NN_VI_SURFACE_SPEC_VERSION 1 +#define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface" + +typedef VkFlags VkViSurfaceCreateFlagsNN; + +typedef struct VkViSurfaceCreateInfoNN { + VkStructureType sType; + const void* pNext; + VkViSurfaceCreateFlagsNN flags; + void* window; +} VkViSurfaceCreateInfoNN; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN( + VkInstance instance, + const VkViSurfaceCreateInfoNN* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif /* VK_USE_PLATFORM_VI_NN */ + +#define VK_EXT_shader_subgroup_ballot 1 +#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1 +#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot" + + +#define VK_EXT_shader_subgroup_vote 1 +#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1 +#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" + + +#define VK_NVX_device_generated_commands 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX) + +#define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1 +#define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands" + + +typedef enum VkIndirectCommandsTokenTypeNVX { + VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX = 0, + VK_INDIRECT_COMMANDS_TOKEN_DESCRIPTOR_SET_NVX = 1, + VK_INDIRECT_COMMANDS_TOKEN_INDEX_BUFFER_NVX = 2, + VK_INDIRECT_COMMANDS_TOKEN_VERTEX_BUFFER_NVX = 3, + VK_INDIRECT_COMMANDS_TOKEN_PUSH_CONSTANT_NVX = 4, + VK_INDIRECT_COMMANDS_TOKEN_DRAW_INDEXED_NVX = 5, + VK_INDIRECT_COMMANDS_TOKEN_DRAW_NVX = 6, + VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX = 7, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_BEGIN_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_END_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_RANGE_SIZE_NVX = (VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX - VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX + 1), + VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF +} VkIndirectCommandsTokenTypeNVX; + +typedef enum VkObjectEntryTypeNVX { + VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX = 0, + VK_OBJECT_ENTRY_PIPELINE_NVX = 1, + VK_OBJECT_ENTRY_INDEX_BUFFER_NVX = 2, + VK_OBJECT_ENTRY_VERTEX_BUFFER_NVX = 3, + VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX = 4, + VK_OBJECT_ENTRY_TYPE_BEGIN_RANGE_NVX = VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX, + VK_OBJECT_ENTRY_TYPE_END_RANGE_NVX = VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX, + VK_OBJECT_ENTRY_TYPE_RANGE_SIZE_NVX = (VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX - VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX + 1), + VK_OBJECT_ENTRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF +} VkObjectEntryTypeNVX; + + +typedef enum VkIndirectCommandsLayoutUsageFlagBitsNVX { + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF +} VkIndirectCommandsLayoutUsageFlagBitsNVX; +typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNVX; + +typedef enum VkObjectEntryUsageFlagBitsNVX { + VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001, + VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002, + VK_OBJECT_ENTRY_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF +} VkObjectEntryUsageFlagBitsNVX; +typedef VkFlags VkObjectEntryUsageFlagsNVX; + +typedef struct VkDeviceGeneratedCommandsFeaturesNVX { + VkStructureType sType; + const void* pNext; + VkBool32 computeBindingPointSupport; +} VkDeviceGeneratedCommandsFeaturesNVX; + +typedef struct VkDeviceGeneratedCommandsLimitsNVX { + VkStructureType sType; + const void* pNext; + uint32_t maxIndirectCommandsLayoutTokenCount; + uint32_t maxObjectEntryCounts; + uint32_t minSequenceCountBufferOffsetAlignment; + uint32_t minSequenceIndexBufferOffsetAlignment; + uint32_t minCommandsTokenBufferOffsetAlignment; +} VkDeviceGeneratedCommandsLimitsNVX; + +typedef struct VkIndirectCommandsTokenNVX { + VkIndirectCommandsTokenTypeNVX tokenType; + VkBuffer buffer; + VkDeviceSize offset; +} VkIndirectCommandsTokenNVX; + +typedef struct VkIndirectCommandsLayoutTokenNVX { + VkIndirectCommandsTokenTypeNVX tokenType; + uint32_t bindingUnit; + uint32_t dynamicCount; + uint32_t divisor; +} VkIndirectCommandsLayoutTokenNVX; + +typedef struct VkIndirectCommandsLayoutCreateInfoNVX { + VkStructureType sType; + const void* pNext; + VkPipelineBindPoint pipelineBindPoint; + VkIndirectCommandsLayoutUsageFlagsNVX flags; + uint32_t tokenCount; + const VkIndirectCommandsLayoutTokenNVX* pTokens; +} VkIndirectCommandsLayoutCreateInfoNVX; + +typedef struct VkCmdProcessCommandsInfoNVX { + VkStructureType sType; + const void* pNext; + VkObjectTableNVX objectTable; + VkIndirectCommandsLayoutNVX indirectCommandsLayout; + uint32_t indirectCommandsTokenCount; + const VkIndirectCommandsTokenNVX* pIndirectCommandsTokens; + uint32_t maxSequencesCount; + VkCommandBuffer targetCommandBuffer; + VkBuffer sequencesCountBuffer; + VkDeviceSize sequencesCountOffset; + VkBuffer sequencesIndexBuffer; + VkDeviceSize sequencesIndexOffset; +} VkCmdProcessCommandsInfoNVX; + +typedef struct VkCmdReserveSpaceForCommandsInfoNVX { + VkStructureType sType; + const void* pNext; + VkObjectTableNVX objectTable; + VkIndirectCommandsLayoutNVX indirectCommandsLayout; + uint32_t maxSequencesCount; +} VkCmdReserveSpaceForCommandsInfoNVX; + +typedef struct VkObjectTableCreateInfoNVX { + VkStructureType sType; + const void* pNext; + uint32_t objectCount; + const VkObjectEntryTypeNVX* pObjectEntryTypes; + const uint32_t* pObjectEntryCounts; + const VkObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags; + uint32_t maxUniformBuffersPerDescriptor; + uint32_t maxStorageBuffersPerDescriptor; + uint32_t maxStorageImagesPerDescriptor; + uint32_t maxSampledImagesPerDescriptor; + uint32_t maxPipelineLayouts; +} VkObjectTableCreateInfoNVX; + +typedef struct VkObjectTableEntryNVX { + VkObjectEntryTypeNVX type; + VkObjectEntryUsageFlagsNVX flags; +} VkObjectTableEntryNVX; + +typedef struct VkObjectTablePipelineEntryNVX { + VkObjectEntryTypeNVX type; + VkObjectEntryUsageFlagsNVX flags; + VkPipeline pipeline; +} VkObjectTablePipelineEntryNVX; + +typedef struct VkObjectTableDescriptorSetEntryNVX { + VkObjectEntryTypeNVX type; + VkObjectEntryUsageFlagsNVX flags; + VkPipelineLayout pipelineLayout; + VkDescriptorSet descriptorSet; +} VkObjectTableDescriptorSetEntryNVX; + +typedef struct VkObjectTableVertexBufferEntryNVX { + VkObjectEntryTypeNVX type; + VkObjectEntryUsageFlagsNVX flags; + VkBuffer buffer; +} VkObjectTableVertexBufferEntryNVX; + +typedef struct VkObjectTableIndexBufferEntryNVX { + VkObjectEntryTypeNVX type; + VkObjectEntryUsageFlagsNVX flags; + VkBuffer buffer; + VkIndexType indexType; +} VkObjectTableIndexBufferEntryNVX; + +typedef struct VkObjectTablePushConstantEntryNVX { + VkObjectEntryTypeNVX type; + VkObjectEntryUsageFlagsNVX flags; + VkPipelineLayout pipelineLayout; + VkShaderStageFlags stageFlags; +} VkObjectTablePushConstantEntryNVX; + + +typedef void (VKAPI_PTR *PFN_vkCmdProcessCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdReserveSpaceForCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNVX)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNVX)(VkDevice device, VkIndirectCommandsLayoutNVX indirectCommandsLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateObjectTableNVX)(VkDevice device, const VkObjectTableCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkObjectTableNVX* pObjectTable); +typedef void (VKAPI_PTR *PFN_vkDestroyObjectTableNVX)(VkDevice device, VkObjectTableNVX objectTable, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkRegisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectTableEntryNVX* const* ppObjectTableEntries, const uint32_t* pObjectIndices); +typedef VkResult (VKAPI_PTR *PFN_vkUnregisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectEntryTypeNVX* pObjectEntryTypes, const uint32_t* pObjectIndices); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX)(VkPhysicalDevice physicalDevice, VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, VkDeviceGeneratedCommandsLimitsNVX* pLimits); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdProcessCommandsNVX( + VkCommandBuffer commandBuffer, + const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdReserveSpaceForCommandsNVX( + VkCommandBuffer commandBuffer, + const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNVX( + VkDevice device, + const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNVX( + VkDevice device, + VkIndirectCommandsLayoutNVX indirectCommandsLayout, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateObjectTableNVX( + VkDevice device, + const VkObjectTableCreateInfoNVX* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkObjectTableNVX* pObjectTable); + +VKAPI_ATTR void VKAPI_CALL vkDestroyObjectTableNVX( + VkDevice device, + VkObjectTableNVX objectTable, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkRegisterObjectsNVX( + VkDevice device, + VkObjectTableNVX objectTable, + uint32_t objectCount, + const VkObjectTableEntryNVX* const* ppObjectTableEntries, + const uint32_t* pObjectIndices); + +VKAPI_ATTR VkResult VKAPI_CALL vkUnregisterObjectsNVX( + VkDevice device, + VkObjectTableNVX objectTable, + uint32_t objectCount, + const VkObjectEntryTypeNVX* pObjectEntryTypes, + const uint32_t* pObjectIndices); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX( + VkPhysicalDevice physicalDevice, + VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, + VkDeviceGeneratedCommandsLimitsNVX* pLimits); +#endif + +#define VK_EXT_direct_mode_display 1 +#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1 +#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display" + +typedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display); +#endif + +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT +#define VK_EXT_acquire_xlib_display 1 +#include + +#define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1 +#define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display" + +typedef VkResult (VKAPI_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, VkDisplayKHR display); +typedef VkResult (VKAPI_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, RROutput rrOutput, VkDisplayKHR* pDisplay); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT( + VkPhysicalDevice physicalDevice, + Display* dpy, + VkDisplayKHR display); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetRandROutputDisplayEXT( + VkPhysicalDevice physicalDevice, + Display* dpy, + RROutput rrOutput, + VkDisplayKHR* pDisplay); +#endif +#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */ + +#define VK_EXT_display_surface_counter 1 +#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1 +#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter" + + +typedef enum VkSurfaceCounterFlagBitsEXT { + VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001, + VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkSurfaceCounterFlagBitsEXT; +typedef VkFlags VkSurfaceCounterFlagsEXT; + +typedef struct VkSurfaceCapabilities2EXT { + VkStructureType sType; + void* pNext; + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; + VkSurfaceCounterFlagsEXT supportedSurfaceCounters; +} VkSurfaceCapabilities2EXT; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkSurfaceCapabilities2EXT* pSurfaceCapabilities); +#endif + +#define VK_EXT_display_control 1 +#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control" + + +typedef enum VkDisplayPowerStateEXT { + VK_DISPLAY_POWER_STATE_OFF_EXT = 0, + VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1, + VK_DISPLAY_POWER_STATE_ON_EXT = 2, + VK_DISPLAY_POWER_STATE_BEGIN_RANGE_EXT = VK_DISPLAY_POWER_STATE_OFF_EXT, + VK_DISPLAY_POWER_STATE_END_RANGE_EXT = VK_DISPLAY_POWER_STATE_ON_EXT, + VK_DISPLAY_POWER_STATE_RANGE_SIZE_EXT = (VK_DISPLAY_POWER_STATE_ON_EXT - VK_DISPLAY_POWER_STATE_OFF_EXT + 1), + VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDisplayPowerStateEXT; + +typedef enum VkDeviceEventTypeEXT { + VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0, + VK_DEVICE_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT, + VK_DEVICE_EVENT_TYPE_END_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT, + VK_DEVICE_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT + 1), + VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceEventTypeEXT; + +typedef enum VkDisplayEventTypeEXT { + VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0, + VK_DISPLAY_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT, + VK_DISPLAY_EVENT_TYPE_END_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT, + VK_DISPLAY_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT + 1), + VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDisplayEventTypeEXT; + +typedef struct VkDisplayPowerInfoEXT { + VkStructureType sType; + const void* pNext; + VkDisplayPowerStateEXT powerState; +} VkDisplayPowerInfoEXT; + +typedef struct VkDeviceEventInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceEventTypeEXT deviceEvent; +} VkDeviceEventInfoEXT; + +typedef struct VkDisplayEventInfoEXT { + VkStructureType sType; + const void* pNext; + VkDisplayEventTypeEXT displayEvent; +} VkDisplayEventInfoEXT; + +typedef struct VkSwapchainCounterCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkSurfaceCounterFlagsEXT surfaceCounters; +} VkSwapchainCounterCreateInfoEXT; + + +typedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo); +typedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT( + VkDevice device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT* pDisplayPowerInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT( + VkDevice device, + const VkDeviceEventInfoEXT* pDeviceEventInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); + +VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT( + VkDevice device, + VkDisplayKHR display, + const VkDisplayEventInfoEXT* pDisplayEventInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT( + VkDevice device, + VkSwapchainKHR swapchain, + VkSurfaceCounterFlagBitsEXT counter, + uint64_t* pCounterValue); +#endif + +#define VK_EXT_swapchain_colorspace 1 +#define VK_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 1 +#define VK_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/glfw/include/GLFW/glfw3.h b/src/external/glfw/include/GLFW/glfw3.h new file mode 100644 index 00000000..6923ba68 --- /dev/null +++ b/src/external/glfw/include/GLFW/glfw3.h @@ -0,0 +1,5270 @@ +/************************************************************************* + * GLFW 3.3 - www.glfw.org + * A library for OpenGL, window and input + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2016 Camilla Löwy + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + *************************************************************************/ + +#ifndef _glfw3_h_ +#define _glfw3_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* + * Doxygen documentation + *************************************************************************/ + +/*! @file glfw3.h + * @brief The header of the GLFW 3 API. + * + * This is the header file of the GLFW 3 API. It defines all its types and + * declares all its functions. + * + * For more information about how to use this file, see @ref build_include. + */ +/*! @defgroup context Context reference + * @brief Functions and types related to OpenGL and OpenGL ES contexts. + * + * This is the reference documentation for OpenGL and OpenGL ES context related + * functions. For more task-oriented information, see the @ref context_guide. + */ +/*! @defgroup vulkan Vulkan reference + * @brief Functions and types related to Vulkan. + * + * This is the reference documentation for Vulkan related functions and types. + * For more task-oriented information, see the @ref vulkan_guide. + */ +/*! @defgroup init Initialization, version and error reference + * @brief Functions and types related to initialization and error handling. + * + * This is the reference documentation for initialization and termination of + * the library, version management and error handling. For more task-oriented + * information, see the @ref intro_guide. + */ +/*! @defgroup input Input reference + * @brief Functions and types related to input handling. + * + * This is the reference documentation for input related functions and types. + * For more task-oriented information, see the @ref input_guide. + */ +/*! @defgroup monitor Monitor reference + * @brief Functions and types related to monitors. + * + * This is the reference documentation for monitor related functions and types. + * For more task-oriented information, see the @ref monitor_guide. + */ +/*! @defgroup window Window reference + * @brief Functions and types related to windows. + * + * This is the reference documentation for window related functions and types, + * including creation, deletion and event polling. For more task-oriented + * information, see the @ref window_guide. + */ + + +/************************************************************************* + * Compiler- and platform-specific preprocessor work + *************************************************************************/ + +/* If we are we on Windows, we want a single define for it. + */ +#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)) + #define _WIN32 +#endif /* _WIN32 */ + +/* It is customary to use APIENTRY for OpenGL function pointer declarations on + * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. + */ +#ifndef APIENTRY + #ifdef _WIN32 + #define APIENTRY __stdcall + #else + #define APIENTRY + #endif + #define GLFW_APIENTRY_DEFINED +#endif /* APIENTRY */ + +/* Some Windows OpenGL headers need this. + */ +#if !defined(WINGDIAPI) && defined(_WIN32) + #define WINGDIAPI __declspec(dllimport) + #define GLFW_WINGDIAPI_DEFINED +#endif /* WINGDIAPI */ + +/* Some Windows GLU headers need this. + */ +#if !defined(CALLBACK) && defined(_WIN32) + #define CALLBACK __stdcall + #define GLFW_CALLBACK_DEFINED +#endif /* CALLBACK */ + +/* Include because most Windows GLU headers need wchar_t and + * the macOS OpenGL header blocks the definition of ptrdiff_t by glext.h. + * Include it unconditionally to avoid surprising side-effects. + */ +#include + +/* Include because it is needed by Vulkan and related functions. + * Include it unconditionally to avoid surprising side-effects. + */ +#include + +/* Include the chosen OpenGL or OpenGL ES headers. + */ +#if defined(GLFW_INCLUDE_ES1) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + +#elif defined(GLFW_INCLUDE_ES2) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + +#elif defined(GLFW_INCLUDE_ES3) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + +#elif defined(GLFW_INCLUDE_ES31) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + +#elif defined(GLFW_INCLUDE_ES32) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + +#elif defined(GLFW_INCLUDE_GLCOREARB) + + #if defined(__APPLE__) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif /*GLFW_INCLUDE_GLEXT*/ + + #else /*__APPLE__*/ + + #include + + #endif /*__APPLE__*/ + +#elif !defined(GLFW_INCLUDE_NONE) + + #if defined(__APPLE__) + + #if !defined(GLFW_INCLUDE_GLEXT) + #define GL_GLEXT_LEGACY + #endif + #include + #if defined(GLFW_INCLUDE_GLU) + #include + #endif + + #else /*__APPLE__*/ + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #if defined(GLFW_INCLUDE_GLU) + #include + #endif + + #endif /*__APPLE__*/ + +#endif /* OpenGL and OpenGL ES headers */ + +#if defined(GLFW_INCLUDE_VULKAN) + #include +#endif /* Vulkan header */ + +#if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) + /* GLFW_DLL must be defined by applications that are linking against the DLL + * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW + * configuration header when compiling the DLL version of the library. + */ + #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined" +#endif + +/* GLFWAPI is used to declare public API functions for export + * from the DLL / shared library / dynamic library. + */ +#if defined(_WIN32) && defined(_GLFW_BUILD_DLL) + /* We are building GLFW as a Win32 DLL */ + #define GLFWAPI __declspec(dllexport) +#elif defined(_WIN32) && defined(GLFW_DLL) + /* We are calling GLFW as a Win32 DLL */ + #define GLFWAPI __declspec(dllimport) +#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) + /* We are building GLFW as a shared / dynamic library */ + #define GLFWAPI __attribute__((visibility("default"))) +#else + /* We are building or calling GLFW as a static library */ + #define GLFWAPI +#endif + + +/************************************************************************* + * GLFW API tokens + *************************************************************************/ + +/*! @name GLFW version macros + * @{ */ +/*! @brief The major version number of the GLFW library. + * + * This is incremented when the API is changed in non-compatible ways. + * @ingroup init + */ +#define GLFW_VERSION_MAJOR 3 +/*! @brief The minor version number of the GLFW library. + * + * This is incremented when features are added to the API but it remains + * backward-compatible. + * @ingroup init + */ +#define GLFW_VERSION_MINOR 3 +/*! @brief The revision number of the GLFW library. + * + * This is incremented when a bug fix release is made that does not contain any + * API changes. + * @ingroup init + */ +#define GLFW_VERSION_REVISION 0 +/*! @} */ + +/*! @name Boolean values + * @{ */ +/*! @brief One. + * + * One. Seriously. You don't _need_ to use this symbol in your code. It's + * semantic sugar for the number 1. You can also use `1` or `true` or `_True` + * or `GL_TRUE` or whatever you want. + */ +#define GLFW_TRUE 1 +/*! @brief Zero. + * + * Zero. Seriously. You don't _need_ to use this symbol in your code. It's + * semantic sugar for the number 0. You can also use `0` or `false` or + * `_False` or `GL_FALSE` or whatever you want. + */ +#define GLFW_FALSE 0 +/*! @} */ + +/*! @name Key and button actions + * @{ */ +/*! @brief The key or mouse button was released. + * + * The key or mouse button was released. + * + * @ingroup input + */ +#define GLFW_RELEASE 0 +/*! @brief The key or mouse button was pressed. + * + * The key or mouse button was pressed. + * + * @ingroup input + */ +#define GLFW_PRESS 1 +/*! @brief The key was held down until it repeated. + * + * The key was held down until it repeated. + * + * @ingroup input + */ +#define GLFW_REPEAT 2 +/*! @} */ + +/*! @defgroup hat_state Joystick hat states + * + * See [joystick hat input](@ref joystick_hat) for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_HAT_CENTERED 0 +#define GLFW_HAT_UP 1 +#define GLFW_HAT_RIGHT 2 +#define GLFW_HAT_DOWN 4 +#define GLFW_HAT_LEFT 8 +#define GLFW_HAT_RIGHT_UP (GLFW_HAT_RIGHT | GLFW_HAT_UP) +#define GLFW_HAT_RIGHT_DOWN (GLFW_HAT_RIGHT | GLFW_HAT_DOWN) +#define GLFW_HAT_LEFT_UP (GLFW_HAT_LEFT | GLFW_HAT_UP) +#define GLFW_HAT_LEFT_DOWN (GLFW_HAT_LEFT | GLFW_HAT_DOWN) +/*! @} */ + +/*! @defgroup keys Keyboard keys + * @brief Keyboard key IDs. + * + * See [key input](@ref input_key) for how these are used. + * + * These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60), + * but re-arranged to map to 7-bit ASCII for printable keys (function keys are + * put in the 256+ range). + * + * The naming of the key codes follow these rules: + * - The US keyboard layout is used + * - Names of printable alpha-numeric characters are used (e.g. "A", "R", + * "3", etc.) + * - For non-alphanumeric characters, Unicode:ish names are used (e.g. + * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not + * correspond to the Unicode standard (usually for brevity) + * - Keys that lack a clear US mapping are named "WORLD_x" + * - For non-printable keys, custom names are used (e.g. "F4", + * "BACKSPACE", etc.) + * + * @ingroup input + * @{ + */ + +/* The unknown key */ +#define GLFW_KEY_UNKNOWN -1 + +/* Printable keys */ +#define GLFW_KEY_SPACE 32 +#define GLFW_KEY_APOSTROPHE 39 /* ' */ +#define GLFW_KEY_COMMA 44 /* , */ +#define GLFW_KEY_MINUS 45 /* - */ +#define GLFW_KEY_PERIOD 46 /* . */ +#define GLFW_KEY_SLASH 47 /* / */ +#define GLFW_KEY_0 48 +#define GLFW_KEY_1 49 +#define GLFW_KEY_2 50 +#define GLFW_KEY_3 51 +#define GLFW_KEY_4 52 +#define GLFW_KEY_5 53 +#define GLFW_KEY_6 54 +#define GLFW_KEY_7 55 +#define GLFW_KEY_8 56 +#define GLFW_KEY_9 57 +#define GLFW_KEY_SEMICOLON 59 /* ; */ +#define GLFW_KEY_EQUAL 61 /* = */ +#define GLFW_KEY_A 65 +#define GLFW_KEY_B 66 +#define GLFW_KEY_C 67 +#define GLFW_KEY_D 68 +#define GLFW_KEY_E 69 +#define GLFW_KEY_F 70 +#define GLFW_KEY_G 71 +#define GLFW_KEY_H 72 +#define GLFW_KEY_I 73 +#define GLFW_KEY_J 74 +#define GLFW_KEY_K 75 +#define GLFW_KEY_L 76 +#define GLFW_KEY_M 77 +#define GLFW_KEY_N 78 +#define GLFW_KEY_O 79 +#define GLFW_KEY_P 80 +#define GLFW_KEY_Q 81 +#define GLFW_KEY_R 82 +#define GLFW_KEY_S 83 +#define GLFW_KEY_T 84 +#define GLFW_KEY_U 85 +#define GLFW_KEY_V 86 +#define GLFW_KEY_W 87 +#define GLFW_KEY_X 88 +#define GLFW_KEY_Y 89 +#define GLFW_KEY_Z 90 +#define GLFW_KEY_LEFT_BRACKET 91 /* [ */ +#define GLFW_KEY_BACKSLASH 92 /* \ */ +#define GLFW_KEY_RIGHT_BRACKET 93 /* ] */ +#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */ +#define GLFW_KEY_WORLD_1 161 /* non-US #1 */ +#define GLFW_KEY_WORLD_2 162 /* non-US #2 */ + +/* Function keys */ +#define GLFW_KEY_ESCAPE 256 +#define GLFW_KEY_ENTER 257 +#define GLFW_KEY_TAB 258 +#define GLFW_KEY_BACKSPACE 259 +#define GLFW_KEY_INSERT 260 +#define GLFW_KEY_DELETE 261 +#define GLFW_KEY_RIGHT 262 +#define GLFW_KEY_LEFT 263 +#define GLFW_KEY_DOWN 264 +#define GLFW_KEY_UP 265 +#define GLFW_KEY_PAGE_UP 266 +#define GLFW_KEY_PAGE_DOWN 267 +#define GLFW_KEY_HOME 268 +#define GLFW_KEY_END 269 +#define GLFW_KEY_CAPS_LOCK 280 +#define GLFW_KEY_SCROLL_LOCK 281 +#define GLFW_KEY_NUM_LOCK 282 +#define GLFW_KEY_PRINT_SCREEN 283 +#define GLFW_KEY_PAUSE 284 +#define GLFW_KEY_F1 290 +#define GLFW_KEY_F2 291 +#define GLFW_KEY_F3 292 +#define GLFW_KEY_F4 293 +#define GLFW_KEY_F5 294 +#define GLFW_KEY_F6 295 +#define GLFW_KEY_F7 296 +#define GLFW_KEY_F8 297 +#define GLFW_KEY_F9 298 +#define GLFW_KEY_F10 299 +#define GLFW_KEY_F11 300 +#define GLFW_KEY_F12 301 +#define GLFW_KEY_F13 302 +#define GLFW_KEY_F14 303 +#define GLFW_KEY_F15 304 +#define GLFW_KEY_F16 305 +#define GLFW_KEY_F17 306 +#define GLFW_KEY_F18 307 +#define GLFW_KEY_F19 308 +#define GLFW_KEY_F20 309 +#define GLFW_KEY_F21 310 +#define GLFW_KEY_F22 311 +#define GLFW_KEY_F23 312 +#define GLFW_KEY_F24 313 +#define GLFW_KEY_F25 314 +#define GLFW_KEY_KP_0 320 +#define GLFW_KEY_KP_1 321 +#define GLFW_KEY_KP_2 322 +#define GLFW_KEY_KP_3 323 +#define GLFW_KEY_KP_4 324 +#define GLFW_KEY_KP_5 325 +#define GLFW_KEY_KP_6 326 +#define GLFW_KEY_KP_7 327 +#define GLFW_KEY_KP_8 328 +#define GLFW_KEY_KP_9 329 +#define GLFW_KEY_KP_DECIMAL 330 +#define GLFW_KEY_KP_DIVIDE 331 +#define GLFW_KEY_KP_MULTIPLY 332 +#define GLFW_KEY_KP_SUBTRACT 333 +#define GLFW_KEY_KP_ADD 334 +#define GLFW_KEY_KP_ENTER 335 +#define GLFW_KEY_KP_EQUAL 336 +#define GLFW_KEY_LEFT_SHIFT 340 +#define GLFW_KEY_LEFT_CONTROL 341 +#define GLFW_KEY_LEFT_ALT 342 +#define GLFW_KEY_LEFT_SUPER 343 +#define GLFW_KEY_RIGHT_SHIFT 344 +#define GLFW_KEY_RIGHT_CONTROL 345 +#define GLFW_KEY_RIGHT_ALT 346 +#define GLFW_KEY_RIGHT_SUPER 347 +#define GLFW_KEY_MENU 348 + +#define GLFW_KEY_LAST GLFW_KEY_MENU + +/*! @} */ + +/*! @defgroup mods Modifier key flags + * @brief Modifier key flags. + * + * See [key input](@ref input_key) for how these are used. + * + * @ingroup input + * @{ */ + +/*! @brief If this bit is set one or more Shift keys were held down. + */ +#define GLFW_MOD_SHIFT 0x0001 +/*! @brief If this bit is set one or more Control keys were held down. + */ +#define GLFW_MOD_CONTROL 0x0002 +/*! @brief If this bit is set one or more Alt keys were held down. + */ +#define GLFW_MOD_ALT 0x0004 +/*! @brief If this bit is set one or more Super keys were held down. + */ +#define GLFW_MOD_SUPER 0x0008 + +/*! @} */ + +/*! @defgroup buttons Mouse buttons + * @brief Mouse button IDs. + * + * See [mouse button input](@ref input_mouse_button) for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_MOUSE_BUTTON_1 0 +#define GLFW_MOUSE_BUTTON_2 1 +#define GLFW_MOUSE_BUTTON_3 2 +#define GLFW_MOUSE_BUTTON_4 3 +#define GLFW_MOUSE_BUTTON_5 4 +#define GLFW_MOUSE_BUTTON_6 5 +#define GLFW_MOUSE_BUTTON_7 6 +#define GLFW_MOUSE_BUTTON_8 7 +#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8 +#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1 +#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2 +#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3 +/*! @} */ + +/*! @defgroup joysticks Joysticks + * @brief Joystick IDs. + * + * See [joystick input](@ref joystick) for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_JOYSTICK_1 0 +#define GLFW_JOYSTICK_2 1 +#define GLFW_JOYSTICK_3 2 +#define GLFW_JOYSTICK_4 3 +#define GLFW_JOYSTICK_5 4 +#define GLFW_JOYSTICK_6 5 +#define GLFW_JOYSTICK_7 6 +#define GLFW_JOYSTICK_8 7 +#define GLFW_JOYSTICK_9 8 +#define GLFW_JOYSTICK_10 9 +#define GLFW_JOYSTICK_11 10 +#define GLFW_JOYSTICK_12 11 +#define GLFW_JOYSTICK_13 12 +#define GLFW_JOYSTICK_14 13 +#define GLFW_JOYSTICK_15 14 +#define GLFW_JOYSTICK_16 15 +#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16 +/*! @} */ + +/*! @defgroup gamepad_buttons Gamepad buttons + * @brief Gamepad buttons. + * + * See @ref gamepad for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_GAMEPAD_BUTTON_A 0 +#define GLFW_GAMEPAD_BUTTON_B 1 +#define GLFW_GAMEPAD_BUTTON_X 2 +#define GLFW_GAMEPAD_BUTTON_Y 3 +#define GLFW_GAMEPAD_BUTTON_LEFT_BUMPER 4 +#define GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER 5 +#define GLFW_GAMEPAD_BUTTON_BACK 6 +#define GLFW_GAMEPAD_BUTTON_START 7 +#define GLFW_GAMEPAD_BUTTON_GUIDE 8 +#define GLFW_GAMEPAD_BUTTON_LEFT_THUMB 9 +#define GLFW_GAMEPAD_BUTTON_RIGHT_THUMB 10 +#define GLFW_GAMEPAD_BUTTON_DPAD_UP 11 +#define GLFW_GAMEPAD_BUTTON_DPAD_RIGHT 12 +#define GLFW_GAMEPAD_BUTTON_DPAD_DOWN 13 +#define GLFW_GAMEPAD_BUTTON_DPAD_LEFT 14 +#define GLFW_GAMEPAD_BUTTON_LAST GLFW_GAMEPAD_BUTTON_DPAD_LEFT + +#define GLFW_GAMEPAD_BUTTON_CROSS GLFW_GAMEPAD_BUTTON_A +#define GLFW_GAMEPAD_BUTTON_CIRCLE GLFW_GAMEPAD_BUTTON_B +#define GLFW_GAMEPAD_BUTTON_SQUARE GLFW_GAMEPAD_BUTTON_X +#define GLFW_GAMEPAD_BUTTON_TRIANGLE GLFW_GAMEPAD_BUTTON_Y +/*! @} */ + +/*! @defgroup gamepad_axes Gamepad axes + * @brief Gamepad axes. + * + * See @ref gamepad for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_GAMEPAD_AXIS_LEFT_X 0 +#define GLFW_GAMEPAD_AXIS_LEFT_Y 1 +#define GLFW_GAMEPAD_AXIS_RIGHT_X 2 +#define GLFW_GAMEPAD_AXIS_RIGHT_Y 3 +#define GLFW_GAMEPAD_AXIS_LEFT_TRIGGER 4 +#define GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER 5 +#define GLFW_GAMEPAD_AXIS_LAST GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER +/*! @} */ + +/*! @defgroup errors Error codes + * @brief Error codes. + * + * See [error handling](@ref error_handling) for how these are used. + * + * @ingroup init + * @{ */ +/*! @brief No error has occurred. + * + * No error has occurred. + * + * @analysis Yay. + */ +#define GLFW_NO_ERROR 0 +/*! @brief GLFW has not been initialized. + * + * This occurs if a GLFW function was called that must not be called unless the + * library is [initialized](@ref intro_init). + * + * @analysis Application programmer error. Initialize GLFW before calling any + * function that requires initialization. + */ +#define GLFW_NOT_INITIALIZED 0x00010001 +/*! @brief No context is current for this thread. + * + * This occurs if a GLFW function was called that needs and operates on the + * current OpenGL or OpenGL ES context but no context is current on the calling + * thread. One such function is @ref glfwSwapInterval. + * + * @analysis Application programmer error. Ensure a context is current before + * calling functions that require a current context. + */ +#define GLFW_NO_CURRENT_CONTEXT 0x00010002 +/*! @brief One of the arguments to the function was an invalid enum value. + * + * One of the arguments to the function was an invalid enum value, for example + * requesting @ref GLFW_RED_BITS with @ref glfwGetWindowAttrib. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_INVALID_ENUM 0x00010003 +/*! @brief One of the arguments to the function was an invalid value. + * + * One of the arguments to the function was an invalid value, for example + * requesting a non-existent OpenGL or OpenGL ES version like 2.7. + * + * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead + * result in a @ref GLFW_VERSION_UNAVAILABLE error. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_INVALID_VALUE 0x00010004 +/*! @brief A memory allocation failed. + * + * A memory allocation failed. + * + * @analysis A bug in GLFW or the underlying operating system. Report the bug + * to our [issue tracker](https://github.com/glfw/glfw/issues). + */ +#define GLFW_OUT_OF_MEMORY 0x00010005 +/*! @brief GLFW could not find support for the requested API on the system. + * + * GLFW could not find support for the requested API on the system. + * + * @analysis The installed graphics driver does not support the requested + * API, or does not support it via the chosen context creation backend. + * Below are a few examples. + * + * @par + * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only + * supports OpenGL ES via EGL, while Nvidia and Intel only support it via + * a WGL or GLX extension. macOS does not provide OpenGL ES at all. The Mesa + * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary + * driver. Older graphics drivers do not support Vulkan. + */ +#define GLFW_API_UNAVAILABLE 0x00010006 +/*! @brief The requested OpenGL or OpenGL ES version is not available. + * + * The requested OpenGL or OpenGL ES version (including any requested context + * or framebuffer hints) is not available on this machine. + * + * @analysis The machine does not support your requirements. If your + * application is sufficiently flexible, downgrade your requirements and try + * again. Otherwise, inform the user that their machine does not match your + * requirements. + * + * @par + * Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 + * comes out before the 4.x series gets that far, also fail with this error and + * not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions + * will exist. + */ +#define GLFW_VERSION_UNAVAILABLE 0x00010007 +/*! @brief A platform-specific error occurred that does not match any of the + * more specific categories. + * + * A platform-specific error occurred that does not match any of the more + * specific categories. + * + * @analysis A bug or configuration error in GLFW, the underlying operating + * system or its drivers, or a lack of required resources. Report the issue to + * our [issue tracker](https://github.com/glfw/glfw/issues). + */ +#define GLFW_PLATFORM_ERROR 0x00010008 +/*! @brief The requested format is not supported or available. + * + * If emitted during window creation, the requested pixel format is not + * supported. + * + * If emitted when querying the clipboard, the contents of the clipboard could + * not be converted to the requested format. + * + * @analysis If emitted during window creation, one or more + * [hard constraints](@ref window_hints_hard) did not match any of the + * available pixel formats. If your application is sufficiently flexible, + * downgrade your requirements and try again. Otherwise, inform the user that + * their machine does not match your requirements. + * + * @par + * If emitted when querying the clipboard, ignore the error or report it to + * the user, as appropriate. + */ +#define GLFW_FORMAT_UNAVAILABLE 0x00010009 +/*! @brief The specified window does not have an OpenGL or OpenGL ES context. + * + * A window that does not have an OpenGL or OpenGL ES context was passed to + * a function that requires it to have one. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_NO_WINDOW_CONTEXT 0x0001000A +/*! @} */ + +/*! @addtogroup window + * @{ */ +/*! @brief Input focus window hint and attribute + * + * Input focus [window hint](@ref GLFW_FOCUSED_hint) or + * [window attribute](@ref GLFW_FOCUSED_attrib). + */ +#define GLFW_FOCUSED 0x00020001 +/*! @brief Window iconification window attribute + * + * Window iconification [window attribute](@ref GLFW_ICONIFIED_attrib). + */ +#define GLFW_ICONIFIED 0x00020002 +/*! @brief Window resize-ability window hint and attribute + * + * Window resize-ability [window hint](@ref GLFW_RESIZABLE_hint) and + * [window attribute](@ref GLFW_RESIZABLE_attrib). + */ +#define GLFW_RESIZABLE 0x00020003 +/*! @brief Window visibility window hint and attribute + * + * Window visibility [window hint](@ref GLFW_VISIBLE_hint) and + * [window attribute](@ref GLFW_VISIBLE_attrib). + */ +#define GLFW_VISIBLE 0x00020004 +/*! @brief Window decoration window hint and attribute + * + * Window decoration [window hint](@ref GLFW_DECORATED_hint) and + * [window attribute](@ref GLFW_DECORATED_attrib). + */ +#define GLFW_DECORATED 0x00020005 +/*! @brief Window auto-iconification window hint and attribute + * + * Window auto-iconification [window hint](@ref GLFW_AUTO_ICONIFY_hint) and + * [window attribute](@ref GLFW_AUTO_ICONIFY_attrib). + */ +#define GLFW_AUTO_ICONIFY 0x00020006 +/*! @brief Window decoration window hint and attribute + * + * Window decoration [window hint](@ref GLFW_FLOATING_hint) and + * [window attribute](@ref GLFW_FLOATING_attrib). + */ +#define GLFW_FLOATING 0x00020007 +/*! @brief Window maximization window hint and attribute + * + * Window maximization [window hint](@ref GLFW_MAXIMIZED_hint) and + * [window attribute](@ref GLFW_MAXIMIZED_attrib). + */ +#define GLFW_MAXIMIZED 0x00020008 +/*! @brief Cursor centering window hint + * + * Cursor centering [window hint](@ref GLFW_CENTER_CURSOR_hint). + */ +#define GLFW_CENTER_CURSOR 0x00020009 +/*! @brief Window framebuffer transparency hint and attribute + * + * Window framebuffer transparency [window hint](@ref GLFW_TRANSPARENT_hint) + * and [window attribute](@ref GLFW_TRANSPARENT_attrib). + */ +#define GLFW_TRANSPARENT 0x0002000A + +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_RED_BITS). + */ +#define GLFW_RED_BITS 0x00021001 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_GREEN_BITS). + */ +#define GLFW_GREEN_BITS 0x00021002 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_BLUE_BITS). + */ +#define GLFW_BLUE_BITS 0x00021003 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ALPHA_BITS). + */ +#define GLFW_ALPHA_BITS 0x00021004 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_DEPTH_BITS). + */ +#define GLFW_DEPTH_BITS 0x00021005 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_STENCIL_BITS). + */ +#define GLFW_STENCIL_BITS 0x00021006 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_RED_BITS). + */ +#define GLFW_ACCUM_RED_BITS 0x00021007 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_GREEN_BITS). + */ +#define GLFW_ACCUM_GREEN_BITS 0x00021008 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_BLUE_BITS). + */ +#define GLFW_ACCUM_BLUE_BITS 0x00021009 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_ALPHA_BITS). + */ +#define GLFW_ACCUM_ALPHA_BITS 0x0002100A +/*! @brief Framebuffer auxiliary buffer hint. + * + * Framebuffer auxiliary buffer [hint](@ref GLFW_AUX_BUFFERS). + */ +#define GLFW_AUX_BUFFERS 0x0002100B +/*! @brief OpenGL stereoscopic rendering hint. + * + * OpenGL stereoscopic rendering [hint](@ref GLFW_STEREO). + */ +#define GLFW_STEREO 0x0002100C +/*! @brief Framebuffer MSAA samples hint. + * + * Framebuffer MSAA samples [hint](@ref GLFW_SAMPLES). + */ +#define GLFW_SAMPLES 0x0002100D +/*! @brief Framebuffer sRGB hint. + * + * Framebuffer sRGB [hint](@ref GLFW_SRGB_CAPABLE). + */ +#define GLFW_SRGB_CAPABLE 0x0002100E +/*! @brief Monitor refresh rate hint. + * + * Monitor refresh rate [hint](@ref GLFW_REFRESH_RATE). + */ +#define GLFW_REFRESH_RATE 0x0002100F +/*! @brief Framebuffer double buffering hint. + * + * Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER). + */ +#define GLFW_DOUBLEBUFFER 0x00021010 + +/*! @brief Context client API hint and attribute. + * + * Context client API [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_CLIENT_API 0x00022001 +/*! @brief Context client API major version hint and attribute. + * + * Context client API major version [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 +/*! @brief Context client API minor version hint and attribute. + * + * Context client API minor version [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_CONTEXT_VERSION_MINOR 0x00022003 +/*! @brief Context client API revision number hint and attribute. + * + * Context client API revision number [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_CONTEXT_REVISION 0x00022004 +/*! @brief Context robustness hint and attribute. + * + * Context client API revision number [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_CONTEXT_ROBUSTNESS 0x00022005 +/*! @brief OpenGL forward-compatibility hint and attribute. + * + * OpenGL forward-compatibility [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 +/*! @brief OpenGL debug context hint and attribute. + * + * OpenGL debug context [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 +/*! @brief OpenGL profile hint and attribute. + * + * OpenGL profile [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_OPENGL_PROFILE 0x00022008 +/*! @brief Context flush-on-release hint and attribute. + * + * Context flush-on-release [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 +/*! @brief Context error suppression hint and attribute. + * + * Context error suppression [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_CONTEXT_NO_ERROR 0x0002200A +/*! @brief Context creation API hint and attribute. + * + * Context creation API [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_CONTEXT_CREATION_API 0x0002200B + +#define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001 +#define GLFW_COCOA_FRAME_AUTOSAVE 0x00023002 +#define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003 +/*! @} */ + +#define GLFW_NO_API 0 +#define GLFW_OPENGL_API 0x00030001 +#define GLFW_OPENGL_ES_API 0x00030002 + +#define GLFW_NO_ROBUSTNESS 0 +#define GLFW_NO_RESET_NOTIFICATION 0x00031001 +#define GLFW_LOSE_CONTEXT_ON_RESET 0x00031002 + +#define GLFW_OPENGL_ANY_PROFILE 0 +#define GLFW_OPENGL_CORE_PROFILE 0x00032001 +#define GLFW_OPENGL_COMPAT_PROFILE 0x00032002 + +#define GLFW_CURSOR 0x00033001 +#define GLFW_STICKY_KEYS 0x00033002 +#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 + +#define GLFW_CURSOR_NORMAL 0x00034001 +#define GLFW_CURSOR_HIDDEN 0x00034002 +#define GLFW_CURSOR_DISABLED 0x00034003 + +#define GLFW_ANY_RELEASE_BEHAVIOR 0 +#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 +#define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 + +#define GLFW_NATIVE_CONTEXT_API 0x00036001 +#define GLFW_EGL_CONTEXT_API 0x00036002 +#define GLFW_OSMESA_CONTEXT_API 0x00036003 + +/*! @defgroup shapes Standard cursor shapes + * @brief Standard system cursor shapes. + * + * See [standard cursor creation](@ref cursor_standard) for how these are used. + * + * @ingroup input + * @{ */ + +/*! @brief The regular arrow cursor shape. + * + * The regular arrow cursor. + */ +#define GLFW_ARROW_CURSOR 0x00036001 +/*! @brief The text input I-beam cursor shape. + * + * The text input I-beam cursor shape. + */ +#define GLFW_IBEAM_CURSOR 0x00036002 +/*! @brief The crosshair shape. + * + * The crosshair shape. + */ +#define GLFW_CROSSHAIR_CURSOR 0x00036003 +/*! @brief The hand shape. + * + * The hand shape. + */ +#define GLFW_HAND_CURSOR 0x00036004 +/*! @brief The horizontal resize arrow shape. + * + * The horizontal resize arrow shape. + */ +#define GLFW_HRESIZE_CURSOR 0x00036005 +/*! @brief The vertical resize arrow shape. + * + * The vertical resize arrow shape. + */ +#define GLFW_VRESIZE_CURSOR 0x00036006 +/*! @} */ + +#define GLFW_CONNECTED 0x00040001 +#define GLFW_DISCONNECTED 0x00040002 + +/*! @addtogroup init + * @{ */ +#define GLFW_JOYSTICK_HAT_BUTTONS 0x00050001 + +#define GLFW_COCOA_CHDIR_RESOURCES 0x00051001 +#define GLFW_COCOA_MENUBAR 0x00051002 + +#define GLFW_X11_WM_CLASS_NAME 0x00052001 +#define GLFW_X11_WM_CLASS_CLASS 0x00052002 +/*! @} */ + +#define GLFW_DONT_CARE -1 + + +/************************************************************************* + * GLFW API types + *************************************************************************/ + +/*! @brief Client API function pointer type. + * + * Generic function pointer used for returning client API function pointers + * without forcing a cast from a regular pointer. + * + * @sa @ref context_glext + * @sa @ref glfwGetProcAddress + * + * @since Added in version 3.0. + + * @ingroup context + */ +typedef void (*GLFWglproc)(void); + +/*! @brief Vulkan API function pointer type. + * + * Generic function pointer used for returning Vulkan API function pointers + * without forcing a cast from a regular pointer. + * + * @sa @ref vulkan_proc + * @sa @ref glfwGetInstanceProcAddress + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +typedef void (*GLFWvkproc)(void); + +/*! @brief Opaque monitor object. + * + * Opaque monitor object. + * + * @see @ref monitor_object + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +typedef struct GLFWmonitor GLFWmonitor; + +/*! @brief Opaque window object. + * + * Opaque window object. + * + * @see @ref window_object + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef struct GLFWwindow GLFWwindow; + +/*! @brief Opaque cursor object. + * + * Opaque cursor object. + * + * @see @ref cursor_object + * + * @since Added in version 3.1. + * + * @ingroup cursor + */ +typedef struct GLFWcursor GLFWcursor; + +/*! @brief The function signature for error callbacks. + * + * This is the function signature for error callback functions. + * + * @param[in] error An [error code](@ref errors). + * @param[in] description A UTF-8 encoded string describing the error. + * + * @sa @ref error_handling + * @sa @ref glfwSetErrorCallback + * + * @since Added in version 3.0. + * + * @ingroup init + */ +typedef void (* GLFWerrorfun)(int,const char*); + +/*! @brief The function signature for window position callbacks. + * + * This is the function signature for window position callback functions. + * + * @param[in] window The window that was moved. + * @param[in] xpos The new x-coordinate, in screen coordinates, of the + * upper-left corner of the client area of the window. + * @param[in] ypos The new y-coordinate, in screen coordinates, of the + * upper-left corner of the client area of the window. + * + * @sa @ref window_pos + * @sa @ref glfwSetWindowPosCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); + +/*! @brief The function signature for window resize callbacks. + * + * This is the function signature for window size callback functions. + * + * @param[in] window The window that was resized. + * @param[in] width The new width, in screen coordinates, of the window. + * @param[in] height The new height, in screen coordinates, of the window. + * + * @sa @ref window_size + * @sa @ref glfwSetWindowSizeCallback + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); + +/*! @brief The function signature for window close callbacks. + * + * This is the function signature for window close callback functions. + * + * @param[in] window The window that the user attempted to close. + * + * @sa @ref window_close + * @sa @ref glfwSetWindowCloseCallback + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +typedef void (* GLFWwindowclosefun)(GLFWwindow*); + +/*! @brief The function signature for window content refresh callbacks. + * + * This is the function signature for window refresh callback functions. + * + * @param[in] window The window whose content needs to be refreshed. + * + * @sa @ref window_refresh + * @sa @ref glfwSetWindowRefreshCallback + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); + +/*! @brief The function signature for window focus/defocus callbacks. + * + * This is the function signature for window focus callback functions. + * + * @param[in] window The window that gained or lost input focus. + * @param[in] focused `GLFW_TRUE` if the window was given input focus, or + * `GLFW_FALSE` if it lost it. + * + * @sa @ref window_focus + * @sa @ref glfwSetWindowFocusCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); + +/*! @brief The function signature for window iconify/restore callbacks. + * + * This is the function signature for window iconify/restore callback + * functions. + * + * @param[in] window The window that was iconified or restored. + * @param[in] iconified `GLFW_TRUE` if the window was iconified, or + * `GLFW_FALSE` if it was restored. + * + * @sa @ref window_iconify + * @sa @ref glfwSetWindowIconifyCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); + +/*! @brief The function signature for window maximize/restore callbacks. + * + * This is the function signature for window maximize/restore callback + * functions. + * + * @param[in] window The window that was maximized or restored. + * @param[in] iconified `GLFW_TRUE` if the window was maximized, or + * `GLFW_FALSE` if it was restored. + * + * @sa @ref window_maximize + * @sa glfwSetWindowMaximizeCallback + * + * @since Added in version 3.3. + * + * @ingroup window + */ +typedef void (* GLFWwindowmaximizefun)(GLFWwindow*,int); + +/*! @brief The function signature for framebuffer resize callbacks. + * + * This is the function signature for framebuffer resize callback + * functions. + * + * @param[in] window The window whose framebuffer was resized. + * @param[in] width The new width, in pixels, of the framebuffer. + * @param[in] height The new height, in pixels, of the framebuffer. + * + * @sa @ref window_fbsize + * @sa @ref glfwSetFramebufferSizeCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); + +/*! @brief The function signature for mouse button callbacks. + * + * This is the function signature for mouse button callback functions. + * + * @param[in] window The window that received the event. + * @param[in] button The [mouse button](@ref buttons) that was pressed or + * released. + * @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_mouse_button + * @sa @ref glfwSetMouseButtonCallback + * + * @since Added in version 1.0. + * @glfw3 Added window handle and modifier mask parameters. + * + * @ingroup input + */ +typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); + +/*! @brief The function signature for cursor position callbacks. + * + * This is the function signature for cursor position callback functions. + * + * @param[in] window The window that received the event. + * @param[in] xpos The new cursor x-coordinate, relative to the left edge of + * the client area. + * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the + * client area. + * + * @sa @ref cursor_pos + * @sa @ref glfwSetCursorPosCallback + * + * @since Added in version 3.0. Replaces `GLFWmouseposfun`. + * + * @ingroup input + */ +typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); + +/*! @brief The function signature for cursor enter/leave callbacks. + * + * This is the function signature for cursor enter/leave callback functions. + * + * @param[in] window The window that received the event. + * @param[in] entered `GLFW_TRUE` if the cursor entered the window's client + * area, or `GLFW_FALSE` if it left it. + * + * @sa @ref cursor_enter + * @sa @ref glfwSetCursorEnterCallback + * + * @since Added in version 3.0. + * + * @ingroup input + */ +typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); + +/*! @brief The function signature for scroll callbacks. + * + * This is the function signature for scroll callback functions. + * + * @param[in] window The window that received the event. + * @param[in] xoffset The scroll offset along the x-axis. + * @param[in] yoffset The scroll offset along the y-axis. + * + * @sa @ref scrolling + * @sa @ref glfwSetScrollCallback + * + * @since Added in version 3.0. Replaces `GLFWmousewheelfun`. + * + * @ingroup input + */ +typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); + +/*! @brief The function signature for keyboard key callbacks. + * + * This is the function signature for keyboard key callback functions. + * + * @param[in] window The window that received the event. + * @param[in] key The [keyboard key](@ref keys) that was pressed or released. + * @param[in] scancode The system-specific scancode of the key. + * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_key + * @sa @ref glfwSetKeyCallback + * + * @since Added in version 1.0. + * @glfw3 Added window handle, scancode and modifier mask parameters. + * + * @ingroup input + */ +typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); + +/*! @brief The function signature for Unicode character callbacks. + * + * This is the function signature for Unicode character callback functions. + * + * @param[in] window The window that received the event. + * @param[in] codepoint The Unicode code point of the character. + * + * @sa @ref input_char + * @sa @ref glfwSetCharCallback + * + * @since Added in version 2.4. + * @glfw3 Added window handle parameter. + * + * @ingroup input + */ +typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); + +/*! @brief The function signature for Unicode character with modifiers + * callbacks. + * + * This is the function signature for Unicode character with modifiers callback + * functions. It is called for each input character, regardless of what + * modifier keys are held down. + * + * @param[in] window The window that received the event. + * @param[in] codepoint The Unicode code point of the character. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_char + * @sa @ref glfwSetCharModsCallback + * + * @since Added in version 3.1. + * + * @ingroup input + */ +typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); + +/*! @brief The function signature for file drop callbacks. + * + * This is the function signature for file drop callbacks. + * + * @param[in] window The window that received the event. + * @param[in] count The number of dropped files. + * @param[in] paths The UTF-8 encoded file and/or directory path names. + * + * @sa @ref path_drop + * @sa @ref glfwSetDropCallback + * + * @since Added in version 3.1. + * + * @ingroup input + */ +typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); + +/*! @brief The function signature for monitor configuration callbacks. + * + * This is the function signature for monitor configuration callback functions. + * + * @param[in] monitor The monitor that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * + * @sa @ref monitor_event + * @sa @ref glfwSetMonitorCallback + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); + +/*! @brief The function signature for joystick configuration callbacks. + * + * This is the function signature for joystick configuration callback + * functions. + * + * @param[in] jid The joystick that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * + * @sa @ref joystick_event + * @sa @ref glfwSetJoystickCallback + * + * @since Added in version 3.2. + * + * @ingroup input + */ +typedef void (* GLFWjoystickfun)(int,int); + +/*! @brief Video mode type. + * + * This describes a single video mode. + * + * @sa @ref monitor_modes + * @sa @ref glfwGetVideoMode + * @sa @ref glfwGetVideoModes + * + * @since Added in version 1.0. + * @glfw3 Added refresh rate member. + * + * @ingroup monitor + */ +typedef struct GLFWvidmode +{ + /*! The width, in screen coordinates, of the video mode. + */ + int width; + /*! The height, in screen coordinates, of the video mode. + */ + int height; + /*! The bit depth of the red channel of the video mode. + */ + int redBits; + /*! The bit depth of the green channel of the video mode. + */ + int greenBits; + /*! The bit depth of the blue channel of the video mode. + */ + int blueBits; + /*! The refresh rate, in Hz, of the video mode. + */ + int refreshRate; +} GLFWvidmode; + +/*! @brief Gamma ramp. + * + * This describes the gamma ramp for a monitor. + * + * @sa @ref monitor_gamma + * @sa @ref glfwGetGammaRamp + * @sa @ref glfwSetGammaRamp + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +typedef struct GLFWgammaramp +{ + /*! An array of value describing the response of the red channel. + */ + unsigned short* red; + /*! An array of value describing the response of the green channel. + */ + unsigned short* green; + /*! An array of value describing the response of the blue channel. + */ + unsigned short* blue; + /*! The number of elements in each array. + */ + unsigned int size; +} GLFWgammaramp; + +/*! @brief Image data. + * + * This describes a single 2D image. See the documentation for each related + * function what the expected pixel format is. + * + * @sa @ref cursor_custom + * @sa @ref window_icon + * + * @since Added in version 2.1. + * @glfw3 Removed format and bytes-per-pixel members. + */ +typedef struct GLFWimage +{ + /*! The width, in pixels, of this image. + */ + int width; + /*! The height, in pixels, of this image. + */ + int height; + /*! The pixel data of this image, arranged left-to-right, top-to-bottom. + */ + unsigned char* pixels; +} GLFWimage; + +/*! @brief Gamepad input state + * + * This describes the input state of a gamepad. + * + * @sa @ref gamepad + * @sa @ref glfwGetGamepadState + * + * @since Added in version 3.3. + */ +typedef struct GLFWgamepadstate +{ + /*! The states of each [gamepad button](@ref gamepad_buttons), `GLFW_PRESS` + * or `GLFW_RELEASE`. + */ + unsigned char buttons[15]; + /*! The states of each [gamepad axis](@ref gamepad_axes), in the range -1.0 + * to 1.0 inclusive. + */ + float axes[6]; +} GLFWgamepadstate; + + +/************************************************************************* + * GLFW API functions + *************************************************************************/ + +/*! @brief Initializes the GLFW library. + * + * This function initializes the GLFW library. Before most GLFW functions can + * be used, GLFW must be initialized, and before an application terminates GLFW + * should be terminated in order to free any resources allocated during or + * after initialization. + * + * If this function fails, it calls @ref glfwTerminate before returning. If it + * succeeds, you should call @ref glfwTerminate before the application exits. + * + * Additional calls to this function after successful initialization but before + * termination will return `GLFW_TRUE` immediately. + * + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. + * + * @remark @macos This function will change the current directory of the + * application to the `Contents/Resources` subdirectory of the application's + * bundle, if present. This can be disabled with the @ref + * GLFW_COCOA_CHDIR_RESOURCES init hint. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref intro_init + * @sa @ref glfwTerminate + * + * @since Added in version 1.0. + * + * @ingroup init + */ +GLFWAPI int glfwInit(void); + +/*! @brief Terminates the GLFW library. + * + * This function destroys all remaining windows and cursors, restores any + * modified gamma ramps and frees any other allocated resources. Once this + * function is called, you must again call @ref glfwInit successfully before + * you will be able to use most GLFW functions. + * + * If GLFW has been successfully initialized, this function should be called + * before the application exits. If initialization fails, there is no need to + * call this function, as it is called by @ref glfwInit before it returns + * failure. + * + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. + * + * @remark This function may be called before @ref glfwInit. + * + * @warning The contexts of any remaining windows must not be current on any + * other thread when this function is called. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref intro_init + * @sa @ref glfwInit + * + * @since Added in version 1.0. + * + * @ingroup init + */ +GLFWAPI void glfwTerminate(void); + +/*! @brief Sets the specified init hint to the desired value. + * + * This function sets hints for the next initialization of GLFW. Only integer + * type hints can be set with this function. + * + * The values you set hints to are never reset by GLFW, but they only take + * effect during initialization. Once GLFW has been initialized, any values + * you set will be ignored until the library is terminated and initialized + * again. + * + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. + * + * @param[in] hint The [init hint](@ref init_hints) to set. + * @param[in] value The new value of the init hint. + * + * @errors Possible errors include @ref GLFW_INVALID_ENUM and @ref + * GLFW_INVALID_VALUE. + * + * @remarks This function may be called before @ref glfwInit. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa init_hints + * @sa glfwInit + * @sa glfwInitHintString + * + * @since Added in version 3.3. + * + * @ingroup init + */ +GLFWAPI void glfwInitHint(int hint, int value); + +/*! @brief Sets the specified init hint to the desired value. + * + * This function sets hints for the next initialization of GLFW. Only string + * type hints can be set with this function. + * + * The values you set hints to are never reset by GLFW, but they only take + * effect during initialization. Once GLFW has been initialized, any values + * you set will be ignored until the library is terminated and initialized + * again. + * + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. + * + * @param[in] hint The [init hint](@ref init_hints) to set. + * @param[in] value The new value of the init hint. + * + * @errors Possible errors include @ref GLFW_INVALID_ENUM and @ref + * GLFW_INVALID_VALUE. + * + * @remarks This function may be called before @ref glfwInit. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa init_hints + * @sa glfwInit + * @sa glfwInitHint + * + * @since Added in version 3.3. + * + * @ingroup init + */ +GLFWAPI void glfwInitHintString(int hint, const char* value); + +/*! @brief Retrieves the version of the GLFW library. + * + * This function retrieves the major, minor and revision numbers of the GLFW + * library. It is intended for when you are using GLFW as a shared library and + * want to ensure that you are using the minimum required version. + * + * Any or all of the version arguments may be `NULL`. + * + * @param[out] major Where to store the major version number, or `NULL`. + * @param[out] minor Where to store the minor version number, or `NULL`. + * @param[out] rev Where to store the revision number, or `NULL`. + * + * @errors None. + * + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref intro_version + * @sa @ref glfwGetVersionString + * + * @since Added in version 1.0. + * + * @ingroup init + */ +GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); + +/*! @brief Returns a string describing the compile-time configuration. + * + * This function returns the compile-time generated + * [version string](@ref intro_version_string) of the GLFW library binary. It + * describes the version, platform, compiler and any platform-specific + * compile-time options. It should not be confused with the OpenGL or OpenGL + * ES version string, queried with `glGetString`. + * + * __Do not use the version string__ to parse the GLFW library version. The + * @ref glfwGetVersion function provides the version of the running library + * binary in numerical format. + * + * @return The ASCII encoded GLFW version string. + * + * @errors None. + * + * @remark This function may be called before @ref glfwInit. + * + * @pointer_lifetime The returned string is static and compile-time generated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref intro_version + * @sa @ref glfwGetVersion + * + * @since Added in version 3.0. + * + * @ingroup init + */ +GLFWAPI const char* glfwGetVersionString(void); + +/*! @brief Returns and clears the last error for the calling thread. + * + * This function returns and clears the [error code](@ref errors) of the last + * error that occurred on the calling thread, and optionally a UTF-8 encoded + * human-readable description of it. If no error has occurred since the last + * call, it returns @ref GLFW_NO_ERROR (zero) and the description pointer is + * set to `NULL`. + * + * @param[in] description Where to store the error description pointer, or `NULL`. + * @return The last error code for the calling thread, or @ref GLFW_NO_ERROR + * (zero). + * + * @errors None. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * next error occurs or the library is terminated. + * + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref error_handling + * @sa @ref glfwSetErrorCallback + * + * @since Added in version 3.3. + * + * @ingroup init + */ +GLFWAPI int glfwGetError(const char** description); + +/*! @brief Sets the error callback. + * + * This function sets the error callback, which is called with an error code + * and a human-readable description each time a GLFW error occurs. + * + * The error code is set before the callback is called. Calling @ref + * glfwGetError from the error callback will return the same value as the error + * code argument. + * + * The error callback is called on the thread where the error occurred. If you + * are using GLFW from multiple threads, your error callback needs to be + * written accordingly. + * + * Because the description string may have been generated specifically for that + * error, it is not guaranteed to be valid after the callback has returned. If + * you wish to use it after the callback returns, you need to make a copy. + * + * Once set, the error callback remains set even after the library has been + * terminated. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set. + * + * @errors None. + * + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref error_handling + * @sa @ref glfwGetError + * + * @since Added in version 3.0. + * + * @ingroup init + */ +GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); + +/*! @brief Returns the currently connected monitors. + * + * This function returns an array of handles for all currently connected + * monitors. The primary monitor is always first in the returned array. If no + * monitors were found, this function returns `NULL`. + * + * @param[out] count Where to store the number of monitors in the returned + * array. This is set to zero if an error occurred. + * @return An array of monitor handles, or `NULL` if no monitors were found or + * if an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * monitor configuration changes or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_monitors + * @sa @ref monitor_event + * @sa @ref glfwGetPrimaryMonitor + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); + +/*! @brief Returns the primary monitor. + * + * This function returns the primary monitor. This is usually the monitor + * where elements like the task bar or global menu bar are located. + * + * @return The primary monitor, or `NULL` if no monitors were found or if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @remark The primary monitor is always first in the array returned by @ref + * glfwGetMonitors. + * + * @sa @ref monitor_monitors + * @sa @ref glfwGetMonitors + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); + +/*! @brief Returns the position of the monitor's viewport on the virtual screen. + * + * This function returns the position, in screen coordinates, of the upper-left + * corner of the specified monitor. + * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * + * @param[in] monitor The monitor to query. + * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. + * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); + +/*! @brief Returns the physical size of the monitor. + * + * This function returns the size, in millimetres, of the display area of the + * specified monitor. + * + * Some systems do not provide accurate monitor size information, either + * because the monitor + * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data) + * data is incorrect or because the driver does not report it accurately. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] monitor The monitor to query. + * @param[out] widthMM Where to store the width, in millimetres, of the + * monitor's display area, or `NULL`. + * @param[out] heightMM Where to store the height, in millimetres, of the + * monitor's display area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @win32 calculates the returned physical size from the + * current resolution and system DPI instead of querying the monitor EDID data. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM); + +/*! @brief Retrieves the content scale for the specified monitor. + * + * This function retrieves the content scale for the specified monitor. The + * content scale is the ratio between the current DPI and the platform's + * default DPI. If you scale all pixel dimensions by this scale then your + * content should appear at an appropriate size. This is especially important + * for text and any UI elements. + * + * The content scale may depend on both the monitor resolution and pixel + * density and on user settings. It may be very different from the raw DPI + * calculated from the physical size and current resolution. + * + * @param[in] monitor The monitor to query. + * @param[out] xscale Where to store the x-axis content scale, or `NULL`. + * @param[out] yscale Where to store the y-axis content scale, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_scale + * @sa @ref glfwGetWindowContentScale + * + * @since Added in version 3.3. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* monitor, float* xscale, float* yscale); + +/*! @brief Returns the name of the specified monitor. + * + * This function returns a human-readable name, encoded as UTF-8, of the + * specified monitor. The name typically reflects the make and model of the + * monitor and is not guaranteed to be unique among the connected monitors. + * + * @param[in] monitor The monitor to query. + * @return The UTF-8 encoded name of the monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); + +/*! @brief Sets the monitor configuration callback. + * + * This function sets the monitor configuration callback, or removes the + * currently set callback. This is called when a monitor is connected to or + * disconnected from the system. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_event + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); + +/*! @brief Returns the available video modes for the specified monitor. + * + * This function returns an array of all video modes supported by the specified + * monitor. The returned array is sorted in ascending order, first by color + * bit depth (the sum of all channel depths) and then by resolution area (the + * product of width and height). + * + * @param[in] monitor The monitor to query. + * @param[out] count Where to store the number of video modes in the returned + * array. This is set to zero if an error occurred. + * @return An array of video modes, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected, this function is called again for that monitor or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_modes + * @sa @ref glfwGetVideoMode + * + * @since Added in version 1.0. + * @glfw3 Changed to return an array of modes for a specific monitor. + * + * @ingroup monitor + */ +GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); + +/*! @brief Returns the current mode of the specified monitor. + * + * This function returns the current video mode of the specified monitor. If + * you have created a full screen window for that monitor, the return value + * will depend on whether that window is iconified. + * + * @param[in] monitor The monitor to query. + * @return The current mode of the monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_modes + * @sa @ref glfwGetVideoModes + * + * @since Added in version 3.0. Replaces `glfwGetDesktopMode`. + * + * @ingroup monitor + */ +GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); + +/*! @brief Generates a gamma ramp and sets it for the specified monitor. + * + * This function generates a 256-element gamma ramp from the specified exponent + * and then calls @ref glfwSetGammaRamp with it. The value must be a finite + * number greater than zero. + * + * The software controlled gamma ramp is applied _in addition_ to the hardware + * gamma correction, which today is usually an approximation of sRGB gamma. + * This means that setting a perfectly linear ramp, or gamma 1.0, will produce + * the default (usually sRGB-like) behavior. + * + * For gamma correct rendering with OpenGL or OpenGL ES, see the @ref + * GLFW_SRGB_CAPABLE hint. + * + * @param[in] monitor The monitor whose gamma ramp to set. + * @param[in] gamma The desired exponent. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark @wayland Gamma handling is currently unavailable, this function will + * always emit @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); + +/*! @brief Returns the current gamma ramp for the specified monitor. + * + * This function returns the current gamma ramp of the specified monitor. + * + * @param[in] monitor The monitor to query. + * @return The current gamma ramp, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland Gamma handling is currently unavailable, this function will + * always return `NULL` and emit @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned structure and its arrays are allocated and + * freed by GLFW. You should not free them yourself. They are valid until the + * specified monitor is disconnected, this function is called again for that + * monitor or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); + +/*! @brief Sets the current gamma ramp for the specified monitor. + * + * This function sets the current gamma ramp for the specified monitor. The + * original gamma ramp for that monitor is saved by GLFW the first time this + * function is called and is restored by @ref glfwTerminate. + * + * The software controlled gamma ramp is applied _in addition_ to the hardware + * gamma correction, which today is usually an approximation of sRGB gamma. + * This means that setting a perfectly linear ramp, or gamma 1.0, will produce + * the default (usually sRGB-like) behavior. + * + * For gamma correct rendering with OpenGL or OpenGL ES, see the @ref + * GLFW_SRGB_CAPABLE hint. + * + * @param[in] monitor The monitor whose gamma ramp to set. + * @param[in] ramp The gamma ramp to use. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark Gamma ramp sizes other than 256 are not supported by all platforms + * or graphics hardware. + * + * @remark @win32 The gamma ramp size must be 256. + * + * @remark @wayland Gamma handling is currently unavailable, this function will + * always emit @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified gamma ramp is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); + +/*! @brief Resets all window hints to their default values. + * + * This function resets all window hints to their + * [default values](@ref window_hints_values). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hints + * @sa @ref glfwWindowHint + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwDefaultWindowHints(void); + +/*! @brief Sets the specified window hint to the desired value. + * + * This function sets hints for the next call to @ref glfwCreateWindow. The + * hints, once set, retain their values until changed by a call to @ref + * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is + * terminated. + * + * This function does not check whether the specified hint values are valid. + * If you set hints to invalid values this will instead be reported by the next + * call to @ref glfwCreateWindow. + * + * @param[in] hint The [window hint](@ref window_hints) to set. + * @param[in] value The new value of the window hint. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hints + * @sa @ref glfwDefaultWindowHints + * + * @since Added in version 3.0. Replaces `glfwOpenWindowHint`. + * + * @ingroup window + */ +GLFWAPI void glfwWindowHint(int hint, int value); + +/*! @brief Creates a window and its associated context. + * + * This function creates a window and its associated OpenGL or OpenGL ES + * context. Most of the options controlling how the window and its context + * should be created are specified with [window hints](@ref window_hints). + * + * Successful creation does not change which context is current. Before you + * can use the newly created context, you need to + * [make it current](@ref context_current). For information about the `share` + * parameter, see @ref context_sharing. + * + * The created window, framebuffer and context may differ from what you + * requested, as not all parameters and hints are + * [hard constraints](@ref window_hints_hard). This includes the size of the + * window, especially for full screen windows. To query the actual attributes + * of the created window, framebuffer and context, see @ref + * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. + * + * To create a full screen window, you need to specify the monitor the window + * will cover. If no monitor is specified, the window will be windowed mode. + * Unless you have a way for the user to choose a specific monitor, it is + * recommended that you pick the primary monitor. For more information on how + * to query connected monitors, see @ref monitor_monitors. + * + * For full screen windows, the specified size becomes the resolution of the + * window's _desired video mode_. As long as a full screen window is not + * iconified, the supported video mode most closely matching the desired video + * mode is set for the specified monitor. For more information about full + * screen windows, including the creation of so called _windowed full screen_ + * or _borderless full screen_ windows, see @ref window_windowed_full_screen. + * + * Once you have created the window, you can switch it between windowed and + * full screen mode with @ref glfwSetWindowMonitor. This will not affect its + * OpenGL or OpenGL ES context. + * + * By default, newly created windows use the placement recommended by the + * window system. To create the window at a specific position, make it + * initially invisible using the [GLFW_VISIBLE](@ref GLFW_VISIBLE_hint) window + * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) + * it. + * + * As long as at least one full screen window is not iconified, the screensaver + * is prohibited from starting. + * + * Window systems put limits on window sizes. Very large or very small window + * dimensions may be overridden by the window system on creation. Check the + * actual [size](@ref window_size) after creation. + * + * The [swap interval](@ref buffer_swap) is not set during window creation and + * the initial value may vary depending on driver settings and defaults. + * + * @param[in] width The desired width, in screen coordinates, of the window. + * This must be greater than zero. + * @param[in] height The desired height, in screen coordinates, of the window. + * This must be greater than zero. + * @param[in] title The initial, UTF-8 encoded window title. + * @param[in] monitor The monitor to use for full screen mode, or `NULL` for + * windowed mode. + * @param[in] share The window whose context to share resources with, or `NULL` + * to not share resources. + * @return The handle of the created window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref + * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @win32 Window creation will fail if the Microsoft GDI software + * OpenGL implementation is the only one available. + * + * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it + * will be set as the initial icon for the window. If no such icon is present, + * the `IDI_WINLOGO` icon will be used instead. To set a different icon, see + * @ref glfwSetWindowIcon. + * + * @remark @win32 The context to share resources with must not be current on + * any other thread. + * + * @remark @macos The OS only supports forward-compatible core profile contexts + * for OpenGL versions 3.2 and later. Before creating an OpenGL context of + * version 3.2 or later you must set the + * [GLFW_OPENGL_FORWARD_COMPAT](@ref GLFW_OPENGL_FORWARD_COMPAT_hint) and + * [GLFW_OPENGL_PROFILE](@ref GLFW_OPENGL_PROFILE_hint) hints accordingly. + * OpenGL 3.0 and 3.1 contexts are not supported at all on macOS. + * + * @remark @macos The GLFW window has no icon, as it is not a document + * window, but the dock icon will be the same as the application bundle's icon. + * For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @remark @macos The first time a window is created the menu bar is created. + * If GLFW finds a `MainMenu.nib` it is loaded and assumed to contain a menu + * bar. Otherwise a minimal menu bar is created manually with common commands + * like Hide, Quit and About. The About entry opens a minimal about dialog + * with information from the application's bundle. Menu bar creation can be + * disabled entirely with the @ref GLFW_COCOA_MENUBAR init hint. + * + * @remark @macos On OS X 10.10 and later the window frame will not be rendered + * at full resolution on Retina displays unless the + * [GLFW_COCOA_RETINA_FRAMEBUFFER](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint) + * hint is `GLFW_TRUE` and the `NSHighResolutionCapable` key is enabled in the + * application bundle's `Info.plist`. For more information, see + * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) + * in the Mac Developer Library. The GLFW test and example programs use + * a custom `Info.plist` template for this, which can be found as + * `CMake/MacOSXBundleInfo.plist.in` in the source tree. + * + * @remark @macos When activating frame autosaving with + * [GLFW_COCOA_FRAME_AUTOSAVE](@ref GLFW_COCOA_FRAME_AUTOSAVE_hint), the + * specified window size may be overriden by a previously saved size and + * position. + * + * @remark @x11 Some window managers will not respect the placement of + * initially hidden windows. + * + * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for + * a window to reach its requested state. This means you may not be able to + * query the final size, position or other attributes directly after window + * creation. + * + * @remark @x11 The name and class of the `WM_CLASS` window property will by + * default be set to the window title passed to this function. Set the @ref + * GLFW_X11_WM_CLASS_NAME and @ref GLFW_X11_WM_CLASS_CLASS init hints before + * initialization to override this. + * + * @remark @wayland The window frame is currently unimplemented, as if + * [GLFW_DECORATED](@ref GLFW_DECORATED_hint) was always set to `GLFW_FALSE`. + * A compositor can still emit close, resize or maximize events, using for + * example a keybind mechanism. + * + * @remark @wayland A full screen window will not attempt to change the mode, + * no matter what the requested size or refresh rate. + * + * @remark @wayland The wl_shell protocol does not support window + * icons, the window will inherit the one defined in the application's + * desktop file, so this function emits @ref GLFW_PLATFORM_ERROR. + * + * @remark @wayland Screensaver inhibition is currently unimplemented. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_creation + * @sa @ref glfwDestroyWindow + * + * @since Added in version 3.0. Replaces `glfwOpenWindow`. + * + * @ingroup window + */ +GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); + +/*! @brief Destroys the specified window and its context. + * + * This function destroys the specified window and its context. On calling + * this function, no further callbacks will be called for that window. + * + * If the context of the specified window is current on the main thread, it is + * detached before being destroyed. + * + * @param[in] window The window to destroy. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @note The context of the specified window must not be current on any other + * thread when this function is called. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_creation + * @sa @ref glfwCreateWindow + * + * @since Added in version 3.0. Replaces `glfwCloseWindow`. + * + * @ingroup window + */ +GLFWAPI void glfwDestroyWindow(GLFWwindow* window); + +/*! @brief Checks the close flag of the specified window. + * + * This function returns the value of the close flag of the specified window. + * + * @param[in] window The window to query. + * @return The value of the close flag. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_close + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); + +/*! @brief Sets the close flag of the specified window. + * + * This function sets the value of the close flag of the specified window. + * This can be used to override the user's attempt to close the window, or + * to signal that it should be closed. + * + * @param[in] window The window whose flag to change. + * @param[in] value The new value. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_close + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); + +/*! @brief Sets the title of the specified window. + * + * This function sets the window title, encoded as UTF-8, of the specified + * window. + * + * @param[in] window The window whose title to change. + * @param[in] title The UTF-8 encoded window title. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @macos The window title will not be updated until the next time you + * process events. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_title + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); + +/*! @brief Sets the icon for the specified window. + * + * This function sets the icon of the specified window. If passed an array of + * candidate images, those of or closest to the sizes desired by the system are + * selected. If no images are specified, the window reverts to its default + * icon. + * + * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight + * bits per channel with the red channel first. They are arranged canonically + * as packed sequential rows, starting from the top-left corner. + * + * The desired image sizes varies depending on platform and system settings. + * The selected images will be rescaled as needed. Good sizes include 16x16, + * 32x32 and 48x48. + * + * @param[in] window The window whose icon to set. + * @param[in] count The number of images in the specified array, or zero to + * revert to the default window icon. + * @param[in] images The images to create the icon from. This is ignored if + * count is zero. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified image data is copied before this function + * returns. + * + * @remark @macos The GLFW window has no icon, as it is not a document + * window, so this function does nothing. The dock icon will be the same as + * the application bundle's icon. For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @remark @wayland The wl_shell protocol does not support icons, the window + * will inherit the one defined in the application's desktop file, so this + * function emits @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_icon + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images); + +/*! @brief Retrieves the position of the client area of the specified window. + * + * This function retrieves the position, in screen coordinates, of the + * upper-left corner of the client area of the specified window. + * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * + * @param[in] window The window to query. + * @param[out] xpos Where to store the x-coordinate of the upper-left corner of + * the client area, or `NULL`. + * @param[out] ypos Where to store the y-coordinate of the upper-left corner of + * the client area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland There is no way for an application to retrieve the global + * position of its windows, this function will always emit @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_pos + * @sa @ref glfwSetWindowPos + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); + +/*! @brief Sets the position of the client area of the specified window. + * + * This function sets the position, in screen coordinates, of the upper-left + * corner of the client area of the specified windowed mode window. If the + * window is a full screen window, this function does nothing. + * + * __Do not use this function__ to move an already visible window unless you + * have very good reasons for doing so, as it will confuse and annoy the user. + * + * The window manager may put limits on what positions are allowed. GLFW + * cannot and should not override these limits. + * + * @param[in] window The window to query. + * @param[in] xpos The x-coordinate of the upper-left corner of the client area. + * @param[in] ypos The y-coordinate of the upper-left corner of the client area. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland There is no way for an application to set the global + * position of its windows, this function will always emit @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_pos + * @sa @ref glfwGetWindowPos + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); + +/*! @brief Retrieves the size of the client area of the specified window. + * + * This function retrieves the size, in screen coordinates, of the client area + * of the specified window. If you wish to retrieve the size of the + * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose size to retrieve. + * @param[out] width Where to store the width, in screen coordinates, of the + * client area, or `NULL`. + * @param[out] height Where to store the height, in screen coordinates, of the + * client area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * @sa @ref glfwSetWindowSize + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); + +/*! @brief Sets the size limits of the specified window. + * + * This function sets the size limits of the client area of the specified + * window. If the window is full screen, the size limits only take effect + * once it is made windowed. If the window is not resizable, this function + * does nothing. + * + * The size limits are applied immediately to a windowed mode window and may + * cause it to be resized. + * + * The maximum dimensions must be greater than or equal to the minimum + * dimensions and all must be greater than or equal to zero. + * + * @param[in] window The window to set limits for. + * @param[in] minwidth The minimum width, in screen coordinates, of the client + * area, or `GLFW_DONT_CARE`. + * @param[in] minheight The minimum height, in screen coordinates, of the + * client area, or `GLFW_DONT_CARE`. + * @param[in] maxwidth The maximum width, in screen coordinates, of the client + * area, or `GLFW_DONT_CARE`. + * @param[in] maxheight The maximum height, in screen coordinates, of the + * client area, or `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @remark @wayland The size limits will not be applied until the window is + * actually resized, either by the user or by the compositor. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa @ref glfwSetWindowAspectRatio + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); + +/*! @brief Sets the aspect ratio of the specified window. + * + * This function sets the required aspect ratio of the client area of the + * specified window. If the window is full screen, the aspect ratio only takes + * effect once it is made windowed. If the window is not resizable, this + * function does nothing. + * + * The aspect ratio is specified as a numerator and a denominator and both + * values must be greater than zero. For example, the common 16:9 aspect ratio + * is specified as 16 and 9, respectively. + * + * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect + * ratio limit is disabled. + * + * The aspect ratio is applied immediately to a windowed mode window and may + * cause it to be resized. + * + * @param[in] window The window to set limits for. + * @param[in] numer The numerator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * @param[in] denom The denominator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @remark @wayland The aspect ratio will not be applied until the window is + * actually resized, either by the user or by the compositor. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa @ref glfwSetWindowSizeLimits + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); + +/*! @brief Sets the size of the client area of the specified window. + * + * This function sets the size, in screen coordinates, of the client area of + * the specified window. + * + * For full screen windows, this function updates the resolution of its desired + * video mode and switches to the video mode closest to it, without affecting + * the window's context. As the context is unaffected, the bit depths of the + * framebuffer remain unchanged. + * + * If you wish to update the refresh rate of the desired video mode in addition + * to its resolution, see @ref glfwSetWindowMonitor. + * + * The window manager may put limits on what sizes are allowed. GLFW cannot + * and should not override these limits. + * + * @param[in] window The window to resize. + * @param[in] width The desired width, in screen coordinates, of the window + * client area. + * @param[in] height The desired height, in screen coordinates, of the window + * client area. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland A full screen window will not attempt to change the mode, + * no matter what the requested size. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * @sa @ref glfwGetWindowSize + * @sa @ref glfwSetWindowMonitor + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); + +/*! @brief Retrieves the size of the framebuffer of the specified window. + * + * This function retrieves the size, in pixels, of the framebuffer of the + * specified window. If you wish to retrieve the size of the window in screen + * coordinates, see @ref glfwGetWindowSize. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose framebuffer to query. + * @param[out] width Where to store the width, in pixels, of the framebuffer, + * or `NULL`. + * @param[out] height Where to store the height, in pixels, of the framebuffer, + * or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_fbsize + * @sa @ref glfwSetFramebufferSizeCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); + +/*! @brief Retrieves the size of the frame of the window. + * + * This function retrieves the size, in screen coordinates, of each edge of the + * frame of the specified window. This size includes the title bar, if the + * window has one. The size of the frame may vary depending on the + * [window-related hints](@ref window_hints_wnd) used to create it. + * + * Because this function retrieves the size of each window frame edge and not + * the offset along a particular coordinate axis, the retrieved values will + * always be zero or positive. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose frame size to query. + * @param[out] left Where to store the size, in screen coordinates, of the left + * edge of the window frame, or `NULL`. + * @param[out] top Where to store the size, in screen coordinates, of the top + * edge of the window frame, or `NULL`. + * @param[out] right Where to store the size, in screen coordinates, of the + * right edge of the window frame, or `NULL`. + * @param[out] bottom Where to store the size, in screen coordinates, of the + * bottom edge of the window frame, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland The window frame is currently unimplemented, as if + * [GLFW_DECORATED](@ref GLFW_DECORATED_hint) was always set to `GLFW_FALSE`, + * so the returned values will always be zero. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in version 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); + +/*! @brief Retrieves the content scale for the specified window. + * + * This function retrieves the content scale for the specified window. The + * content scale is the ratio between the current DPI and the platform's + * default DPI. If you scale all pixel dimensions by this scale then your + * content should appear at an appropriate size. This is especially important + * for text and any UI elements. + * + * On systems where each monitors can have its own content scale, the window + * content scale will depend on which monitor the system considers the window + * to be on. + * + * @param[in] window The window to query. + * @param[out] xscale Where to store the x-axis content scale, or `NULL`. + * @param[out] yscale Where to store the y-axis content scale, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_scale + * @sa @ref glfwGetMonitorContentScale + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowContentScale(GLFWwindow* window, float* xscale, float* yscale); + +/*! @brief Iconifies the specified window. + * + * This function iconifies (minimizes) the specified window if it was + * previously restored. If the window is already iconified, this function does + * nothing. + * + * If the specified window is a full screen window, the original monitor + * resolution is restored until the window is restored. + * + * @param[in] window The window to iconify. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland There is no concept of iconification in wl_shell, this + * function will always emit @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * @sa @ref glfwRestoreWindow + * @sa @ref glfwMaximizeWindow + * + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwIconifyWindow(GLFWwindow* window); + +/*! @brief Restores the specified window. + * + * This function restores the specified window if it was previously iconified + * (minimized) or maximized. If the window is already restored, this function + * does nothing. + * + * If the specified window is a full screen window, the resolution chosen for + * the window is restored on the selected monitor. + * + * @param[in] window The window to restore. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * @sa @ref glfwIconifyWindow + * @sa @ref glfwMaximizeWindow + * + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwRestoreWindow(GLFWwindow* window); + +/*! @brief Maximizes the specified window. + * + * This function maximizes the specified window if it was previously not + * maximized. If the window is already maximized, this function does nothing. + * + * If the specified window is a full screen window, this function does nothing. + * + * @param[in] window The window to maximize. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_iconify + * @sa @ref glfwIconifyWindow + * @sa @ref glfwRestoreWindow + * + * @since Added in GLFW 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); + +/*! @brief Makes the specified window visible. + * + * This function makes the specified window visible if it was previously + * hidden. If the window is already visible or is in full screen mode, this + * function does nothing. + * + * @param[in] window The window to make visible. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hide + * @sa @ref glfwHideWindow + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwShowWindow(GLFWwindow* window); + +/*! @brief Hides the specified window. + * + * This function hides the specified window if it was previously visible. If + * the window is already hidden or is in full screen mode, this function does + * nothing. + * + * @param[in] window The window to hide. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hide + * @sa @ref glfwShowWindow + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwHideWindow(GLFWwindow* window); + +/*! @brief Brings the specified window to front and sets input focus. + * + * This function brings the specified window to front and sets input focus. + * The window should already be visible and not iconified. + * + * By default, both windowed and full screen mode windows are focused when + * initially created. Set the [GLFW_FOCUSED](@ref GLFW_FOCUSED_hint) to + * disable this behavior. + * + * __Do not use this function__ to steal focus from other applications unless + * you are certain that is what the user wants. Focus stealing can be + * extremely disruptive. + * + * For a less disruptive way of getting the user's attention, see + * [attention requests](@ref window_attention). + * + * @param[in] window The window to give input focus. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland It is not possible for an application to bring its windows + * to front, this function will always emit @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_focus + * @sa @ref window_attention + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwFocusWindow(GLFWwindow* window); + +/*! @brief Requests user attention to the specified window. + * + * This function requests user attention to the specified window. On + * platforms where this is not supported, attention is requested to the + * application as a whole. + * + * Once the user has given attention, usually by focusing the window or + * application, the system will end the request automatically. + * + * @param[in] window The window to request attention to. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @macos Attention is requested to the application as a whole, not the + * specific window. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_attention + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwRequestWindowAttention(GLFWwindow* window); + +/*! @brief Returns the monitor that the window uses for full screen mode. + * + * This function returns the handle of the monitor that the specified window is + * in full screen on. + * + * @param[in] window The window to query. + * @return The monitor, or `NULL` if the window is in windowed mode or an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa @ref glfwSetWindowMonitor + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); + +/*! @brief Sets the mode, monitor, video mode and placement of a window. + * + * This function sets the monitor that the window uses for full screen mode or, + * if the monitor is `NULL`, makes it windowed mode. + * + * When setting a monitor, this function updates the width, height and refresh + * rate of the desired video mode and switches to the video mode closest to it. + * The window position is ignored when setting a monitor. + * + * When the monitor is `NULL`, the position, width and height are used to + * place the window client area. The refresh rate is ignored when no monitor + * is specified. + * + * If you only wish to update the resolution of a full screen window or the + * size of a windowed mode window, see @ref glfwSetWindowSize. + * + * When a window transitions from full screen to windowed mode, this function + * restores any previous window settings such as whether it is decorated, + * floating, resizable, has size or aspect ratio limits, etc. + * + * @param[in] window The window whose monitor, size or video mode to set. + * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. + * @param[in] xpos The desired x-coordinate of the upper-left corner of the + * client area. + * @param[in] ypos The desired y-coordinate of the upper-left corner of the + * client area. + * @param[in] width The desired with, in screen coordinates, of the client area + * or video mode. + * @param[in] height The desired height, in screen coordinates, of the client + * area or video mode. + * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode, + * or `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark The OpenGL or OpenGL ES context will not be destroyed or otherwise + * affected by any resizing or mode switching, although you may need to update + * your viewport if the framebuffer size has changed. + * + * @remark @wayland The desired window position is ignored, as there is no way + * for an application to set this property. + * + * @remark @wayland Setting the window to full screen will not attempt to + * change the mode, no matter what the requested size or refresh rate. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa @ref window_full_screen + * @sa @ref glfwGetWindowMonitor + * @sa @ref glfwSetWindowSize + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + +/*! @brief Returns an attribute of the specified window. + * + * This function returns the value of an attribute of the specified window or + * its OpenGL or OpenGL ES context. + * + * @param[in] window The window to query. + * @param[in] attrib The [window attribute](@ref window_attribs) whose value to + * return. + * @return The value of the attribute, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @remark Framebuffer related hints are not window attributes. See @ref + * window_attribs_fb for more information. + * + * @remark Zero is a valid value for many window and context related + * attributes so you cannot use a return value of zero as an indication of + * errors. However, this function should not fail as long as it is passed + * valid arguments and the library has been [initialized](@ref intro_init). + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_attribs + * @sa @ref glfwSetWindowAttrib + * + * @since Added in version 3.0. Replaces `glfwGetWindowParam` and + * `glfwGetGLVersion`. + * + * @ingroup window + */ +GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); + +/*! @brief Sets an attribute of the specified window. + * + * This function sets the value of an attribute of the specified window. + * + * The supported attributes are [GLFW_DECORATED](@ref GLFW_DECORATED_attrib), + * [GLFW_RESIZABLE](@ref GLFW_RESIZABLE_attrib), + * [GLFW_FLOATING](@ref GLFW_FLOATING_attrib) and + * [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib). + * + * Some of these attributes are ignored for full screen windows. The new + * value will take effect if the window is later made windowed. + * + * Some of these attributes are ignored for windowed mode windows. The new + * value will take effect if the window is later made full screen. + * + * @param[in] window The window to set the attribute for. + * @param[in] attrib A supported window attribute. + * @param[in] value `GLFW_TRUE` or `GLFW_FALSE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark Calling @ref glfwGetWindowAttrib will always return the latest + * value, even if that value is ignored by the current mode of the window. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_attribs + * @sa @ref glfwGetWindowAttrib + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowAttrib(GLFWwindow* window, int attrib, int value); + +/*! @brief Sets the user pointer of the specified window. + * + * This function sets the user-defined pointer of the specified window. The + * current value is retained until the window is destroyed. The initial value + * is `NULL`. + * + * @param[in] window The window whose pointer to set. + * @param[in] pointer The new value. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_userptr + * @sa @ref glfwGetWindowUserPointer + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); + +/*! @brief Returns the user pointer of the specified window. + * + * This function returns the current value of the user-defined pointer of the + * specified window. The initial value is `NULL`. + * + * @param[in] window The window whose pointer to return. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_userptr + * @sa @ref glfwSetWindowUserPointer + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); + +/*! @brief Sets the position callback for the specified window. + * + * This function sets the position callback of the specified window, which is + * called when the window is moved. The callback is provided with the + * position, in screen coordinates, of the upper-left corner of the client area + * of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @wayland This callback will never be called, as there is no way for + * an application to know its global position. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_pos + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun cbfun); + +/*! @brief Sets the size callback for the specified window. + * + * This function sets the size callback of the specified window, which is + * called when the window is resized. The callback is provided with the size, + * in screen coordinates, of the client area of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup window + */ +GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun cbfun); + +/*! @brief Sets the close callback for the specified window. + * + * This function sets the close callback of the specified window, which is + * called when the user attempts to close the window, for example by clicking + * the close widget in the title bar. + * + * The close flag is set before this callback is called, but you can modify it + * at any time with @ref glfwSetWindowShouldClose. + * + * The close callback is not triggered by @ref glfwDestroyWindow. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @macos Selecting Quit from the application menu will trigger the + * close callback for all windows. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_close + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup window + */ +GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun cbfun); + +/*! @brief Sets the refresh callback for the specified window. + * + * This function sets the refresh callback of the specified window, which is + * called when the client area of the window needs to be redrawn, for example + * if the window has been exposed after having been covered by another window. + * + * On compositing window systems such as Aero, Compiz, Aqua or Wayland, where + * the window contents are saved off-screen, this callback may be called only + * very infrequently or never at all. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_refresh + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup window + */ +GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun cbfun); + +/*! @brief Sets the focus callback for the specified window. + * + * This function sets the focus callback of the specified window, which is + * called when the window gains or loses input focus. + * + * After the focus callback is called for a window that lost input focus, + * synthetic key and mouse button release events will be generated for all such + * that had been pressed. For more information, see @ref glfwSetKeyCallback + * and @ref glfwSetMouseButtonCallback. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_focus + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun cbfun); + +/*! @brief Sets the iconify callback for the specified window. + * + * This function sets the iconification callback of the specified window, which + * is called when the window is iconified or restored. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @wayland The wl_shell protocol has no concept of iconification, + * this callback will never be called. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun cbfun); + +/*! @brief Sets the maximize callback for the specified window. + * + * This function sets the maximization callback of the specified window, which + * is called when the window is maximized or restored. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_maximize + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, GLFWwindowmaximizefun cbfun); + +/*! @brief Sets the framebuffer resize callback for the specified window. + * + * This function sets the framebuffer resize callback of the specified window, + * which is called when the framebuffer of the specified window is resized. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_fbsize + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun); + +/*! @brief Processes all pending events. + * + * This function processes only those events that are already in the event + * queue and then returns immediately. Processing events will cause the window + * and input callbacks associated with those events to be called. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * Do not assume that callbacks you set will _only_ be called in response to + * event processing functions like this one. While it is necessary to poll for + * events, window systems that require GLFW to register callbacks of its own + * can pass events to GLFW in response to many window system function calls. + * GLFW will pass those events on to the application callbacks before + * returning. + * + * Event processing is not required for joystick input to work. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa @ref glfwWaitEvents + * @sa @ref glfwWaitEventsTimeout + * + * @since Added in version 1.0. + * + * @ingroup window + */ +GLFWAPI void glfwPollEvents(void); + +/*! @brief Waits until events are queued and processes them. + * + * This function puts the calling thread to sleep until at least one event is + * available in the event queue. Once one or more events are available, + * it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue + * are processed and the function then returns immediately. Processing events + * will cause the window and input callbacks associated with those events to be + * called. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * Do not assume that callbacks you set will _only_ be called in response to + * event processing functions like this one. While it is necessary to poll for + * events, window systems that require GLFW to register callbacks of its own + * can pass events to GLFW in response to many window system function calls. + * GLFW will pass those events on to the application callbacks before + * returning. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * Event processing is not required for joystick input to work. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa @ref glfwPollEvents + * @sa @ref glfwWaitEventsTimeout + * + * @since Added in version 2.5. + * + * @ingroup window + */ +GLFWAPI void glfwWaitEvents(void); + +/*! @brief Waits with timeout until events are queued and processes them. + * + * This function puts the calling thread to sleep until at least one event is + * available in the event queue, or until the specified timeout is reached. If + * one or more events are available, it behaves exactly like @ref + * glfwPollEvents, i.e. the events in the queue are processed and the function + * then returns immediately. Processing events will cause the window and input + * callbacks associated with those events to be called. + * + * The timeout value must be a positive finite number. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * Do not assume that callbacks you set will _only_ be called in response to + * event processing functions like this one. While it is necessary to poll for + * events, window systems that require GLFW to register callbacks of its own + * can pass events to GLFW in response to many window system function calls. + * GLFW will pass those events on to the application callbacks before + * returning. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * Event processing is not required for joystick input to work. + * + * @param[in] timeout The maximum amount of time, in seconds, to wait. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa @ref glfwPollEvents + * @sa @ref glfwWaitEvents + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwWaitEventsTimeout(double timeout); + +/*! @brief Posts an empty event to the event queue. + * + * This function posts an empty event from the current thread to the event + * queue, causing @ref glfwWaitEvents or @ref glfwWaitEventsTimeout to return. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref events + * @sa @ref glfwWaitEvents + * @sa @ref glfwWaitEventsTimeout + * + * @since Added in version 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwPostEmptyEvent(void); + +/*! @brief Returns the value of an input option for the specified window. + * + * This function returns the value of an input option for the specified window. + * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or + * @ref GLFW_STICKY_MOUSE_BUTTONS. + * + * @param[in] window The window to query. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref glfwSetInputMode + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); + +/*! @brief Sets an input option for the specified window. + * + * This function sets an input mode option for the specified window. The mode + * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or + * @ref GLFW_STICKY_MOUSE_BUTTONS. + * + * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor + * modes: + * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. + * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client + * area of the window but does not restrict the cursor from leaving. + * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual + * and unlimited cursor movement. This is useful for implementing for + * example 3D camera controls. + * + * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to + * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are + * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` + * the next time it is called even if the key had been released before the + * call. This is useful when you are only interested in whether keys have been + * pressed but not when or in which order. + * + * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either + * `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it. + * If sticky mouse buttons are enabled, a mouse button press will ensure that + * @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even + * if the mouse button had been released before the call. This is useful when + * you are only interested in whether mouse buttons have been pressed but not + * when or in which order. + * + * @param[in] window The window whose input mode to set. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * @param[in] value The new value of the specified input mode. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref glfwGetInputMode + * + * @since Added in version 3.0. Replaces `glfwEnable` and `glfwDisable`. + * + * @ingroup input + */ +GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); + +/*! @brief Returns the layout-specific name of the specified printable key. + * + * This function returns the name of the specified printable key, encoded as + * UTF-8. This is typically the character that key would produce without any + * modifier keys, intended for displaying key bindings to the user. For dead + * keys, it is typically the diacritic it would add to a character. + * + * __Do not use this function__ for [text input](@ref input_char). You will + * break text input for many languages even if it happens to work for yours. + * + * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used to identify the key, + * otherwise the scancode is ignored. If you specify a non-printable key, or + * `GLFW_KEY_UNKNOWN` and a scancode that maps to a non-printable key, this + * function returns `NULL` but does not emit an error. + * + * This behavior allows you to always pass in the arguments in the + * [key callback](@ref input_key) without modification. + * + * The printable keys are: + * - `GLFW_KEY_APOSTROPHE` + * - `GLFW_KEY_COMMA` + * - `GLFW_KEY_MINUS` + * - `GLFW_KEY_PERIOD` + * - `GLFW_KEY_SLASH` + * - `GLFW_KEY_SEMICOLON` + * - `GLFW_KEY_EQUAL` + * - `GLFW_KEY_LEFT_BRACKET` + * - `GLFW_KEY_RIGHT_BRACKET` + * - `GLFW_KEY_BACKSLASH` + * - `GLFW_KEY_WORLD_1` + * - `GLFW_KEY_WORLD_2` + * - `GLFW_KEY_0` to `GLFW_KEY_9` + * - `GLFW_KEY_A` to `GLFW_KEY_Z` + * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9` + * - `GLFW_KEY_KP_DECIMAL` + * - `GLFW_KEY_KP_DIVIDE` + * - `GLFW_KEY_KP_MULTIPLY` + * - `GLFW_KEY_KP_SUBTRACT` + * - `GLFW_KEY_KP_ADD` + * - `GLFW_KEY_KP_EQUAL` + * + * Names for printable keys depend on keyboard layout, while names for + * non-printable keys are the same across layouts but depend on the application + * language and should be localized along with other user interface text. + * + * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`. + * @param[in] scancode The scancode of the key to query. + * @return The UTF-8 encoded, layout-specific name of the key, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetKeyName, or until the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key_name + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetKeyName(int key, int scancode); + +/*! @brief Returns the platform-specific scancode of the specified key. + * + * This function returns the platform-specific scancode of the specified key. + * + * If the key is `GLFW_KEY_UNKNOWN` or does not exist on the keyboard this + * method will return `-1`. + * + * @param[in] key Any [named key](@ref keys). + * @return The platform-specific scancode for the key, or `-1` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref input_key + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwGetKeyScancode(int key); + +/*! @brief Returns the last reported state of a keyboard key for the specified + * window. + * + * This function returns the last state reported for the specified key to the + * specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to + * the key callback. + * + * If the @ref GLFW_STICKY_KEYS input mode is enabled, this function returns + * `GLFW_PRESS` the first time you call it for a key that was pressed, even if + * that key has already been released. + * + * The key functions deal with physical keys, with [key tokens](@ref keys) + * named after their use on the standard US keyboard layout. If you want to + * input text, use the Unicode character callback instead. + * + * The [modifier key bit masks](@ref mods) are not key tokens and cannot be + * used with this function. + * + * __Do not use this function__ to implement [text input](@ref input_char). + * + * @param[in] window The desired window. + * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is + * not a valid key for this function. + * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup input + */ +GLFWAPI int glfwGetKey(GLFWwindow* window, int key); + +/*! @brief Returns the last reported state of a mouse button for the specified + * window. + * + * This function returns the last state reported for the specified mouse button + * to the specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. + * + * If the @ref GLFW_STICKY_MOUSE_BUTTONS input mode is enabled, this function + * `GLFW_PRESS` the first time you call it for a mouse button that was pressed, + * even if that mouse button has already been released. + * + * @param[in] window The desired window. + * @param[in] button The desired [mouse button](@ref buttons). + * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup input + */ +GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); + +/*! @brief Retrieves the position of the cursor relative to the client area of + * the window. + * + * This function returns the position of the cursor, in screen coordinates, + * relative to the upper-left corner of the client area of the specified + * window. + * + * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor + * position is unbounded and limited only by the minimum and maximum values of + * a `double`. + * + * The coordinate can be converted to their integer equivalents with the + * `floor` function. Casting directly to an integer type works for positive + * coordinates, but fails for negative ones. + * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * + * @param[in] window The desired window. + * @param[out] xpos Where to store the cursor x-coordinate, relative to the + * left edge of the client area, or `NULL`. + * @param[out] ypos Where to store the cursor y-coordinate, relative to the to + * top edge of the client area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * @sa @ref glfwSetCursorPos + * + * @since Added in version 3.0. Replaces `glfwGetMousePos`. + * + * @ingroup input + */ +GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); + +/*! @brief Sets the position of the cursor, relative to the client area of the + * window. + * + * This function sets the position, in screen coordinates, of the cursor + * relative to the upper-left corner of the client area of the specified + * window. The window must have input focus. If the window does not have + * input focus when this function is called, it fails silently. + * + * __Do not use this function__ to implement things like camera controls. GLFW + * already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the + * cursor, transparently re-centers it and provides unconstrained cursor + * motion. See @ref glfwSetInputMode for more information. + * + * If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is + * unconstrained and limited only by the minimum and maximum values of + * a `double`. + * + * @param[in] window The desired window. + * @param[in] xpos The desired x-coordinate, relative to the left edge of the + * client area. + * @param[in] ypos The desired y-coordinate, relative to the top edge of the + * client area. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland This function will only work when the cursor mode is + * `GLFW_CURSOR_DISABLED`, otherwise it will do nothing. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * @sa @ref glfwGetCursorPos + * + * @since Added in version 3.0. Replaces `glfwSetMousePos`. + * + * @ingroup input + */ +GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); + +/*! @brief Creates a custom cursor. + * + * Creates a new custom cursor image that can be set for a window with @ref + * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. + * Any remaining cursors are destroyed by @ref glfwTerminate. + * + * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight + * bits per channel with the red channel first. They are arranged canonically + * as packed sequential rows, starting from the top-left corner. + * + * The cursor hotspot is specified in pixels, relative to the upper-left corner + * of the cursor image. Like all other coordinate systems in GLFW, the X-axis + * points to the right and the Y-axis points down. + * + * @param[in] image The desired cursor image. + * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot. + * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. + * @return The handle of the created cursor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified image data is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa @ref glfwDestroyCursor + * @sa @ref glfwCreateStandardCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); + +/*! @brief Creates a cursor with a standard shape. + * + * Returns a cursor with a [standard shape](@ref shapes), that can be set for + * a window with @ref glfwSetCursor. + * + * @param[in] shape One of the [standard shapes](@ref shapes). + * @return A new cursor ready to use or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa @ref glfwCreateCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); + +/*! @brief Destroys a cursor. + * + * This function destroys a cursor previously created with @ref + * glfwCreateCursor. Any remaining cursors will be destroyed by @ref + * glfwTerminate. + * + * If the specified cursor is current for any window, that window will be + * reverted to the default cursor. This does not affect the cursor mode. + * + * @param[in] cursor The cursor object to destroy. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa @ref glfwCreateCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); + +/*! @brief Sets the cursor for the window. + * + * This function sets the cursor image to be used when the cursor is over the + * client area of the specified window. The set cursor will only be visible + * when the [cursor mode](@ref cursor_mode) of the window is + * `GLFW_CURSOR_NORMAL`. + * + * On some platforms, the set cursor may not be visible unless the window also + * has input focus. + * + * @param[in] window The window to set the cursor for. + * @param[in] cursor The cursor to set, or `NULL` to switch back to the default + * arrow cursor. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); + +/*! @brief Sets the key callback. + * + * This function sets the key callback of the specified window, which is called + * when a key is pressed, repeated or released. + * + * The key functions deal with physical keys, with layout independent + * [key tokens](@ref keys) named after their values in the standard US keyboard + * layout. If you want to input text, use the + * [character callback](@ref glfwSetCharCallback) instead. + * + * When a window loses input focus, it will generate synthetic key release + * events for all pressed keys. You can tell these events from user-generated + * events by the fact that the synthetic ones are generated after the focus + * loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. + * + * The scancode of a key is specific to that platform or sometimes even to that + * machine. Scancodes are intended to allow users to bind keys that don't have + * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their + * state is not saved and so it cannot be queried with @ref glfwGetKey. + * + * Sometimes GLFW needs to generate synthetic key events, in which case the + * scancode may be zero. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new key callback, or `NULL` to remove the currently + * set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup input + */ +GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); + +/*! @brief Sets the Unicode character callback. + * + * This function sets the character callback of the specified window, which is + * called when a Unicode character is input. + * + * The character callback is intended for Unicode text input. As it deals with + * characters, it is keyboard layout dependent, whereas the + * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1 + * to physical keys, as a key may produce zero, one or more characters. If you + * want to know whether a specific physical key was pressed or released, see + * the key callback instead. + * + * The character callback behaves as system text input normally does and will + * not be called if modifier keys are held down that would prevent normal text + * input on that platform, for example a Super (Command) key on macOS or Alt key + * on Windows. There is a + * [character with modifiers callback](@ref glfwSetCharModsCallback) that + * receives these events. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in version 2.4. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup input + */ +GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); + +/*! @brief Sets the Unicode character with modifiers callback. + * + * This function sets the character with modifiers callback of the specified + * window, which is called when a Unicode character is input regardless of what + * modifier keys are used. + * + * The character with modifiers callback is intended for implementing custom + * Unicode character input. For regular Unicode text input, see the + * [character callback](@ref glfwSetCharCallback). Like the character + * callback, the character with modifiers callback deals with characters and is + * keyboard layout dependent. Characters do not map 1:1 to physical keys, as + * a key may produce zero, one or more characters. If you want to know whether + * a specific physical key was pressed or released, see the + * [key callback](@ref glfwSetKeyCallback) instead. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun); + +/*! @brief Sets the mouse button callback. + * + * This function sets the mouse button callback of the specified window, which + * is called when a mouse button is pressed or released. + * + * When a window loses input focus, it will generate synthetic mouse button + * release events for all pressed mouse buttons. You can tell these events + * from user-generated events by the fact that the synthetic ones are generated + * after the focus loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup input + */ +GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun cbfun); + +/*! @brief Sets the cursor position callback. + * + * This function sets the cursor position callback of the specified window, + * which is called when the cursor is moved. The callback is provided with the + * position, in screen coordinates, relative to the upper-left corner of the + * client area of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * + * @since Added in version 3.0. Replaces `glfwSetMousePosCallback`. + * + * @ingroup input + */ +GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun cbfun); + +/*! @brief Sets the cursor enter/exit callback. + * + * This function sets the cursor boundary crossing callback of the specified + * window, which is called when the cursor enters or leaves the client area of + * the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_enter + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun cbfun); + +/*! @brief Sets the scroll callback. + * + * This function sets the scroll callback of the specified window, which is + * called when a scrolling device is used, such as a mouse wheel or scrolling + * area of a touchpad. + * + * The scroll callback receives all scrolling input, like that from a mouse + * wheel or a touchpad scrolling area. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new scroll callback, or `NULL` to remove the currently + * set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref scrolling + * + * @since Added in version 3.0. Replaces `glfwSetMouseWheelCallback`. + * + * @ingroup input + */ +GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun); + +/*! @brief Sets the file drop callback. + * + * This function sets the file drop callback of the specified window, which is + * called when one or more dragged files are dropped on the window. + * + * Because the path array and its strings may have been generated specifically + * for that event, they are not guaranteed to be valid after the callback has + * returned. If you wish to use them after the callback returns, you need to + * make a deep copy. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new file drop callback, or `NULL` to remove the + * currently set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @wayland File drop is currently unimplemented. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref path_drop + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); + +/*! @brief Returns whether the specified joystick is present. + * + * This function returns whether the specified joystick is present. + * + * There is no need to call this function before other functions that accept + * a joystick ID, as they all check for presence before performing any other + * work. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick + * + * @since Added in version 3.0. Replaces `glfwGetJoystickParam`. + * + * @ingroup input + */ +GLFWAPI int glfwJoystickPresent(int jid); + +/*! @brief Returns the values of all axes of the specified joystick. + * + * This function returns the values of all axes of the specified joystick. + * Each element in the array is a value between -1.0 and 1.0. + * + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of axis values in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * @return An array of axis values, or `NULL` if the joystick is not present or + * an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_axis + * + * @since Added in version 3.0. Replaces `glfwGetJoystickPos`. + * + * @ingroup input + */ +GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count); + +/*! @brief Returns the state of all buttons of the specified joystick. + * + * This function returns the state of all buttons of the specified joystick. + * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. + * + * For backward compatibility with earlier versions that did not have @ref + * glfwGetJoystickHats, the button array also includes all hats, each + * represented as four buttons. The hats are in the same order as returned by + * __glfwGetJoystickHats__ and are in the order _up_, _right_, _down_ and + * _left_. To disable these extra buttons, set the @ref + * GLFW_JOYSTICK_HAT_BUTTONS init hint before initialization. + * + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of button states in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * @return An array of button states, or `NULL` if the joystick is not present + * or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_button + * + * @since Added in version 2.2. + * @glfw3 Changed to return a dynamic array. + * + * @ingroup input + */ +GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count); + +/*! @brief Returns the state of all hats of the specified joystick. + * + * This function returns the state of all hats of the specified joystick. + * Each element in the array is one of the following values: + * + * Name | Value + * --------------------- | -------------------------------- + * `GLFW_HAT_CENTERED` | 0 + * `GLFW_HAT_UP` | 1 + * `GLFW_HAT_RIGHT` | 2 + * `GLFW_HAT_DOWN` | 4 + * `GLFW_HAT_LEFT` | 8 + * `GLFW_HAT_RIGHT_UP` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_UP` + * `GLFW_HAT_RIGHT_DOWN` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_DOWN` + * `GLFW_HAT_LEFT_UP` | `GLFW_HAT_LEFT` \| `GLFW_HAT_UP` + * `GLFW_HAT_LEFT_DOWN` | `GLFW_HAT_LEFT` \| `GLFW_HAT_DOWN` + * + * The diagonal directions are bitwise combinations of the primary (up, right, + * down and left) directions and you can test for these individually by ANDing + * it with the corresponding direction. + * + * @code + * if (hats[2] & GLFW_HAT_RIGHT) + * { + * // State of hat 2 could be right-up, right or right-down + * } + * @endcode + * + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of hat states in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * @return An array of hat states, or `NULL` if the joystick is not present + * or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_hat + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count); + +/*! @brief Returns the name of the specified joystick. + * + * This function returns the name, encoded as UTF-8, of the specified joystick. + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. + * + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick + * is not present or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_name + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetJoystickName(int jid); + +/*! @brief Returns the SDL comaptible GUID of the specified joystick. + * + * This function returns the SDL compatible GUID, as a UTF-8 encoded + * hexadecimal string, of the specified joystick. The returned string is + * allocated and freed by GLFW. You should not free it yourself. + * + * The GUID is what connects a joystick to a gamepad mapping. A connected + * joystick will always have a GUID even if there is no gamepad mapping + * assigned to it. + * + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * The GUID uses the format introduced in SDL 2.0.5. This GUID tries to + * uniquely identify the make and model of a joystick but does not identify + * a specific unit, e.g. all wired Xbox 360 controllers will have the same + * GUID on that platform. The GUID for a unit may vary between platforms + * depending on what hardware information the platform specific APIs provide. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return The UTF-8 encoded GUID of the joystick, or `NULL` if the joystick + * is not present or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetJoystickGUID(int jid); + +/*! @brief Returns whether the specified joystick has a gamepad mapping. + * + * This function returns whether the specified joystick is both present and has + * a gamepad mapping. + * + * If the specified joystick is present but does not have a gamepad mapping + * this function will return `GLFW_FALSE` but will not generate an error. Call + * @ref glfwJoystickPresent to check if a joystick is present regardless of + * whether it has a mapping. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return `GLFW_TRUE` if a joystick is both present and has a gamepad mapping, + * or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwGetGamepadState + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwJoystickIsGamepad(int jid); + +/*! @brief Sets the joystick configuration callback. + * + * This function sets the joystick configuration callback, or removes the + * currently set callback. This is called when a joystick is connected to or + * disconnected from the system. + * + * For joystick connection and disconnection events to be delivered on all + * platforms, you need to call one of the [event processing](@ref events) + * functions. Joystick disconnection may also be detected and the callback + * called by joystick functions. The function will then return whatever it + * returns if the joystick is not present. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_event + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun); + +/*! @brief Adds the specified SDL_GameControllerDB gamepad mappings. + * + * This function parses the specified ASCII encoded string and updates the + * internal list with any gamepad mappings it finds. This string may + * contain either a single gamepad mapping or many mappings separated by + * newlines. The parser supports the full format of the `gamecontrollerdb.txt` + * source file including empty lines and comments. + * + * See @ref gamepad_mapping for a description of the format. + * + * If there is already a gamepad mapping for a given GUID in the internal list, + * it will be replaced by the one passed to this function. If the library is + * terminated and re-initialized the internal list will revert to the built-in + * default. + * + * @param[in] string The string containing the gamepad mappings. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwJoystickIsGamepad + * @sa @ref glfwGetGamepadName + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwUpdateGamepadMappings(const char* string); + +/*! @brief Returns the human-readable gamepad name for the specified joystick. + * + * This function returns the human-readable name of the gamepad from the + * gamepad mapping assigned to the specified joystick. + * + * If the specified joystick is not present or does not have a gamepad mapping + * this function will return `NULL` but will not generate an error. Call + * @ref glfwJoystickPresent to check whether it is present regardless of + * whether it has a mapping. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return The UTF-8 encoded name of the gamepad, or `NULL` if the + * joystick is not present, does not have a mapping or an + * [error](@ref error_handling) occurred. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, the gamepad mappings are updated or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwJoystickIsGamepad + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetGamepadName(int jid); + +/*! @brief Retrieves the state of the specified joystick remapped as a gamepad. + * + * This function retrives the state of the specified joystick remapped to + * an Xbox-like gamepad. + * + * If the specified joystick is not present or does not have a gamepad mapping + * this function will return `GLFW_FALSE` but will not generate an error. Call + * @ref glfwJoystickPresent to check whether it is present regardless of + * whether it has a mapping. + * + * The Guide button may not be available for input as it is often hooked by the + * system or the Steam client. + * + * Not all devices have all the buttons or axes provided by @ref + * GLFWgamepadstate. Unavailable buttons and axes will always report + * `GLFW_RELEASE` and 1.0 respectively. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @param[out] state The gamepad input state of the joystick. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if no joystick is + * connected, it has no gamepad mapping or an [error](@ref error_handling) + * occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @sa @ref gamepad + * @sa @ref glfwUpdateGamepadMappings + * @sa @ref glfwJoystickIsGamepad + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state); + +/*! @brief Sets the clipboard to the specified string. + * + * This function sets the system clipboard to the specified, UTF-8 encoded + * string. + * + * @param[in] window The window that will own the clipboard contents. + * @param[in] string A UTF-8 encoded string. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland Clipboard is currently unimplemented. + * + * @pointer_lifetime The specified string is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa @ref glfwGetClipboardString + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); + +/*! @brief Returns the contents of the clipboard as a string. + * + * This function returns the contents of the system clipboard, if it contains + * or is convertible to a UTF-8 encoded string. If the clipboard is empty or + * if its contents cannot be converted, `NULL` is returned and a @ref + * GLFW_FORMAT_UNAVAILABLE error is generated. + * + * @param[in] window The window that will request the clipboard contents. + * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` + * if an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland Clipboard is currently unimplemented. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa @ref glfwSetClipboardString + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); + +/*! @brief Returns the value of the GLFW timer. + * + * This function returns the value of the GLFW timer. Unless the timer has + * been set using @ref glfwSetTime, the timer measures time elapsed since GLFW + * was initialized. + * + * The resolution of the timer is system dependent, but is usually on the order + * of a few micro- or nanoseconds. It uses the highest-resolution monotonic + * time source on each supported platform. + * + * @return The current value, in seconds, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Reading and + * writing of the internal timer offset is not atomic, so it needs to be + * externally synchronized with calls to @ref glfwSetTime. + * + * @sa @ref time + * + * @since Added in version 1.0. + * + * @ingroup input + */ +GLFWAPI double glfwGetTime(void); + +/*! @brief Sets the GLFW timer. + * + * This function sets the value of the GLFW timer. It then continues to count + * up from that value. The value must be a positive finite number less than + * or equal to 18446744073.0, which is approximately 584.5 years. + * + * @param[in] time The new value, in seconds. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @remark The upper limit of the timer is calculated as + * floor((264 - 1) / 109) and is due to implementations + * storing nanoseconds in 64 bits. The limit may be increased in the future. + * + * @thread_safety This function may be called from any thread. Reading and + * writing of the internal timer offset is not atomic, so it needs to be + * externally synchronized with calls to @ref glfwGetTime. + * + * @sa @ref time + * + * @since Added in version 2.2. + * + * @ingroup input + */ +GLFWAPI void glfwSetTime(double time); + +/*! @brief Returns the current value of the raw timer. + * + * This function returns the current value of the raw timer, measured in + * 1 / frequency seconds. To get the frequency, call @ref + * glfwGetTimerFrequency. + * + * @return The value of the timer, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa @ref glfwGetTimerFrequency + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerValue(void); + +/*! @brief Returns the frequency, in Hz, of the raw timer. + * + * This function returns the frequency, in Hz, of the raw timer. + * + * @return The frequency of the timer, in Hz, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa @ref glfwGetTimerValue + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerFrequency(void); + +/*! @brief Makes the context of the specified window current for the calling + * thread. + * + * This function makes the OpenGL or OpenGL ES context of the specified window + * current on the calling thread. A context can only be made current on + * a single thread at a time and each thread can have only a single current + * context at a time. + * + * By default, making a context non-current implicitly forces a pipeline flush. + * On machines that support `GL_KHR_context_flush_control`, you can control + * whether a context performs this flush by setting the + * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint) + * hint. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * + * @param[in] window The window whose context to make current, or `NULL` to + * detach the current context. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_current + * @sa @ref glfwGetCurrentContext + * + * @since Added in version 3.0. + * + * @ingroup context + */ +GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); + +/*! @brief Returns the window whose context is current on the calling thread. + * + * This function returns the window whose OpenGL or OpenGL ES context is + * current on the calling thread. + * + * @return The window whose context is current, or `NULL` if no window's + * context is current. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_current + * @sa @ref glfwMakeContextCurrent + * + * @since Added in version 3.0. + * + * @ingroup context + */ +GLFWAPI GLFWwindow* glfwGetCurrentContext(void); + +/*! @brief Swaps the front and back buffers of the specified window. + * + * This function swaps the front and back buffers of the specified window when + * rendering with OpenGL or OpenGL ES. If the swap interval is greater than + * zero, the GPU driver waits the specified number of screen updates before + * swapping the buffers. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see `vkQueuePresentKHR` instead. + * + * @param[in] window The window whose buffers to swap. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark __EGL:__ The context of the specified window must be current on the + * calling thread. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref buffer_swap + * @sa @ref glfwSwapInterval + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSwapBuffers(GLFWwindow* window); + +/*! @brief Sets the swap interval for the current context. + * + * This function sets the swap interval for the current OpenGL or OpenGL ES + * context, i.e. the number of screen updates to wait from the time @ref + * glfwSwapBuffers was called before swapping the buffers and returning. This + * is sometimes called _vertical synchronization_, _vertical retrace + * synchronization_ or just _vsync_. + * + * Contexts that support either of the `WGL_EXT_swap_control_tear` and + * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, + * which allow the driver to swap even if a frame arrives a little bit late. + * You can check for the presence of these extensions using @ref + * glfwExtensionSupported. For more information about swap tearing, see the + * extension specifications. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see the present mode of your swapchain instead. + * + * @param[in] interval The minimum number of screen updates to wait for + * until the buffers are swapped by @ref glfwSwapBuffers. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark This function is not called during context creation, leaving the + * swap interval set to whatever is the default on that platform. This is done + * because some swap interval extensions used by GLFW do not allow the swap + * interval to be reset to zero once it has been set to a non-zero value. + * + * @remark Some GPU drivers do not honor the requested swap interval, either + * because of a user setting that overrides the application's request or due to + * bugs in the driver. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref buffer_swap + * @sa @ref glfwSwapBuffers + * + * @since Added in version 1.0. + * + * @ingroup context + */ +GLFWAPI void glfwSwapInterval(int interval); + +/*! @brief Returns whether the specified extension is available. + * + * This function returns whether the specified + * [API extension](@ref context_glext) is supported by the current OpenGL or + * OpenGL ES context. It searches both for client API extension and context + * creation API extensions. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * As this functions retrieves and searches one or more extension strings each + * call, it is recommended that you cache its results if it is going to be used + * frequently. The extension strings will not change during the lifetime of + * a context, so there is no danger in doing this. + * + * This function does not apply to Vulkan. If you are using Vulkan, see @ref + * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties` + * and `vkEnumerateDeviceExtensionProperties` instead. + * + * @param[in] extension The ASCII encoded name of the extension. + * @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE` + * otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_glext + * @sa @ref glfwGetProcAddress + * + * @since Added in version 1.0. + * + * @ingroup context + */ +GLFWAPI int glfwExtensionSupported(const char* extension); + +/*! @brief Returns the address of the specified function for the current + * context. + * + * This function returns the address of the specified OpenGL or OpenGL ES + * [core or extension function](@ref context_glext), if it is supported + * by the current context. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and + * `vkGetDeviceProcAddr` instead. + * + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark The address of a given function is not guaranteed to be the same + * between contexts. + * + * @remark This function may return a non-`NULL` address despite the + * associated version or extension not being available. Always check the + * context version or extension string first. + * + * @pointer_lifetime The returned function pointer is valid until the context + * is destroyed or the library is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_glext + * @sa @ref glfwExtensionSupported + * + * @since Added in version 1.0. + * + * @ingroup context + */ +GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); + +/*! @brief Returns whether the Vulkan loader and an ICD have been found. + * + * This function returns whether the Vulkan loader and any minimally functional + * ICD have been found. + * + * The availability of a Vulkan loader and even an ICD does not by itself + * guarantee that surface creation or even instance creation is possible. + * For example, on Fermi systems Nvidia will install an ICD that provides no + * actual Vulkan support. Call @ref glfwGetRequiredInstanceExtensions to check + * whether the extensions necessary for Vulkan surface creation are available + * and @ref glfwGetPhysicalDevicePresentationSupport to check whether a queue + * family of a physical device supports image presentation. + * + * @return `GLFW_TRUE` if Vulkan is minimally available, or `GLFW_FALSE` + * otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_support + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwVulkanSupported(void); + +/*! @brief Returns the Vulkan instance extensions required by GLFW. + * + * This function returns an array of names of Vulkan instance extensions required + * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the + * list will always contains `VK_KHR_surface`, so if you don't require any + * additional extensions you can pass this list directly to the + * `VkInstanceCreateInfo` struct. + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is at least minimally available. + * + * If Vulkan is available but no set of extensions allowing window surface + * creation was found, this function returns `NULL`. You may still use Vulkan + * for off-screen rendering and compute work. + * + * @param[out] count Where to store the number of extensions in the returned + * array. This is set to zero if an error occurred. + * @return An array of ASCII encoded extension names, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @remark Additional extensions may be required by future versions of GLFW. + * You should check if any extensions you wish to enable are already in the + * returned array, as it is an error to specify an extension more than once in + * the `VkInstanceCreateInfo` struct. + * + * @remark @macos This function currently only supports the + * `VK_MVK_macos_surface` extension from MoltenVK. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * library is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_ext + * @sa @ref glfwCreateWindowSurface + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count); + +#if defined(VK_VERSION_1_0) + +/*! @brief Returns the address of the specified Vulkan instance function. + * + * This function returns the address of the specified Vulkan core or extension + * function for the specified instance. If instance is set to `NULL` it can + * return any function exported from the Vulkan loader, including at least the + * following functions: + * + * - `vkEnumerateInstanceExtensionProperties` + * - `vkEnumerateInstanceLayerProperties` + * - `vkCreateInstance` + * - `vkGetInstanceProcAddr` + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is at least minimally available. + * + * This function is equivalent to calling `vkGetInstanceProcAddr` with + * a platform-specific query of the Vulkan loader as a fallback. + * + * @param[in] instance The Vulkan instance to query, or `NULL` to retrieve + * functions related to instance creation. + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @pointer_lifetime The returned function pointer is valid until the library + * is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_proc + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname); + +/*! @brief Returns whether the specified queue family can present images. + * + * This function returns whether the specified queue family of the specified + * physical device supports presentation to the platform GLFW was built for. + * + * If Vulkan or the required window surface creation instance extensions are + * not available on the machine, or if the specified instance was not created + * with the required extensions, this function returns `GLFW_FALSE` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is at least minimally available and @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * @param[in] instance The instance that the physical device belongs to. + * @param[in] device The physical device that the queue family belongs to. + * @param[in] queuefamily The index of the queue family to query. + * @return `GLFW_TRUE` if the queue family supports presentation, or + * `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @remark @macos This function currently always returns `GLFW_TRUE`, as the + * `VK_MVK_macos_surface` extension does not provide + * a `vkGetPhysicalDevice*PresentationSupport` type function. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_present + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); + +/*! @brief Creates a Vulkan surface for the specified window. + * + * This function creates a Vulkan surface for the specified window. + * + * If the Vulkan loader or at least one minimally functional ICD were not found, + * this function returns `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref + * GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported to check whether + * Vulkan is at least minimally available. + * + * If the required window surface creation instance extensions are not + * available or if the specified instance was not created with these extensions + * enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * The window surface must be destroyed before the specified Vulkan instance. + * It is the responsibility of the caller to destroy the window surface. GLFW + * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the + * surface. + * + * @param[in] instance The Vulkan instance to create the surface in. + * @param[in] window The window to create the surface for. + * @param[in] allocator The allocator to use, or `NULL` to use the default + * allocator. + * @param[out] surface Where to store the handle of the surface. This is set + * to `VK_NULL_HANDLE` if an error occurred. + * @return `VK_SUCCESS` if successful, or a Vulkan error code if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If an error occurs before the creation call is made, GLFW returns + * the Vulkan error code most appropriate for the error. Appropriate use of + * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should + * eliminate almost all occurrences of these errors. + * + * @remark @macos This function currently only supports the + * `VK_MVK_macos_surface` extension from MoltenVK. + * + * @remark @macos This function creates and sets a `CAMetalLayer` instance for + * the window content view, which is required for MoltenVK to function. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_surface + * @sa @ref glfwGetRequiredInstanceExtensions + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); + +#endif /*VK_VERSION_1_0*/ + + +/************************************************************************* + * Global definition cleanup + *************************************************************************/ + +/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ + +#ifdef GLFW_WINGDIAPI_DEFINED + #undef WINGDIAPI + #undef GLFW_WINGDIAPI_DEFINED +#endif + +#ifdef GLFW_CALLBACK_DEFINED + #undef CALLBACK + #undef GLFW_CALLBACK_DEFINED +#endif + +/* Some OpenGL related headers need GLAPIENTRY, but it is unconditionally + * defined by some gl.h variants (OpenBSD) so define it after if needed. + */ +#ifndef GLAPIENTRY + #define GLAPIENTRY APIENTRY +#endif + +/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _glfw3_h_ */ + diff --git a/src/external/glfw/include/GLFW/glfw3native.h b/src/external/glfw/include/GLFW/glfw3native.h new file mode 100644 index 00000000..4372cb76 --- /dev/null +++ b/src/external/glfw/include/GLFW/glfw3native.h @@ -0,0 +1,572 @@ +/************************************************************************* + * GLFW 3.3 - www.glfw.org + * A library for OpenGL, window and input + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2016 Camilla Löwy + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + *************************************************************************/ + +#ifndef _glfw3_native_h_ +#define _glfw3_native_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* + * Doxygen documentation + *************************************************************************/ + +/*! @file glfw3native.h + * @brief The header of the native access functions. + * + * This is the header file of the native access functions. See @ref native for + * more information. + */ +/*! @defgroup native Native access + * @brief Functions related to accessing native handles. + * + * **By using the native access functions you assert that you know what you're + * doing and how to fix problems caused by using them. If you don't, you + * shouldn't be using them.** + * + * Before the inclusion of @ref glfw3native.h, you may define zero or more + * window system API macro and zero or more context creation API macros. + * + * The chosen backends must match those the library was compiled for. Failure + * to do this will cause a link-time error. + * + * The available window API macros are: + * * `GLFW_EXPOSE_NATIVE_WIN32` + * * `GLFW_EXPOSE_NATIVE_COCOA` + * * `GLFW_EXPOSE_NATIVE_X11` + * * `GLFW_EXPOSE_NATIVE_WAYLAND` + * * `GLFW_EXPOSE_NATIVE_MIR` + * + * The available context API macros are: + * * `GLFW_EXPOSE_NATIVE_WGL` + * * `GLFW_EXPOSE_NATIVE_NSGL` + * * `GLFW_EXPOSE_NATIVE_GLX` + * * `GLFW_EXPOSE_NATIVE_EGL` + * * `GLFW_EXPOSE_NATIVE_OSMESA` + * + * These macros select which of the native access functions that are declared + * and which platform-specific headers to include. It is then up your (by + * definition platform-specific) code to handle which of these should be + * defined. + */ + + +/************************************************************************* + * System headers and types + *************************************************************************/ + +#if defined(GLFW_EXPOSE_NATIVE_WIN32) + // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for + // example to allow applications to correctly declare a GL_ARB_debug_output + // callback) but windows.h assumes no one will define APIENTRY before it does + #if defined(GLFW_APIENTRY_DEFINED) + #undef APIENTRY + #undef GLFW_APIENTRY_DEFINED + #endif + #include +#elif defined(GLFW_EXPOSE_NATIVE_COCOA) + #include + #if defined(__OBJC__) + #import + #else + typedef void* id; + #endif +#elif defined(GLFW_EXPOSE_NATIVE_X11) + #include + #include +#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) + #include +#elif defined(GLFW_EXPOSE_NATIVE_MIR) + #include +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WGL) + /* WGL is declared by windows.h */ +#endif +#if defined(GLFW_EXPOSE_NATIVE_NSGL) + /* NSGL is declared by Cocoa.h */ +#endif +#if defined(GLFW_EXPOSE_NATIVE_GLX) + #include +#endif +#if defined(GLFW_EXPOSE_NATIVE_EGL) + #include +#endif +#if defined(GLFW_EXPOSE_NATIVE_OSMESA) + #include +#endif + + +/************************************************************************* + * Functions + *************************************************************************/ + +#if defined(GLFW_EXPOSE_NATIVE_WIN32) +/*! @brief Returns the adapter device name of the specified monitor. + * + * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) + * of the specified monitor, or `NULL` if an [error](@ref error_handling) + * occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.1. + * + * @ingroup native + */ +GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); + +/*! @brief Returns the display device name of the specified monitor. + * + * @return The UTF-8 encoded display device name (for example + * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.1. + * + * @ingroup native + */ +GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); + +/*! @brief Returns the `HWND` of the specified window. + * + * @return The `HWND` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WGL) +/*! @brief Returns the `HGLRC` of the specified window. + * + * @return The `HGLRC` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_COCOA) +/*! @brief Returns the `CGDirectDisplayID` of the specified monitor. + * + * @return The `CGDirectDisplayID` of the specified monitor, or + * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.1. + * + * @ingroup native + */ +GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); + +/*! @brief Returns the `NSWindow` of the specified window. + * + * @return The `NSWindow` of the specified window, or `nil` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_NSGL) +/*! @brief Returns the `NSOpenGLContext` of the specified window. + * + * @return The `NSOpenGLContext` of the specified window, or `nil` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_X11) +/*! @brief Returns the `Display` used by GLFW. + * + * @return The `Display` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI Display* glfwGetX11Display(void); + +/*! @brief Returns the `RRCrtc` of the specified monitor. + * + * @return The `RRCrtc` of the specified monitor, or `None` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.1. + * + * @ingroup native + */ +GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); + +/*! @brief Returns the `RROutput` of the specified monitor. + * + * @return The `RROutput` of the specified monitor, or `None` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.1. + * + * @ingroup native + */ +GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); + +/*! @brief Returns the `Window` of the specified window. + * + * @return The `Window` of the specified window, or `None` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI Window glfwGetX11Window(GLFWwindow* window); + +/*! @brief Sets the current primary selection to the specified string. + * + * @param[in] string A UTF-8 encoded string. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified string is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa glfwGetX11SelectionString + * @sa glfwSetClipboardString + * + * @since Added in version 3.3. + * + * @ingroup native + */ +GLFWAPI void glfwSetX11SelectionString(const char* string); + +/*! @brief Returns the contents of the current primary selection as a string. + * + * If the selection is empty or if its contents cannot be converted, `NULL` + * is returned and a @ref GLFW_FORMAT_UNAVAILABLE error is generated. + * + * @return The contents of the selection as a UTF-8 encoded string, or `NULL` + * if an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetX11SelectionString or @ref glfwSetX11SelectionString, or until the + * library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa glfwSetX11SelectionString + * @sa glfwGetClipboardString + * + * @since Added in version 3.3. + * + * @ingroup native + */ +GLFWAPI const char* glfwGetX11SelectionString(void); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_GLX) +/*! @brief Returns the `GLXContext` of the specified window. + * + * @return The `GLXContext` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); + +/*! @brief Returns the `GLXWindow` of the specified window. + * + * @return The `GLXWindow` of the specified window, or `None` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WAYLAND) +/*! @brief Returns the `struct wl_display*` used by GLFW. + * + * @return The `struct wl_display*` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_display* glfwGetWaylandDisplay(void); + +/*! @brief Returns the `struct wl_output*` of the specified monitor. + * + * @return The `struct wl_output*` of the specified monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); + +/*! @brief Returns the main `struct wl_surface*` of the specified window. + * + * @return The main `struct wl_surface*` of the specified window, or `NULL` if + * an [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_MIR) +/*! @brief Returns the `MirConnection*` used by GLFW. + * + * @return The `MirConnection*` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI MirConnection* glfwGetMirDisplay(void); + +/*! @brief Returns the Mir output ID of the specified monitor. + * + * @return The Mir output ID of the specified monitor, or zero if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); + +/*! @brief Returns the `MirWindow*` of the specified window. + * + * @return The `MirWindow*` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI MirWindow* glfwGetMirWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_EGL) +/*! @brief Returns the `EGLDisplay` used by GLFW. + * + * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI EGLDisplay glfwGetEGLDisplay(void); + +/*! @brief Returns the `EGLContext` of the specified window. + * + * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); + +/*! @brief Returns the `EGLSurface` of the specified window. + * + * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_OSMESA) +/*! @brief Retrieves the color buffer associated with the specified window. + * + * @param[in] window The window whose color buffer to retrieve. + * @param[out] width Where to store the width of the color buffer, or `NULL`. + * @param[out] height Where to store the height of the color buffer, or `NULL`. + * @param[out] format Where to store the OSMesa pixel format of the color + * buffer, or `NULL`. + * @param[out] buffer Where to store the address of the color buffer, or + * `NULL`. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.3. + * + * @ingroup native + */ +GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* window, int* width, int* height, int* format, void** buffer); + +/*! @brief Retrieves the depth buffer associated with the specified window. + * + * @param[in] window The window whose depth buffer to retrieve. + * @param[out] width Where to store the width of the depth buffer, or `NULL`. + * @param[out] height Where to store the height of the depth buffer, or `NULL`. + * @param[out] bytesPerValue Where to store the number of bytes per depth + * buffer element, or `NULL`. + * @param[out] buffer Where to store the address of the depth buffer, or + * `NULL`. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.3. + * + * @ingroup native + */ +GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* window, int* width, int* height, int* bytesPerValue, void** buffer); + +/*! @brief Returns the `OSMesaContext` of the specified window. + * + * @return The `OSMesaContext` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.3. + * + * @ingroup native + */ +GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* window); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _glfw3_native_h_ */ + diff --git a/src/external/glfw/src/CMakeLists.txt b/src/external/glfw/src/CMakeLists.txt new file mode 100644 index 00000000..b14512cc --- /dev/null +++ b/src/external/glfw/src/CMakeLists.txt @@ -0,0 +1,152 @@ + +set(common_HEADERS internal.h mappings.h + "${GLFW_BINARY_DIR}/src/glfw_config.h" + "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" + "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h") +set(common_SOURCES context.c init.c input.c monitor.c vulkan.c window.c) + +if (_GLFW_COCOA) + set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h + posix_thread.h nsgl_context.h egl_context.h osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m + cocoa_monitor.m cocoa_window.m cocoa_time.c posix_thread.c + nsgl_context.m egl_context.c osmesa_context.c) +elseif (_GLFW_WIN32) + set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h + wgl_context.h egl_context.h osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_joystick.c + win32_monitor.c win32_time.c win32_thread.c win32_window.c + wgl_context.c egl_context.c osmesa_context.c) +elseif (_GLFW_X11) + set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h posix_time.h + posix_thread.h glx_context.h egl_context.h osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c + xkb_unicode.c posix_time.c posix_thread.c glx_context.c + egl_context.c osmesa_context.c) + + if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + set(glfw_HEADERS ${glfw_HEADERS} linux_joystick.h) + set(glfw_SOURCES ${glfw_SOURCES} linux_joystick.c) + else() + set(glfw_HEADERS ${glfw_HEADERS} null_joystick.h) + set(glfw_SOURCES ${glfw_SOURCES} null_joystick.c) + endif() +elseif (_GLFW_WAYLAND) + set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h + posix_time.h posix_thread.h xkb_unicode.h egl_context.h + osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c + linux_joystick.c posix_time.c posix_thread.c xkb_unicode.c + egl_context.c osmesa_context.c) + + ecm_add_wayland_client_protocol(glfw_SOURCES + PROTOCOL + "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" + BASENAME relative-pointer-unstable-v1) + ecm_add_wayland_client_protocol(glfw_SOURCES + PROTOCOL + "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" + BASENAME pointer-constraints-unstable-v1) +elseif (_GLFW_MIR) + set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h + posix_time.h posix_thread.h xkb_unicode.h egl_context.h + osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c + linux_joystick.c posix_time.c posix_thread.c xkb_unicode.c + egl_context.c osmesa_context.c) +elseif (_GLFW_OSMESA) + set(glfw_HEADERS ${common_HEADERS} null_platform.h null_joystick.h + posix_time.h posix_thread.h osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} null_init.c null_monitor.c null_window.c + null_joystick.c posix_time.c posix_thread.c osmesa_context.c) +endif() + +if (APPLE) + # For some reason, CMake doesn't know about .m + set_source_files_properties(${glfw_SOURCES} PROPERTIES LANGUAGE C) +endif() + +# Make GCC and Clang warn about declarations that VS 2010 and 2012 won't accept +# for all source files that VS will build +if (${CMAKE_C_COMPILER_ID} STREQUAL GNU OR ${CMAKE_C_COMPILER_ID} STREQUAL Clang) + if (WIN32) + set(windows_SOURCES ${glfw_SOURCES}) + else() + set(windows_SOURCES ${common_SOURCES}) + endif() + set_source_files_properties(${windows_SOURCES} PROPERTIES + COMPILE_FLAGS -Wdeclaration-after-statement) +endif() + +add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS}) +set_target_properties(glfw PROPERTIES + OUTPUT_NAME ${GLFW_LIB_NAME} + VERSION ${GLFW_VERSION} + SOVERSION ${GLFW_VERSION_MAJOR} + POSITION_INDEPENDENT_CODE ON + FOLDER "GLFW3") + +target_compile_definitions(glfw PRIVATE + _GLFW_USE_CONFIG_H + $<$:_XOPEN_SOURCE=600>) +target_include_directories(glfw PUBLIC + "$" + "$/include>") +target_include_directories(glfw PRIVATE + "${GLFW_SOURCE_DIR}/src" + "${GLFW_BINARY_DIR}/src" + ${glfw_INCLUDE_DIRS}) + +# HACK: When building on MinGW, WINVER and UNICODE need to be defined before +# the inclusion of stddef.h (by glfw3.h), which is itself included before +# win32_platform.h. We define them here until a saner solution can be found +# NOTE: MinGW-w64 and Visual C++ do /not/ need this hack. +target_compile_definitions(glfw PRIVATE + "$<$:UNICODE;WINVER=0x0501>") + +# Enable a reasonable set of warnings (no, -Wextra is not reasonable) +target_compile_options(glfw PRIVATE + "$<$:-Wall>" + "$<$:-Wall>") + +if (BUILD_SHARED_LIBS) + if (WIN32) + if (MINGW) + # Remove the lib prefix on the DLL (but not the import library + set_target_properties(glfw PROPERTIES PREFIX "") + + # Add a suffix to the import library to avoid naming conflicts + set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.a") + else() + # Add a suffix to the import library to avoid naming conflicts + set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.lib") + endif() + elseif (APPLE) + # Add -fno-common to work around a bug in Apple's GCC + target_compile_options(glfw PRIVATE "-fno-common") + + set_target_properties(glfw PROPERTIES + INSTALL_NAME_DIR "lib${LIB_SUFFIX}") + elseif (UNIX) + # Hide symbols not explicitly tagged for export from the shared library + target_compile_options(glfw PRIVATE "-fvisibility=hidden") + endif() + + target_compile_definitions(glfw INTERFACE GLFW_DLL) + target_link_libraries(glfw PRIVATE ${glfw_LIBRARIES}) +else() + target_link_libraries(glfw INTERFACE ${glfw_LIBRARIES}) +endif() + +if (MSVC) + target_compile_definitions(glfw PRIVATE _CRT_SECURE_NO_WARNINGS) +endif() + +if (GLFW_INSTALL) + install(TARGETS glfw + EXPORT glfwTargets + RUNTIME DESTINATION "bin" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + LIBRARY DESTINATION "lib${LIB_SUFFIX}") +endif() + diff --git a/src/external/glfw/src/cocoa_init.m b/src/external/glfw/src/cocoa_init.m new file mode 100644 index 00000000..01a746ba --- /dev/null +++ b/src/external/glfw/src/cocoa_init.m @@ -0,0 +1,374 @@ +//======================================================================== +// GLFW 3.3 macOS - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" +#include // For MAXPATHLEN + + +// Change to our application bundle's resources directory, if present +// +static void changeToResourcesDirectory(void) +{ + char resourcesPath[MAXPATHLEN]; + + CFBundleRef bundle = CFBundleGetMainBundle(); + if (!bundle) + return; + + CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle); + + CFStringRef last = CFURLCopyLastPathComponent(resourcesURL); + if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo) + { + CFRelease(last); + CFRelease(resourcesURL); + return; + } + + CFRelease(last); + + if (!CFURLGetFileSystemRepresentation(resourcesURL, + true, + (UInt8*) resourcesPath, + MAXPATHLEN)) + { + CFRelease(resourcesURL); + return; + } + + CFRelease(resourcesURL); + + chdir(resourcesPath); +} + +// Create key code translation tables +// +static void createKeyTables(void) +{ + int scancode; + + memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes)); + memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes)); + + _glfw.ns.keycodes[0x1D] = GLFW_KEY_0; + _glfw.ns.keycodes[0x12] = GLFW_KEY_1; + _glfw.ns.keycodes[0x13] = GLFW_KEY_2; + _glfw.ns.keycodes[0x14] = GLFW_KEY_3; + _glfw.ns.keycodes[0x15] = GLFW_KEY_4; + _glfw.ns.keycodes[0x17] = GLFW_KEY_5; + _glfw.ns.keycodes[0x16] = GLFW_KEY_6; + _glfw.ns.keycodes[0x1A] = GLFW_KEY_7; + _glfw.ns.keycodes[0x1C] = GLFW_KEY_8; + _glfw.ns.keycodes[0x19] = GLFW_KEY_9; + _glfw.ns.keycodes[0x00] = GLFW_KEY_A; + _glfw.ns.keycodes[0x0B] = GLFW_KEY_B; + _glfw.ns.keycodes[0x08] = GLFW_KEY_C; + _glfw.ns.keycodes[0x02] = GLFW_KEY_D; + _glfw.ns.keycodes[0x0E] = GLFW_KEY_E; + _glfw.ns.keycodes[0x03] = GLFW_KEY_F; + _glfw.ns.keycodes[0x05] = GLFW_KEY_G; + _glfw.ns.keycodes[0x04] = GLFW_KEY_H; + _glfw.ns.keycodes[0x22] = GLFW_KEY_I; + _glfw.ns.keycodes[0x26] = GLFW_KEY_J; + _glfw.ns.keycodes[0x28] = GLFW_KEY_K; + _glfw.ns.keycodes[0x25] = GLFW_KEY_L; + _glfw.ns.keycodes[0x2E] = GLFW_KEY_M; + _glfw.ns.keycodes[0x2D] = GLFW_KEY_N; + _glfw.ns.keycodes[0x1F] = GLFW_KEY_O; + _glfw.ns.keycodes[0x23] = GLFW_KEY_P; + _glfw.ns.keycodes[0x0C] = GLFW_KEY_Q; + _glfw.ns.keycodes[0x0F] = GLFW_KEY_R; + _glfw.ns.keycodes[0x01] = GLFW_KEY_S; + _glfw.ns.keycodes[0x11] = GLFW_KEY_T; + _glfw.ns.keycodes[0x20] = GLFW_KEY_U; + _glfw.ns.keycodes[0x09] = GLFW_KEY_V; + _glfw.ns.keycodes[0x0D] = GLFW_KEY_W; + _glfw.ns.keycodes[0x07] = GLFW_KEY_X; + _glfw.ns.keycodes[0x10] = GLFW_KEY_Y; + _glfw.ns.keycodes[0x06] = GLFW_KEY_Z; + + _glfw.ns.keycodes[0x27] = GLFW_KEY_APOSTROPHE; + _glfw.ns.keycodes[0x2A] = GLFW_KEY_BACKSLASH; + _glfw.ns.keycodes[0x2B] = GLFW_KEY_COMMA; + _glfw.ns.keycodes[0x18] = GLFW_KEY_EQUAL; + _glfw.ns.keycodes[0x32] = GLFW_KEY_GRAVE_ACCENT; + _glfw.ns.keycodes[0x21] = GLFW_KEY_LEFT_BRACKET; + _glfw.ns.keycodes[0x1B] = GLFW_KEY_MINUS; + _glfw.ns.keycodes[0x2F] = GLFW_KEY_PERIOD; + _glfw.ns.keycodes[0x1E] = GLFW_KEY_RIGHT_BRACKET; + _glfw.ns.keycodes[0x29] = GLFW_KEY_SEMICOLON; + _glfw.ns.keycodes[0x2C] = GLFW_KEY_SLASH; + _glfw.ns.keycodes[0x0A] = GLFW_KEY_WORLD_1; + + _glfw.ns.keycodes[0x33] = GLFW_KEY_BACKSPACE; + _glfw.ns.keycodes[0x39] = GLFW_KEY_CAPS_LOCK; + _glfw.ns.keycodes[0x75] = GLFW_KEY_DELETE; + _glfw.ns.keycodes[0x7D] = GLFW_KEY_DOWN; + _glfw.ns.keycodes[0x77] = GLFW_KEY_END; + _glfw.ns.keycodes[0x24] = GLFW_KEY_ENTER; + _glfw.ns.keycodes[0x35] = GLFW_KEY_ESCAPE; + _glfw.ns.keycodes[0x7A] = GLFW_KEY_F1; + _glfw.ns.keycodes[0x78] = GLFW_KEY_F2; + _glfw.ns.keycodes[0x63] = GLFW_KEY_F3; + _glfw.ns.keycodes[0x76] = GLFW_KEY_F4; + _glfw.ns.keycodes[0x60] = GLFW_KEY_F5; + _glfw.ns.keycodes[0x61] = GLFW_KEY_F6; + _glfw.ns.keycodes[0x62] = GLFW_KEY_F7; + _glfw.ns.keycodes[0x64] = GLFW_KEY_F8; + _glfw.ns.keycodes[0x65] = GLFW_KEY_F9; + _glfw.ns.keycodes[0x6D] = GLFW_KEY_F10; + _glfw.ns.keycodes[0x67] = GLFW_KEY_F11; + _glfw.ns.keycodes[0x6F] = GLFW_KEY_F12; + _glfw.ns.keycodes[0x69] = GLFW_KEY_F13; + _glfw.ns.keycodes[0x6B] = GLFW_KEY_F14; + _glfw.ns.keycodes[0x71] = GLFW_KEY_F15; + _glfw.ns.keycodes[0x6A] = GLFW_KEY_F16; + _glfw.ns.keycodes[0x40] = GLFW_KEY_F17; + _glfw.ns.keycodes[0x4F] = GLFW_KEY_F18; + _glfw.ns.keycodes[0x50] = GLFW_KEY_F19; + _glfw.ns.keycodes[0x5A] = GLFW_KEY_F20; + _glfw.ns.keycodes[0x73] = GLFW_KEY_HOME; + _glfw.ns.keycodes[0x72] = GLFW_KEY_INSERT; + _glfw.ns.keycodes[0x7B] = GLFW_KEY_LEFT; + _glfw.ns.keycodes[0x3A] = GLFW_KEY_LEFT_ALT; + _glfw.ns.keycodes[0x3B] = GLFW_KEY_LEFT_CONTROL; + _glfw.ns.keycodes[0x38] = GLFW_KEY_LEFT_SHIFT; + _glfw.ns.keycodes[0x37] = GLFW_KEY_LEFT_SUPER; + _glfw.ns.keycodes[0x6E] = GLFW_KEY_MENU; + _glfw.ns.keycodes[0x47] = GLFW_KEY_NUM_LOCK; + _glfw.ns.keycodes[0x79] = GLFW_KEY_PAGE_DOWN; + _glfw.ns.keycodes[0x74] = GLFW_KEY_PAGE_UP; + _glfw.ns.keycodes[0x7C] = GLFW_KEY_RIGHT; + _glfw.ns.keycodes[0x3D] = GLFW_KEY_RIGHT_ALT; + _glfw.ns.keycodes[0x3E] = GLFW_KEY_RIGHT_CONTROL; + _glfw.ns.keycodes[0x3C] = GLFW_KEY_RIGHT_SHIFT; + _glfw.ns.keycodes[0x36] = GLFW_KEY_RIGHT_SUPER; + _glfw.ns.keycodes[0x31] = GLFW_KEY_SPACE; + _glfw.ns.keycodes[0x30] = GLFW_KEY_TAB; + _glfw.ns.keycodes[0x7E] = GLFW_KEY_UP; + + _glfw.ns.keycodes[0x52] = GLFW_KEY_KP_0; + _glfw.ns.keycodes[0x53] = GLFW_KEY_KP_1; + _glfw.ns.keycodes[0x54] = GLFW_KEY_KP_2; + _glfw.ns.keycodes[0x55] = GLFW_KEY_KP_3; + _glfw.ns.keycodes[0x56] = GLFW_KEY_KP_4; + _glfw.ns.keycodes[0x57] = GLFW_KEY_KP_5; + _glfw.ns.keycodes[0x58] = GLFW_KEY_KP_6; + _glfw.ns.keycodes[0x59] = GLFW_KEY_KP_7; + _glfw.ns.keycodes[0x5B] = GLFW_KEY_KP_8; + _glfw.ns.keycodes[0x5C] = GLFW_KEY_KP_9; + _glfw.ns.keycodes[0x45] = GLFW_KEY_KP_ADD; + _glfw.ns.keycodes[0x41] = GLFW_KEY_KP_DECIMAL; + _glfw.ns.keycodes[0x4B] = GLFW_KEY_KP_DIVIDE; + _glfw.ns.keycodes[0x4C] = GLFW_KEY_KP_ENTER; + _glfw.ns.keycodes[0x51] = GLFW_KEY_KP_EQUAL; + _glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY; + _glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT; + + for (scancode = 0; scancode < 256; scancode++) + { + // Store the reverse translation for faster key name lookup + if (_glfw.ns.keycodes[scancode] >= 0) + _glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode; + } +} + +// Retrieve Unicode data for the current keyboard layout +// +static GLFWbool updateUnicodeDataNS(void) +{ + if (_glfw.ns.inputSource) + { + CFRelease(_glfw.ns.inputSource); + _glfw.ns.inputSource = NULL; + _glfw.ns.unicodeData = nil; + } + + _glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource(); + if (!_glfw.ns.inputSource) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to retrieve keyboard layout input source"); + return GLFW_FALSE; + } + + _glfw.ns.unicodeData = + TISGetInputSourceProperty(_glfw.ns.inputSource, + kTISPropertyUnicodeKeyLayoutData); + if (!_glfw.ns.unicodeData) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to retrieve keyboard layout Unicode data"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Load HIToolbox.framework and the TIS symbols we need from it +// +static GLFWbool initializeTIS(void) +{ + // This works only because Cocoa has already loaded it properly + _glfw.ns.tis.bundle = + CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox")); + if (!_glfw.ns.tis.bundle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to load HIToolbox.framework"); + return GLFW_FALSE; + } + + CFStringRef* kPropertyUnicodeKeyLayoutData = + CFBundleGetDataPointerForName(_glfw.ns.tis.bundle, + CFSTR("kTISPropertyUnicodeKeyLayoutData")); + _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource = + CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, + CFSTR("TISCopyCurrentKeyboardLayoutInputSource")); + _glfw.ns.tis.GetInputSourceProperty = + CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, + CFSTR("TISGetInputSourceProperty")); + _glfw.ns.tis.GetKbdType = + CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, + CFSTR("LMGetKbdType")); + + if (!kPropertyUnicodeKeyLayoutData || + !TISCopyCurrentKeyboardLayoutInputSource || + !TISGetInputSourceProperty || + !LMGetKbdType) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to load TIS API symbols"); + return GLFW_FALSE; + } + + _glfw.ns.tis.kPropertyUnicodeKeyLayoutData = + *kPropertyUnicodeKeyLayoutData; + + return updateUnicodeDataNS(); +} + +@interface GLFWLayoutListener : NSObject +@end + +@implementation GLFWLayoutListener + +- (void)selectedKeyboardInputSourceChanged:(NSObject* )object +{ + updateUnicodeDataNS(); +} + +@end + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; + + if (_glfw.hints.init.ns.chdir) + changeToResourcesDirectory(); + + _glfw.ns.listener = [[GLFWLayoutListener alloc] init]; + [[NSNotificationCenter defaultCenter] + addObserver:_glfw.ns.listener + selector:@selector(selectedKeyboardInputSourceChanged:) + name:NSTextInputContextKeyboardSelectionDidChangeNotification + object:nil]; + + createKeyTables(); + + _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + if (!_glfw.ns.eventSource) + return GLFW_FALSE; + + CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0); + + if (!initializeTIS()) + return GLFW_FALSE; + + _glfwInitTimerNS(); + _glfwInitJoysticksNS(); + + _glfwPollMonitorsNS(); + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + if (_glfw.ns.inputSource) + { + CFRelease(_glfw.ns.inputSource); + _glfw.ns.inputSource = NULL; + _glfw.ns.unicodeData = nil; + } + + if (_glfw.ns.eventSource) + { + CFRelease(_glfw.ns.eventSource); + _glfw.ns.eventSource = NULL; + } + + if (_glfw.ns.delegate) + { + [NSApp setDelegate:nil]; + [_glfw.ns.delegate release]; + _glfw.ns.delegate = nil; + } + + if (_glfw.ns.listener) + { + [[NSNotificationCenter defaultCenter] + removeObserver:_glfw.ns.listener + name:NSTextInputContextKeyboardSelectionDidChangeNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + removeObserver:_glfw.ns.listener]; + [_glfw.ns.listener release]; + _glfw.ns.listener = nil; + } + + free(_glfw.ns.clipboardString); + + _glfwTerminateNSGL(); + _glfwTerminateJoysticksNS(); + + [_glfw.ns.autoreleasePool release]; + _glfw.ns.autoreleasePool = nil; +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " Cocoa NSGL" +#if defined(_GLFW_BUILD_DLL) + " dynamic" +#endif + ; +} + diff --git a/src/external/glfw/src/cocoa_joystick.h b/src/external/glfw/src/cocoa_joystick.h new file mode 100644 index 00000000..d18d032a --- /dev/null +++ b/src/external/glfw/src/cocoa_joystick.h @@ -0,0 +1,50 @@ +//======================================================================== +// GLFW 3.3 Cocoa - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include +#include +#include +#include + +#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickNS ns +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE + +#define _GLFW_PLATFORM_MAPPING_NAME "Mac OS X" + +// Cocoa-specific per-joystick data +// +typedef struct _GLFWjoystickNS +{ + IOHIDDeviceRef device; + CFMutableArrayRef axes; + CFMutableArrayRef buttons; + CFMutableArrayRef hats; +} _GLFWjoystickNS; + + +void _glfwInitJoysticksNS(void); +void _glfwTerminateJoysticksNS(void); + diff --git a/src/external/glfw/src/cocoa_joystick.m b/src/external/glfw/src/cocoa_joystick.m new file mode 100644 index 00000000..3a5751ef --- /dev/null +++ b/src/external/glfw/src/cocoa_joystick.m @@ -0,0 +1,462 @@ +//======================================================================== +// GLFW 3.3 Cocoa - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Löwy +// Copyright (c) 2012 Torsten Walluhn +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + +#include +#include + +#include +#include + + +// Joystick element information +// +typedef struct _GLFWjoyelementNS +{ + IOHIDElementRef native; + uint32_t usage; + int index; + long minimum; + long maximum; + +} _GLFWjoyelementNS; + + +// Returns the value of the specified element of the specified joystick +// +static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element) +{ + IOHIDValueRef valueRef; + long value = 0; + + if (js->ns.device) + { + if (IOHIDDeviceGetValue(js->ns.device, + element->native, + &valueRef) == kIOReturnSuccess) + { + value = IOHIDValueGetIntegerValue(valueRef); + } + } + + return value; +} + +// Comparison function for matching the SDL element order +// +static CFComparisonResult compareElements(const void* fp, + const void* sp, + void* user) +{ + const _GLFWjoyelementNS* fe = fp; + const _GLFWjoyelementNS* se = sp; + if (fe->usage < se->usage) + return kCFCompareLessThan; + if (fe->usage > se->usage) + return kCFCompareGreaterThan; + if (fe->index < se->index) + return kCFCompareLessThan; + if (fe->index > se->index) + return kCFCompareGreaterThan; + return kCFCompareEqualTo; +} + +// Removes the specified joystick +// +static void closeJoystick(_GLFWjoystick* js) +{ + int i; + + if (!js->present) + return; + + for (i = 0; i < CFArrayGetCount(js->ns.axes); i++) + free((void*) CFArrayGetValueAtIndex(js->ns.axes, i)); + CFRelease(js->ns.axes); + + for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++) + free((void*) CFArrayGetValueAtIndex(js->ns.buttons, i)); + CFRelease(js->ns.buttons); + + for (i = 0; i < CFArrayGetCount(js->ns.hats); i++) + free((void*) CFArrayGetValueAtIndex(js->ns.hats, i)); + CFRelease(js->ns.hats); + + _glfwFreeJoystick(js); + _glfwInputJoystick(js, GLFW_DISCONNECTED); +} + +// Callback for user-initiated joystick addition +// +static void matchCallback(void* context, + IOReturn result, + void* sender, + IOHIDDeviceRef device) +{ + int jid; + char name[256]; + char guid[33]; + CFIndex i; + CFTypeRef property; + uint32_t vendor = 0, product = 0, version = 0; + _GLFWjoystick* js; + CFMutableArrayRef axes, buttons, hats; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (_glfw.joysticks[jid].ns.device == device) + return; + } + + axes = CFArrayCreateMutable(NULL, 0, NULL); + buttons = CFArrayCreateMutable(NULL, 0, NULL); + hats = CFArrayCreateMutable(NULL, 0, NULL); + + property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); + if (property) + { + CFStringGetCString(property, + name, + sizeof(name), + kCFStringEncodingUTF8); + } + else + strncpy(name, "Unknown", sizeof(name)); + + property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)); + if (property) + CFNumberGetValue(property, kCFNumberSInt32Type, &vendor); + + property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)); + if (property) + CFNumberGetValue(property, kCFNumberSInt32Type, &product); + + property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVersionNumberKey)); + if (property) + CFNumberGetValue(property, kCFNumberSInt32Type, &version); + + // Generate a joystick GUID that matches the SDL 2.0.5+ one + if (vendor && product) + { + sprintf(guid, "03000000%02x%02x0000%02x%02x0000%02x%02x0000", + (uint8_t) vendor, (uint8_t) (vendor >> 8), + (uint8_t) product, (uint8_t) (product >> 8), + (uint8_t) version, (uint8_t) (version >> 8)); + } + else + { + sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00", + name[0], name[1], name[2], name[3], + name[4], name[5], name[6], name[7], + name[8], name[9], name[10]); + } + + CFArrayRef elements = + IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone); + + for (i = 0; i < CFArrayGetCount(elements); i++) + { + IOHIDElementRef native = (IOHIDElementRef) + CFArrayGetValueAtIndex(elements, i); + if (CFGetTypeID(native) != IOHIDElementGetTypeID()) + continue; + + const IOHIDElementType type = IOHIDElementGetType(native); + if ((type != kIOHIDElementTypeInput_Axis) && + (type != kIOHIDElementTypeInput_Button) && + (type != kIOHIDElementTypeInput_Misc)) + { + continue; + } + + CFMutableArrayRef target = NULL; + + const uint32_t usage = IOHIDElementGetUsage(native); + const uint32_t page = IOHIDElementGetUsagePage(native); + if (page == kHIDPage_GenericDesktop) + { + switch (usage) + { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + case kHIDUsage_GD_Slider: + case kHIDUsage_GD_Dial: + case kHIDUsage_GD_Wheel: + target = axes; + break; + case kHIDUsage_GD_Hatswitch: + target = hats; + break; + } + } + else if (page == kHIDPage_Button) + target = buttons; + + if (target) + { + _GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS)); + element->native = native; + element->usage = usage; + element->index = (int) CFArrayGetCount(target); + element->minimum = IOHIDElementGetLogicalMin(native); + element->maximum = IOHIDElementGetLogicalMax(native); + CFArrayAppendValue(target, element); + } + } + + CFRelease(elements); + + CFArraySortValues(axes, CFRangeMake(0, CFArrayGetCount(axes)), + compareElements, NULL); + CFArraySortValues(buttons, CFRangeMake(0, CFArrayGetCount(buttons)), + compareElements, NULL); + CFArraySortValues(hats, CFRangeMake(0, CFArrayGetCount(hats)), + compareElements, NULL); + + js = _glfwAllocJoystick(name, guid, + CFArrayGetCount(axes), + CFArrayGetCount(buttons), + CFArrayGetCount(hats)); + + js->ns.device = device; + js->ns.axes = axes; + js->ns.buttons = buttons; + js->ns.hats = hats; + + _glfwInputJoystick(js, GLFW_CONNECTED); +} + +// Callback for user-initiated joystick removal +// +static void removeCallback(void* context, + IOReturn result, + void* sender, + IOHIDDeviceRef device) +{ + int jid; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (_glfw.joysticks[jid].ns.device == device) + { + closeJoystick(_glfw.joysticks + jid); + break; + } + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +void _glfwInitJoysticksNS(void) +{ + CFMutableArrayRef matching; + const long usages[] = + { + kHIDUsage_GD_Joystick, + kHIDUsage_GD_GamePad, + kHIDUsage_GD_MultiAxisController + }; + + _glfw.ns.hidManager = IOHIDManagerCreate(kCFAllocatorDefault, + kIOHIDOptionsTypeNone); + + matching = CFArrayCreateMutable(kCFAllocatorDefault, + 0, + &kCFTypeArrayCallBacks); + if (!matching) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create array"); + return; + } + + for (int i = 0; i < sizeof(usages) / sizeof(long); i++) + { + const long page = kHIDPage_GenericDesktop; + + CFMutableDictionaryRef dict = + CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!dict) + continue; + + CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault, + kCFNumberLongType, + &page); + CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault, + kCFNumberLongType, + &usages[i]); + if (pageRef && usageRef) + { + CFDictionarySetValue(dict, + CFSTR(kIOHIDDeviceUsagePageKey), + pageRef); + CFDictionarySetValue(dict, + CFSTR(kIOHIDDeviceUsageKey), + usageRef); + CFArrayAppendValue(matching, dict); + } + + if (pageRef) + CFRelease(pageRef); + if (usageRef) + CFRelease(usageRef); + + CFRelease(dict); + } + + IOHIDManagerSetDeviceMatchingMultiple(_glfw.ns.hidManager, matching); + CFRelease(matching); + + IOHIDManagerRegisterDeviceMatchingCallback(_glfw.ns.hidManager, + &matchCallback, NULL); + IOHIDManagerRegisterDeviceRemovalCallback(_glfw.ns.hidManager, + &removeCallback, NULL); + IOHIDManagerScheduleWithRunLoop(_glfw.ns.hidManager, + CFRunLoopGetMain(), + kCFRunLoopDefaultMode); + IOHIDManagerOpen(_glfw.ns.hidManager, kIOHIDOptionsTypeNone); + + // Execute the run loop once in order to register any initially-attached + // joysticks + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false); +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticksNS(void) +{ + int jid; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + closeJoystick(_glfw.joysticks + jid); + + CFRelease(_glfw.ns.hidManager); + _glfw.ns.hidManager = NULL; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) +{ + if (mode & _GLFW_POLL_AXES) + { + CFIndex i; + + for (i = 0; i < CFArrayGetCount(js->ns.axes); i++) + { + _GLFWjoyelementNS* axis = (_GLFWjoyelementNS*) + CFArrayGetValueAtIndex(js->ns.axes, i); + + const long raw = getElementValue(js, axis); + // Perform auto calibration + if (raw < axis->minimum) + axis->minimum = raw; + if (raw > axis->maximum) + axis->maximum = raw; + + const long delta = axis->maximum - axis->minimum; + if (delta == 0) + _glfwInputJoystickAxis(js, i, 0.f); + else + { + const float value = (2.f * (raw - axis->minimum) / delta) - 1.f; + _glfwInputJoystickAxis(js, i, value); + } + } + } + + if (mode & _GLFW_POLL_BUTTONS) + { + CFIndex i; + + for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++) + { + _GLFWjoyelementNS* button = (_GLFWjoyelementNS*) + CFArrayGetValueAtIndex(js->ns.buttons, i); + const char value = getElementValue(js, button) - button->minimum; + _glfwInputJoystickButton(js, i, value); + } + + for (i = 0; i < CFArrayGetCount(js->ns.hats); i++) + { + const int states[9] = + { + GLFW_HAT_UP, + GLFW_HAT_RIGHT_UP, + GLFW_HAT_RIGHT, + GLFW_HAT_RIGHT_DOWN, + GLFW_HAT_DOWN, + GLFW_HAT_LEFT_DOWN, + GLFW_HAT_LEFT, + GLFW_HAT_LEFT_UP, + GLFW_HAT_CENTERED + }; + + _GLFWjoyelementNS* hat = (_GLFWjoyelementNS*) + CFArrayGetValueAtIndex(js->ns.hats, i); + long state = getElementValue(js, hat) - hat->minimum; + if (state < 0 || state > 8) + state = 8; + + _glfwInputJoystickHat(js, i, states[state]); + } + } + + return js->present; +} + +void _glfwPlatformUpdateGamepadGUID(char* guid) +{ + if ((strncmp(guid + 4, "000000000000", 12) == 0) && + (strncmp(guid + 20, "000000000000", 12) == 0)) + { + char original[33]; + strcpy(original, guid); + sprintf(guid, "03000000%.4s0000%.4s000000000000", + original, original + 16); + } +} + diff --git a/src/external/glfw/src/cocoa_monitor.m b/src/external/glfw/src/cocoa_monitor.m new file mode 100644 index 00000000..6108342c --- /dev/null +++ b/src/external/glfw/src/cocoa_monitor.m @@ -0,0 +1,531 @@ +//======================================================================== +// GLFW 3.3 macOS - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + +#include +#include +#include +#include + + +// Get the name of the specified display, or NULL +// +static char* getDisplayName(CGDirectDisplayID displayID) +{ + io_iterator_t it; + io_service_t service; + CFDictionaryRef info; + + if (IOServiceGetMatchingServices(kIOMasterPortDefault, + IOServiceMatching("IODisplayConnect"), + &it) != 0) + { + // This may happen if a desktop Mac is running headless + return NULL; + } + + while ((service = IOIteratorNext(it)) != 0) + { + info = IODisplayCreateInfoDictionary(service, + kIODisplayOnlyPreferredName); + + CFNumberRef vendorIDRef = + CFDictionaryGetValue(info, CFSTR(kDisplayVendorID)); + CFNumberRef productIDRef = + CFDictionaryGetValue(info, CFSTR(kDisplayProductID)); + if (!vendorIDRef || !productIDRef) + { + CFRelease(info); + continue; + } + + unsigned int vendorID, productID; + CFNumberGetValue(vendorIDRef, kCFNumberIntType, &vendorID); + CFNumberGetValue(productIDRef, kCFNumberIntType, &productID); + + if (CGDisplayVendorNumber(displayID) == vendorID && + CGDisplayModelNumber(displayID) == productID) + { + // Info dictionary is used and freed below + break; + } + + CFRelease(info); + } + + IOObjectRelease(it); + + if (!service) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to find service port for display"); + return NULL; + } + + CFDictionaryRef names = + CFDictionaryGetValue(info, CFSTR(kDisplayProductName)); + + CFStringRef nameRef; + + if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), + (const void**) &nameRef)) + { + // This may happen if a desktop Mac is running headless + CFRelease(info); + return NULL; + } + + const CFIndex size = + CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), + kCFStringEncodingUTF8); + char* name = calloc(size + 1, 1); + CFStringGetCString(nameRef, name, size, kCFStringEncodingUTF8); + + CFRelease(info); + return name; +} + +// Check whether the display mode should be included in enumeration +// +static GLFWbool modeIsGood(CGDisplayModeRef mode) +{ + uint32_t flags = CGDisplayModeGetIOFlags(mode); + + if (!(flags & kDisplayModeValidFlag) || !(flags & kDisplayModeSafeFlag)) + return GLFW_FALSE; + if (flags & kDisplayModeInterlacedFlag) + return GLFW_FALSE; + if (flags & kDisplayModeStretchedFlag) + return GLFW_FALSE; + +#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100 + CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); + if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) && + CFStringCompare(format, CFSTR(IO32BitDirectPixels), 0)) + { + CFRelease(format); + return GLFW_FALSE; + } + + CFRelease(format); +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */ + return GLFW_TRUE; +} + +// Convert Core Graphics display mode to GLFW video mode +// +static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode, + CVDisplayLinkRef link) +{ + GLFWvidmode result; + result.width = (int) CGDisplayModeGetWidth(mode); + result.height = (int) CGDisplayModeGetHeight(mode); + result.refreshRate = (int) CGDisplayModeGetRefreshRate(mode); + + if (result.refreshRate == 0) + { + const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); + if (!(time.flags & kCVTimeIsIndefinite)) + result.refreshRate = (int) (time.timeScale / (double) time.timeValue); + } + +#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100 + CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); + if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0) + { + result.redBits = 5; + result.greenBits = 5; + result.blueBits = 5; + } + else +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */ + { + result.redBits = 8; + result.greenBits = 8; + result.blueBits = 8; + } + +#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100 + CFRelease(format); +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */ + return result; +} + +// Starts reservation for display fading +// +static CGDisplayFadeReservationToken beginFadeReservation(void) +{ + CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken; + + if (CGAcquireDisplayFadeReservation(5, &token) == kCGErrorSuccess) + { + CGDisplayFade(token, 0.3, + kCGDisplayBlendNormal, + kCGDisplayBlendSolidColor, + 0.0, 0.0, 0.0, + TRUE); + } + + return token; +} + +// Ends reservation for display fading +// +static void endFadeReservation(CGDisplayFadeReservationToken token) +{ + if (token != kCGDisplayFadeReservationInvalidToken) + { + CGDisplayFade(token, 0.5, + kCGDisplayBlendSolidColor, + kCGDisplayBlendNormal, + 0.0, 0.0, 0.0, + FALSE); + CGReleaseDisplayFadeReservation(token); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Poll for changes in the set of connected monitors +// +void _glfwPollMonitorsNS(void) +{ + uint32_t i, j, displayCount, disconnectedCount; + CGDirectDisplayID* displays; + _GLFWmonitor** disconnected = NULL; + + CGGetOnlineDisplayList(0, NULL, &displayCount); + displays = calloc(displayCount, sizeof(CGDirectDisplayID)); + CGGetOnlineDisplayList(displayCount, displays, &displayCount); + + for (i = 0; i < _glfw.monitorCount; i++) + _glfw.monitors[i]->ns.screen = nil; + + disconnectedCount = _glfw.monitorCount; + if (disconnectedCount) + { + disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); + memcpy(disconnected, + _glfw.monitors, + _glfw.monitorCount * sizeof(_GLFWmonitor*)); + } + + for (i = 0; i < displayCount; i++) + { + _GLFWmonitor* monitor; + const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]); + + if (CGDisplayIsAsleep(displays[i])) + continue; + + for (j = 0; j < disconnectedCount; j++) + { + // HACK: Compare unit numbers instead of display IDs to work around + // display replacement on machines with automatic graphics + // switching + if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber) + { + disconnected[j] = NULL; + break; + } + } + + const CGSize size = CGDisplayScreenSize(displays[i]); + char* name = getDisplayName(displays[i]); + if (!name) + name = strdup("Unknown"); + + monitor = _glfwAllocMonitor(name, size.width, size.height); + monitor->ns.displayID = displays[i]; + monitor->ns.unitNumber = unitNumber; + + free(name); + + _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); + } + + for (i = 0; i < disconnectedCount; i++) + { + if (disconnected[i]) + _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); + } + + free(disconnected); + free(displays); +} + +// Change the current video mode +// +GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired) +{ + CFArrayRef modes; + CFIndex count, i; + CVDisplayLinkRef link; + CGDisplayModeRef native = NULL; + GLFWvidmode current; + const GLFWvidmode* best; + + best = _glfwChooseVideoMode(monitor, desired); + _glfwPlatformGetVideoMode(monitor, ¤t); + if (_glfwCompareVideoModes(¤t, best) == 0) + return GLFW_TRUE; + + CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); + + modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); + count = CFArrayGetCount(modes); + + for (i = 0; i < count; i++) + { + CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); + if (!modeIsGood(dm)) + continue; + + const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); + if (_glfwCompareVideoModes(best, &mode) == 0) + { + native = dm; + break; + } + } + + if (native) + { + if (monitor->ns.previousMode == NULL) + monitor->ns.previousMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); + + CGDisplayFadeReservationToken token = beginFadeReservation(); + CGDisplaySetDisplayMode(monitor->ns.displayID, native, NULL); + endFadeReservation(token); + } + + CFRelease(modes); + CVDisplayLinkRelease(link); + + if (!native) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Monitor mode list changed"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Restore the previously saved (original) video mode +// +void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor) +{ + if (monitor->ns.previousMode) + { + CGDisplayFadeReservationToken token = beginFadeReservation(); + CGDisplaySetDisplayMode(monitor->ns.displayID, + monitor->ns.previousMode, NULL); + endFadeReservation(token); + + CGDisplayModeRelease(monitor->ns.previousMode); + monitor->ns.previousMode = NULL; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + const CGRect bounds = CGDisplayBounds(monitor->ns.displayID); + + if (xpos) + *xpos = (int) bounds.origin.x; + if (ypos) + *ypos = (int) bounds.origin.y; +} + +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + if (!monitor->ns.screen) + { + NSUInteger i; + NSArray* screens = [NSScreen screens]; + + for (i = 0; i < [screens count]; i++) + { + NSScreen* screen = [screens objectAtIndex:i]; + NSNumber* displayID = + [[screen deviceDescription] objectForKey:@"NSScreenNumber"]; + + // HACK: Compare unit numbers instead of display IDs to work around + // display replacement on machines with automatic graphics + // switching + if (monitor->ns.unitNumber == + CGDisplayUnitNumber([displayID unsignedIntValue])) + { + monitor->ns.screen = screen; + break; + } + } + + if (i == [screens count]) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to find a screen for monitor"); + return; + } + } + + const NSRect points = [monitor->ns.screen frame]; + const NSRect pixels = [monitor->ns.screen convertRectToBacking:points]; + + if (xscale) + *xscale = (float) (pixels.size.width / points.size.width); + if (yscale) + *yscale = (float) (pixels.size.height / points.size.height); +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) +{ + CFArrayRef modes; + CFIndex found, i, j; + GLFWvidmode* result; + CVDisplayLinkRef link; + + *count = 0; + + CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); + + modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); + found = CFArrayGetCount(modes); + result = calloc(found, sizeof(GLFWvidmode)); + + for (i = 0; i < found; i++) + { + CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); + if (!modeIsGood(dm)) + continue; + + const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); + + for (j = 0; j < *count; j++) + { + if (_glfwCompareVideoModes(result + j, &mode) == 0) + break; + } + + // Skip duplicate modes + if (i < *count) + continue; + + (*count)++; + result[*count - 1] = mode; + } + + CFRelease(modes); + CVDisplayLinkRelease(link); + return result; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode) +{ + CGDisplayModeRef displayMode; + CVDisplayLinkRef link; + + CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); + + displayMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); + *mode = vidmodeFromCGDisplayMode(displayMode, link); + CGDisplayModeRelease(displayMode); + + CVDisplayLinkRelease(link); +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID); + CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue)); + + CGGetDisplayTransferByTable(monitor->ns.displayID, + size, + values, + values + size, + values + size * 2, + &size); + + _glfwAllocGammaArrays(ramp, size); + + for (i = 0; i < size; i++) + { + ramp->red[i] = (unsigned short) (values[i] * 65535); + ramp->green[i] = (unsigned short) (values[i + size] * 65535); + ramp->blue[i] = (unsigned short) (values[i + size * 2] * 65535); + } + + free(values); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + int i; + CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue)); + + for (i = 0; i < ramp->size; i++) + { + values[i] = ramp->red[i] / 65535.f; + values[i + ramp->size] = ramp->green[i] / 65535.f; + values[i + ramp->size * 2] = ramp->blue[i] / 65535.f; + } + + CGSetDisplayTransferByTable(monitor->ns.displayID, + ramp->size, + values, + values + ramp->size, + values + ramp->size * 2); + + free(values); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay); + return monitor->ns.displayID; +} + diff --git a/src/external/glfw/src/cocoa_platform.h b/src/external/glfw/src/cocoa_platform.h new file mode 100644 index 00000000..61d0ee91 --- /dev/null +++ b/src/external/glfw/src/cocoa_platform.h @@ -0,0 +1,164 @@ +//======================================================================== +// GLFW 3.3 macOS - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include +#include + +#if defined(__OBJC__) +#import +#import +#else +#include +#include +typedef void* id; +#endif + +typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; + +typedef struct VkMacOSSurfaceCreateInfoMVK +{ + VkStructureType sType; + const void* pNext; + VkMacOSSurfaceCreateFlagsMVK flags; + const void* pView; +} VkMacOSSurfaceCreateInfoMVK; + +typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*); + +#include "posix_thread.h" +#include "cocoa_joystick.h" +#include "nsgl_context.h" +#include "egl_context.h" +#include "osmesa_context.h" + +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) + +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.view) +#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns +#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerNS ns +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns + +// HIToolbox.framework pointer typedefs +#define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData +typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void); +#define TISCopyCurrentKeyboardLayoutInputSource _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource +typedef void* (*PFN_TISGetInputSourceProperty)(TISInputSourceRef,CFStringRef); +#define TISGetInputSourceProperty _glfw.ns.tis.GetInputSourceProperty +typedef UInt8 (*PFN_LMGetKbdType)(void); +#define LMGetKbdType _glfw.ns.tis.GetKbdType + + +// Cocoa-specific per-window data +// +typedef struct _GLFWwindowNS +{ + id object; + id delegate; + id view; + id layer; + + GLFWbool maximized; + + // The total sum of the distances the cursor has been warped + // since the last cursor motion event was processed + // This is kept to counteract Cocoa doing the same internally + double cursorWarpDeltaX, cursorWarpDeltaY; + +} _GLFWwindowNS; + +// Cocoa-specific global data +// +typedef struct _GLFWlibraryNS +{ + CGEventSourceRef eventSource; + id delegate; + id autoreleasePool; + GLFWbool cursorHidden; + TISInputSourceRef inputSource; + IOHIDManagerRef hidManager; + id unicodeData; + id listener; + + char keyName[64]; + short int keycodes[256]; + short int scancodes[GLFW_KEY_LAST + 1]; + char* clipboardString; + CGPoint cascadePoint; + // Where to place the cursor when re-enabled + double restoreCursorPosX, restoreCursorPosY; + // The window whose disabled cursor mode is active + _GLFWwindow* disabledCursorWindow; + + struct { + CFBundleRef bundle; + PFN_TISCopyCurrentKeyboardLayoutInputSource CopyCurrentKeyboardLayoutInputSource; + PFN_TISGetInputSourceProperty GetInputSourceProperty; + PFN_LMGetKbdType GetKbdType; + CFStringRef kPropertyUnicodeKeyLayoutData; + } tis; + +} _GLFWlibraryNS; + +// Cocoa-specific per-monitor data +// +typedef struct _GLFWmonitorNS +{ + CGDirectDisplayID displayID; + CGDisplayModeRef previousMode; + uint32_t unitNumber; + id screen; + +} _GLFWmonitorNS; + +// Cocoa-specific per-cursor data +// +typedef struct _GLFWcursorNS +{ + id object; + +} _GLFWcursorNS; + +// Cocoa-specific global timer data +// +typedef struct _GLFWtimerNS +{ + uint64_t frequency; + +} _GLFWtimerNS; + + +void _glfwInitTimerNS(void); + +void _glfwPollMonitorsNS(void); +GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired); +void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor); + diff --git a/src/external/glfw/src/cocoa_time.c b/src/external/glfw/src/cocoa_time.c new file mode 100644 index 00000000..3b270351 --- /dev/null +++ b/src/external/glfw/src/cocoa_time.c @@ -0,0 +1,60 @@ +//======================================================================== +// GLFW 3.3 macOS - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimerNS(void) +{ + mach_timebase_info_data_t info; + mach_timebase_info(&info); + + _glfw.timer.ns.frequency = (info.denom * 1e9) / info.numer; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +uint64_t _glfwPlatformGetTimerValue(void) +{ + return mach_absolute_time(); +} + +uint64_t _glfwPlatformGetTimerFrequency(void) +{ + return _glfw.timer.ns.frequency; +} + diff --git a/src/external/glfw/src/cocoa_window.m b/src/external/glfw/src/cocoa_window.m new file mode 100644 index 00000000..1ee85bc6 --- /dev/null +++ b/src/external/glfw/src/cocoa_window.m @@ -0,0 +1,1863 @@ +//======================================================================== +// GLFW 3.3 macOS - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + +// Needed for _NSGetProgname +#include + +// HACK: The 10.12 SDK adds new symbols and immediately deprecates the old ones +#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 + #define NSWindowStyleMaskBorderless NSBorderlessWindowMask + #define NSWindowStyleMaskClosable NSClosableWindowMask + #define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask + #define NSWindowStyleMaskResizable NSResizableWindowMask + #define NSWindowStyleMaskTitled NSTitledWindowMask + #define NSEventModifierFlagCommand NSCommandKeyMask + #define NSEventModifierFlagControl NSControlKeyMask + #define NSEventModifierFlagOption NSAlternateKeyMask + #define NSEventModifierFlagShift NSShiftKeyMask + #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask + #define NSEventMaskAny NSAnyEventMask + #define NSEventTypeApplicationDefined NSApplicationDefined + #define NSEventTypeKeyUp NSKeyUp +#endif + + +// Returns the style mask corresponding to the window settings +// +static NSUInteger getStyleMask(_GLFWwindow* window) +{ + NSUInteger styleMask = 0; + + if (window->monitor || !window->decorated) + styleMask |= NSWindowStyleMaskBorderless; + else + { + styleMask |= NSWindowStyleMaskTitled | + NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable; + + if (window->resizable) + styleMask |= NSWindowStyleMaskResizable; + } + + return styleMask; +} + +// Center the cursor in the view of the window +// +static void centerCursor(_GLFWwindow *window) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); +} + +// Returns whether the cursor is in the client area of the specified window +// +static GLFWbool cursorInClientArea(_GLFWwindow* window) +{ + const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; + return [window->ns.view mouse:pos inRect:[window->ns.view frame]]; +} + +// Hides the cursor if not already hidden +// +static void hideCursor(_GLFWwindow* window) +{ + if (!_glfw.ns.cursorHidden) + { + [NSCursor hide]; + _glfw.ns.cursorHidden = GLFW_TRUE; + } +} + +// Shows the cursor if not already shown +// +static void showCursor(_GLFWwindow* window) +{ + if (_glfw.ns.cursorHidden) + { + [NSCursor unhide]; + _glfw.ns.cursorHidden = GLFW_FALSE; + } +} + +// Updates the cursor image according to its cursor mode +// +static void updateCursorImage(_GLFWwindow* window) +{ + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + showCursor(window); + + if (window->cursor) + [(NSCursor*) window->cursor->ns.object set]; + else + [[NSCursor arrowCursor] set]; + } + else + hideCursor(window); +} + +// Transforms the specified y-coordinate between the CG display and NS screen +// coordinate systems +// +static float transformY(float y) +{ + return CGDisplayBounds(CGMainDisplayID()).size.height - y; +} + +// Make the specified window and its video mode active on its monitor +// +static GLFWbool acquireMonitor(_GLFWwindow* window) +{ + const GLFWbool status = _glfwSetVideoModeNS(window->monitor, &window->videoMode); + const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID); + const NSRect frame = NSMakeRect(bounds.origin.x, + transformY(bounds.origin.y + bounds.size.height), + bounds.size.width, + bounds.size.height); + + [window->ns.object setFrame:frame display:YES]; + + _glfwInputMonitorWindow(window->monitor, window); + return status; +} + +// Remove the window and restore the original video mode +// +static void releaseMonitor(_GLFWwindow* window) +{ + if (window->monitor->window != window) + return; + + _glfwInputMonitorWindow(window->monitor, NULL); + _glfwRestoreVideoModeNS(window->monitor); +} + +// Translates macOS key modifiers into GLFW ones +// +static int translateFlags(NSUInteger flags) +{ + int mods = 0; + + if (flags & NSEventModifierFlagShift) + mods |= GLFW_MOD_SHIFT; + if (flags & NSEventModifierFlagControl) + mods |= GLFW_MOD_CONTROL; + if (flags & NSEventModifierFlagOption) + mods |= GLFW_MOD_ALT; + if (flags & NSEventModifierFlagCommand) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Translates a macOS keycode to a GLFW keycode +// +static int translateKey(unsigned int key) +{ + if (key >= sizeof(_glfw.ns.keycodes) / sizeof(_glfw.ns.keycodes[0])) + return GLFW_KEY_UNKNOWN; + + return _glfw.ns.keycodes[key]; +} + +// Translate a GLFW keycode to a Cocoa modifier flag +// +static NSUInteger translateKeyToModifierFlag(int key) +{ + switch (key) + { + case GLFW_KEY_LEFT_SHIFT: + case GLFW_KEY_RIGHT_SHIFT: + return NSEventModifierFlagShift; + case GLFW_KEY_LEFT_CONTROL: + case GLFW_KEY_RIGHT_CONTROL: + return NSEventModifierFlagControl; + case GLFW_KEY_LEFT_ALT: + case GLFW_KEY_RIGHT_ALT: + return NSEventModifierFlagOption; + case GLFW_KEY_LEFT_SUPER: + case GLFW_KEY_RIGHT_SUPER: + return NSEventModifierFlagCommand; + } + + return 0; +} + +// Defines a constant for empty ranges in NSTextInputClient +// +static const NSRange kEmptyRange = { NSNotFound, 0 }; + + +//------------------------------------------------------------------------ +// Delegate for window related notifications +//------------------------------------------------------------------------ + +@interface GLFWWindowDelegate : NSObject +{ + _GLFWwindow* window; +} + +- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow; + +@end + +@implementation GLFWWindowDelegate + +- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow +{ + self = [super init]; + if (self != nil) + window = initWindow; + + return self; +} + +- (BOOL)windowShouldClose:(id)sender +{ + _glfwInputWindowCloseRequest(window); + return NO; +} + +- (void)windowDidResize:(NSNotification *)notification +{ + if (window->context.client != GLFW_NO_API) + [window->context.nsgl.object update]; + + if (_glfw.ns.disabledCursorWindow == window) + centerCursor(window); + + const int maximized = [window->ns.object isZoomed]; + if (window->ns.maximized != maximized) + { + window->ns.maximized = maximized; + _glfwInputWindowMaximize(window, maximized); + } + + const NSRect contentRect = [window->ns.view frame]; + const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; + + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); +} + +- (void)windowDidMove:(NSNotification *)notification +{ + if (window->context.client != GLFW_NO_API) + [window->context.nsgl.object update]; + + if (_glfw.ns.disabledCursorWindow == window) + centerCursor(window); + + int x, y; + _glfwPlatformGetWindowPos(window, &x, &y); + _glfwInputWindowPos(window, x, y); +} + +- (void)windowDidMiniaturize:(NSNotification *)notification +{ + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowIconify(window, GLFW_TRUE); +} + +- (void)windowDidDeminiaturize:(NSNotification *)notification +{ + if (window->monitor) + acquireMonitor(window); + + _glfwInputWindowIconify(window, GLFW_FALSE); +} + +- (void)windowDidBecomeKey:(NSNotification *)notification +{ + if (_glfw.ns.disabledCursorWindow == window) + centerCursor(window); + + _glfwInputWindowFocus(window, GLFW_TRUE); + _glfwPlatformSetCursorMode(window, window->cursorMode); +} + +- (void)windowDidResignKey:(NSNotification *)notification +{ + if (window->monitor && window->autoIconify) + _glfwPlatformIconifyWindow(window); + + _glfwInputWindowFocus(window, GLFW_FALSE); +} + +@end + + +//------------------------------------------------------------------------ +// Delegate for application related notifications +//------------------------------------------------------------------------ + +@interface GLFWApplicationDelegate : NSObject +@end + +@implementation GLFWApplicationDelegate + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +{ + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) + _glfwInputWindowCloseRequest(window); + + return NSTerminateCancel; +} + +- (void)applicationDidChangeScreenParameters:(NSNotification *) notification +{ + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) + { + if (window->context.client != GLFW_NO_API) + [window->context.nsgl.object update]; + } + + _glfwPollMonitorsNS(); +} + +- (void)applicationDidFinishLaunching:(NSNotification *)notification +{ + [NSApp stop:nil]; + + _glfwPlatformPostEmptyEvent(); +} + +- (void)applicationDidHide:(NSNotification *)notification +{ + int i; + + for (i = 0; i < _glfw.monitorCount; i++) + _glfwRestoreVideoModeNS(_glfw.monitors[i]); +} + +@end + + +//------------------------------------------------------------------------ +// Content view class for the GLFW window +//------------------------------------------------------------------------ + +@interface GLFWContentView : NSView +{ + _GLFWwindow* window; + NSTrackingArea* trackingArea; + NSMutableAttributedString* markedText; +} + +- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow; + +@end + +@implementation GLFWContentView + +- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow +{ + self = [super init]; + if (self != nil) + { + window = initWindow; + trackingArea = nil; + markedText = [[NSMutableAttributedString alloc] init]; + + [self updateTrackingAreas]; + [self registerForDraggedTypes:[NSArray arrayWithObjects: + NSFilenamesPboardType, nil]]; + } + + return self; +} + +- (void)dealloc +{ + [trackingArea release]; + [markedText release]; + [super dealloc]; +} + +- (BOOL)isOpaque +{ + return [window->ns.object isOpaque]; +} + +- (BOOL)canBecomeKeyView +{ + return YES; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (BOOL)wantsUpdateLayer +{ + return YES; +} + +- (id)makeBackingLayer +{ + if (window->ns.layer) + return window->ns.layer; + + return [super makeBackingLayer]; +} + +- (void)cursorUpdate:(NSEvent *)event +{ + updateCursorImage(window); +} + +- (void)mouseDown:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_LEFT, + GLFW_PRESS, + translateFlags([event modifierFlags])); +} + +- (void)mouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)mouseUp:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE, + translateFlags([event modifierFlags])); +} + +- (void)mouseMoved:(NSEvent *)event +{ + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + const double dx = [event deltaX] - window->ns.cursorWarpDeltaX; + const double dy = [event deltaY] - window->ns.cursorWarpDeltaY; + + _glfwInputCursorPos(window, + window->virtualCursorPosX + dx, + window->virtualCursorPosY + dy); + } + else + { + const NSRect contentRect = [window->ns.view frame]; + const NSPoint pos = [event locationInWindow]; + + _glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y); + } + + window->ns.cursorWarpDeltaX = 0; + window->ns.cursorWarpDeltaY = 0; +} + +- (void)rightMouseDown:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_RIGHT, + GLFW_PRESS, + translateFlags([event modifierFlags])); +} + +- (void)rightMouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)rightMouseUp:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_RIGHT, + GLFW_RELEASE, + translateFlags([event modifierFlags])); +} + +- (void)otherMouseDown:(NSEvent *)event +{ + _glfwInputMouseClick(window, + (int) [event buttonNumber], + GLFW_PRESS, + translateFlags([event modifierFlags])); +} + +- (void)otherMouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)otherMouseUp:(NSEvent *)event +{ + _glfwInputMouseClick(window, + (int) [event buttonNumber], + GLFW_RELEASE, + translateFlags([event modifierFlags])); +} + +- (void)mouseExited:(NSEvent *)event +{ + if (window->cursorMode == GLFW_CURSOR_HIDDEN) + showCursor(window); + + _glfwInputCursorEnter(window, GLFW_FALSE); +} + +- (void)mouseEntered:(NSEvent *)event +{ + if (window->cursorMode == GLFW_CURSOR_HIDDEN) + hideCursor(window); + + _glfwInputCursorEnter(window, GLFW_TRUE); +} + +- (void)viewDidChangeBackingProperties +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; + + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); +} + +- (void)drawRect:(NSRect)rect +{ + _glfwInputWindowDamage(window); +} + +- (void)updateTrackingAreas +{ + if (trackingArea != nil) + { + [self removeTrackingArea:trackingArea]; + [trackingArea release]; + } + + const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | + NSTrackingActiveInKeyWindow | + NSTrackingEnabledDuringMouseDrag | + NSTrackingCursorUpdate | + NSTrackingInVisibleRect | + NSTrackingAssumeInside; + + trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] + options:options + owner:self + userInfo:nil]; + + [self addTrackingArea:trackingArea]; + [super updateTrackingAreas]; +} + +- (void)keyDown:(NSEvent *)event +{ + const int key = translateKey([event keyCode]); + const int mods = translateFlags([event modifierFlags]); + + _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods); + + [self interpretKeyEvents:[NSArray arrayWithObject:event]]; +} + +- (void)flagsChanged:(NSEvent *)event +{ + int action; + const unsigned int modifierFlags = + [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; + const int key = translateKey([event keyCode]); + const int mods = translateFlags(modifierFlags); + const NSUInteger keyFlag = translateKeyToModifierFlag(key); + + if (keyFlag & modifierFlags) + { + if (window->keys[key] == GLFW_PRESS) + action = GLFW_RELEASE; + else + action = GLFW_PRESS; + } + else + action = GLFW_RELEASE; + + _glfwInputKey(window, key, [event keyCode], action, mods); +} + +- (void)keyUp:(NSEvent *)event +{ + const int key = translateKey([event keyCode]); + const int mods = translateFlags([event modifierFlags]); + _glfwInputKey(window, key, [event keyCode], GLFW_RELEASE, mods); +} + +- (void)scrollWheel:(NSEvent *)event +{ + double deltaX, deltaY; + + deltaX = [event scrollingDeltaX]; + deltaY = [event scrollingDeltaY]; + + if ([event hasPreciseScrollingDeltas]) + { + deltaX *= 0.1; + deltaY *= 0.1; + } + + if (fabs(deltaX) > 0.0 || fabs(deltaY) > 0.0) + _glfwInputScroll(window, deltaX, deltaY); +} + +- (NSDragOperation)draggingEntered:(id )sender +{ + if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) + == NSDragOperationGeneric) + { + [self setNeedsDisplay:YES]; + return NSDragOperationGeneric; + } + + return NSDragOperationNone; +} + +- (BOOL)prepareForDragOperation:(id )sender +{ + [self setNeedsDisplay:YES]; + return YES; +} + +- (BOOL)performDragOperation:(id )sender +{ + NSPasteboard* pasteboard = [sender draggingPasteboard]; + NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType]; + + const NSRect contentRect = [window->ns.view frame]; + _glfwInputCursorPos(window, + [sender draggingLocation].x, + contentRect.size.height - [sender draggingLocation].y); + + const int count = [files count]; + if (count) + { + NSEnumerator* e = [files objectEnumerator]; + char** paths = calloc(count, sizeof(char*)); + int i; + + for (i = 0; i < count; i++) + paths[i] = strdup([[e nextObject] UTF8String]); + + _glfwInputDrop(window, count, (const char**) paths); + + for (i = 0; i < count; i++) + free(paths[i]); + free(paths); + } + + return YES; +} + +- (void)concludeDragOperation:(id )sender +{ + [self setNeedsDisplay:YES]; +} + +- (BOOL)hasMarkedText +{ + return [markedText length] > 0; +} + +- (NSRange)markedRange +{ + if ([markedText length] > 0) + return NSMakeRange(0, [markedText length] - 1); + else + return kEmptyRange; +} + +- (NSRange)selectedRange +{ + return kEmptyRange; +} + +- (void)setMarkedText:(id)string + selectedRange:(NSRange)selectedRange + replacementRange:(NSRange)replacementRange +{ + [markedText release]; + if ([string isKindOfClass:[NSAttributedString class]]) + markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string]; + else + markedText = [[NSMutableAttributedString alloc] initWithString:string]; +} + +- (void)unmarkText +{ + [[markedText mutableString] setString:@""]; +} + +- (NSArray*)validAttributesForMarkedText +{ + return [NSArray array]; +} + +- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range + actualRange:(NSRangePointer)actualRange +{ + return nil; +} + +- (NSUInteger)characterIndexForPoint:(NSPoint)point +{ + return 0; +} + +- (NSRect)firstRectForCharacterRange:(NSRange)range + actualRange:(NSRangePointer)actualRange +{ + int xpos, ypos; + _glfwPlatformGetWindowPos(window, &xpos, &ypos); + const NSRect contentRect = [window->ns.view frame]; + return NSMakeRect(xpos, transformY(ypos + contentRect.size.height), 0.0, 0.0); +} + +- (void)insertText:(id)string replacementRange:(NSRange)replacementRange +{ + NSString* characters; + NSEvent* event = [NSApp currentEvent]; + const int mods = translateFlags([event modifierFlags]); + const int plain = !(mods & GLFW_MOD_SUPER); + + if ([string isKindOfClass:[NSAttributedString class]]) + characters = [string string]; + else + characters = (NSString*) string; + + NSUInteger i, length = [characters length]; + + for (i = 0; i < length; i++) + { + const unichar codepoint = [characters characterAtIndex:i]; + if ((codepoint & 0xff00) == 0xf700) + continue; + + _glfwInputChar(window, codepoint, mods, plain); + } +} + +- (void)doCommandBySelector:(SEL)selector +{ +} + +@end + + +//------------------------------------------------------------------------ +// GLFW window class +//------------------------------------------------------------------------ + +@interface GLFWWindow : NSWindow {} +@end + +@implementation GLFWWindow + +- (BOOL)canBecomeKeyWindow +{ + // Required for NSWindowStyleMaskBorderless windows + return YES; +} + +- (BOOL)canBecomeMainWindow +{ + return YES; +} + +@end + + +//------------------------------------------------------------------------ +// GLFW application class +//------------------------------------------------------------------------ + +@interface GLFWApplication : NSApplication +{ + NSArray* nibObjects; +} + +@end + +@implementation GLFWApplication + +// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost +// This works around an AppKit bug, where key up events while holding +// down the command key don't get sent to the key window. +- (void)sendEvent:(NSEvent *)event +{ + if ([event type] == NSEventTypeKeyUp && + ([event modifierFlags] & NSEventModifierFlagCommand)) + { + [[self keyWindow] sendEvent:event]; + } + else + [super sendEvent:event]; +} + + +// No-op thread entry point +// +- (void)doNothing:(id)object +{ +} + +- (void)loadMainMenu +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 100800 + [[NSBundle mainBundle] loadNibNamed:@"MainMenu" + owner:NSApp + topLevelObjects:&nibObjects]; +#else + [[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp]; +#endif +} +@end + +// Set up the menu bar (manually) +// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that +// could go away at any moment, lots of stuff that really should be +// localize(d|able), etc. Add a nib to save us this horror. +// +static void createMenuBar(void) +{ + size_t i; + NSString* appName = nil; + NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary]; + NSString* nameKeys[] = + { + @"CFBundleDisplayName", + @"CFBundleName", + @"CFBundleExecutable", + }; + + // Try to figure out what the calling application is called + + for (i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++) + { + id name = [bundleInfo objectForKey:nameKeys[i]]; + if (name && + [name isKindOfClass:[NSString class]] && + ![name isEqualToString:@""]) + { + appName = name; + break; + } + } + + if (!appName) + { + char** progname = _NSGetProgname(); + if (progname && *progname) + appName = [NSString stringWithUTF8String:*progname]; + else + appName = @"GLFW Application"; + } + + NSMenu* bar = [[NSMenu alloc] init]; + [NSApp setMainMenu:bar]; + + NSMenuItem* appMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + NSMenu* appMenu = [[NSMenu alloc] init]; + [appMenuItem setSubmenu:appMenu]; + + [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] + action:@selector(orderFrontStandardAboutPanel:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + NSMenu* servicesMenu = [[NSMenu alloc] init]; + [NSApp setServicesMenu:servicesMenu]; + [[appMenu addItemWithTitle:@"Services" + action:NULL + keyEquivalent:@""] setSubmenu:servicesMenu]; + [servicesMenu release]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] + action:@selector(hide:) + keyEquivalent:@"h"]; + [[appMenu addItemWithTitle:@"Hide Others" + action:@selector(hideOtherApplications:) + keyEquivalent:@"h"] + setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand]; + [appMenu addItemWithTitle:@"Show All" + action:@selector(unhideAllApplications:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] + action:@selector(terminate:) + keyEquivalent:@"q"]; + + NSMenuItem* windowMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + [bar release]; + NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + [NSApp setWindowsMenu:windowMenu]; + [windowMenuItem setSubmenu:windowMenu]; + + [windowMenu addItemWithTitle:@"Minimize" + action:@selector(performMiniaturize:) + keyEquivalent:@"m"]; + [windowMenu addItemWithTitle:@"Zoom" + action:@selector(performZoom:) + keyEquivalent:@""]; + [windowMenu addItem:[NSMenuItem separatorItem]]; + [windowMenu addItemWithTitle:@"Bring All to Front" + action:@selector(arrangeInFront:) + keyEquivalent:@""]; + + // TODO: Make this appear at the bottom of the menu (for consistency) + [windowMenu addItem:[NSMenuItem separatorItem]]; + [[windowMenu addItemWithTitle:@"Enter Full Screen" + action:@selector(toggleFullScreen:) + keyEquivalent:@"f"] + setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand]; + + // Prior to Snow Leopard, we need to use this oddly-named semi-private API + // to get the application menu working properly. + SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:"); + [NSApp performSelector:setAppleMenuSelector withObject:appMenu]; +} + +// Initialize the Cocoa Application Kit +// +static GLFWbool initializeAppKit(void) +{ + if (NSApp) + return GLFW_TRUE; + + // Implicitly create shared NSApplication instance + [GLFWApplication sharedApplication]; + + // Make Cocoa enter multi-threaded mode + [NSThread detachNewThreadSelector:@selector(doNothing:) + toTarget:NSApp + withObject:nil]; + + if (_glfw.hints.init.ns.menubar) + { + // In case we are unbundled, make us a proper UI application + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + + // Menu bar setup must go between sharedApplication above and + // finishLaunching below, in order to properly emulate the behavior + // of NSApplicationMain + + if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) + [NSApp loadMainMenu]; + else + createMenuBar(); + } + + // There can only be one application delegate, but we allocate it the + // first time a window is created to keep all window code in this file + _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; + if (_glfw.ns.delegate == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create application delegate"); + return GLFW_FALSE; + } + + [NSApp setDelegate:_glfw.ns.delegate]; + [NSApp run]; + + // Press and Hold prevents some keys from emitting repeated characters + NSDictionary* defaults = + [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], + @"ApplePressAndHoldEnabled", + nil]; + [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; + + return GLFW_TRUE; +} + +// Create the Cocoa window +// +static GLFWbool createNativeWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ + window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window]; + if (window->ns.delegate == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create window delegate"); + return GLFW_FALSE; + } + + NSRect contentRect; + + if (window->monitor) + { + GLFWvidmode mode; + int xpos, ypos; + + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + + contentRect = NSMakeRect(xpos, ypos, mode.width, mode.height); + } + else + contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height); + + window->ns.object = [[GLFWWindow alloc] + initWithContentRect:contentRect + styleMask:getStyleMask(window) + backing:NSBackingStoreBuffered + defer:NO]; + + if (window->ns.object == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create window"); + return GLFW_FALSE; + } + + if (window->monitor) + [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; + else + { + [window->ns.object center]; + _glfw.ns.cascadePoint = + NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint: + NSPointFromCGPoint(_glfw.ns.cascadePoint)]); + + if (wndconfig->resizable) + { + const NSWindowCollectionBehavior behavior = + NSWindowCollectionBehaviorFullScreenPrimary | + NSWindowCollectionBehaviorManaged; + [window->ns.object setCollectionBehavior:behavior]; + } + + if (wndconfig->floating) + [window->ns.object setLevel:NSFloatingWindowLevel]; + + if (wndconfig->maximized) + [window->ns.object zoom:nil]; + } + + if (wndconfig->ns.frame) + [window->ns.object setFrameAutosaveName:[NSString stringWithUTF8String:wndconfig->title]]; + + window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; + + if (wndconfig->ns.retina) + [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; + + if (fbconfig->transparent) + { + [window->ns.object setOpaque:NO]; + [window->ns.object setBackgroundColor:[NSColor clearColor]]; + } + + [window->ns.object setContentView:window->ns.view]; + [window->ns.object makeFirstResponder:window->ns.view]; + [window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]]; + [window->ns.object setDelegate:window->ns.delegate]; + [window->ns.object setAcceptsMouseMovedEvents:YES]; + [window->ns.object setRestorable:NO]; + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!initializeAppKit()) + return GLFW_FALSE; + + if (!createNativeWindow(window, wndconfig, fbconfig)) + return GLFW_FALSE; + + if (ctxconfig->client != GLFW_NO_API) + { + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwInitNSGL()) + return GLFW_FALSE; + if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwInitOSMesa()) + return GLFW_FALSE; + if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + } + + if (window->monitor) + { + _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); + if (!acquireMonitor(window)) + return GLFW_FALSE; + + if (wndconfig->centerCursor) + centerCursor(window); + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (_glfw.ns.disabledCursorWindow == window) + _glfw.ns.disabledCursorWindow = NULL; + + [window->ns.object orderOut:nil]; + + if (window->monitor) + releaseMonitor(window); + + if (window->context.destroy) + window->context.destroy(window); + + [window->ns.object setDelegate:nil]; + [window->ns.delegate release]; + window->ns.delegate = nil; + + [window->ns.view release]; + window->ns.view = nil; + + [window->ns.object close]; + window->ns.object = nil; + + [_glfw.ns.autoreleasePool drain]; + _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title) +{ + NSString* string = [NSString stringWithUTF8String:title]; + [window->ns.object setTitle:string]; + // HACK: Set the miniwindow title explicitly as setTitle: doesn't update it + // if the window lacks NSWindowStyleMaskTitled + [window->ns.object setMiniwindowTitle:string]; +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + // Regular windows do not have icons +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + const NSRect contentRect = + [window->ns.object contentRectForFrameRect:[window->ns.object frame]]; + + if (xpos) + *xpos = contentRect.origin.x; + if (ypos) + *ypos = transformY(contentRect.origin.y + contentRect.size.height); +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int x, int y) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect dummyRect = NSMakeRect(x, transformY(y + contentRect.size.height), 0, 0); + const NSRect frameRect = [window->ns.object frameRectForContentRect:dummyRect]; + [window->ns.object setFrameOrigin:frameRect.origin]; +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + const NSRect contentRect = [window->ns.view frame]; + + if (width) + *width = contentRect.size.width; + if (height) + *height = contentRect.size.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + if (window->monitor) + { + if (window->monitor->window == window) + acquireMonitor(window); + } + else + [window->ns.object setContentSize:NSMakeSize(width, height)]; +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) + [window->ns.object setContentMinSize:NSMakeSize(0, 0)]; + else + [window->ns.object setContentMinSize:NSMakeSize(minwidth, minheight)]; + + if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE) + [window->ns.object setContentMaxSize:NSMakeSize(DBL_MAX, DBL_MAX)]; + else + [window->ns.object setContentMaxSize:NSMakeSize(maxwidth, maxheight)]; +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +{ + if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) + [window->ns.object setResizeIncrements:NSMakeSize(1.0, 1.0)]; + else + [window->ns.object setContentAspectRatio:NSMakeSize(numer, denom)]; +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; + + if (width) + *width = (int) fbRect.size.width; + if (height) + *height = (int) fbRect.size.height; +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect]; + + if (left) + *left = contentRect.origin.x - frameRect.origin.x; + if (top) + *top = frameRect.origin.y + frameRect.size.height - + contentRect.origin.y - contentRect.size.height; + if (right) + *right = frameRect.origin.x + frameRect.size.width - + contentRect.origin.x - contentRect.size.width; + if (bottom) + *bottom = contentRect.origin.y - frameRect.origin.y; +} + +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + const NSRect points = [window->ns.view frame]; + const NSRect pixels = [window->ns.view convertRectToBacking:points]; + + if (xscale) + *xscale = (float) (pixels.size.width / points.size.width); + if (yscale) + *yscale = (float) (pixels.size.height / points.size.height); +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + [window->ns.object miniaturize:nil]; +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + if ([window->ns.object isMiniaturized]) + [window->ns.object deminiaturize:nil]; + else if ([window->ns.object isZoomed]) + [window->ns.object zoom:nil]; +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + if (![window->ns.object isZoomed]) + [window->ns.object zoom:nil]; +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + [window->ns.object orderFront:nil]; +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + [window->ns.object orderOut:nil]; +} + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + [NSApp requestUserAttention:NSInformationalRequest]; +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + // Make us the active application + // HACK: This has been moved here from initializeAppKit to prevent + // applications using only hidden windows from being activated, but + // should probably not be done every time any window is shown + [NSApp activateIgnoringOtherApps:YES]; + + [window->ns.object makeKeyAndOrderFront:nil]; +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + const NSRect contentRect = + NSMakeRect(xpos, transformY(ypos + height), width, height); + const NSRect frameRect = + [window->ns.object frameRectForContentRect:contentRect + styleMask:getStyleMask(window)]; + + [window->ns.object setFrame:frameRect display:YES]; + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitor(window, monitor); + + // HACK: Allow the state cached in Cocoa to catch up to reality + // TODO: Solve this in a less terrible way + _glfwPlatformPollEvents(); + + const NSUInteger styleMask = getStyleMask(window); + [window->ns.object setStyleMask:styleMask]; + [window->ns.object makeFirstResponder:window->ns.view]; + + NSRect contentRect; + + if (monitor) + { + GLFWvidmode mode; + + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + + contentRect = NSMakeRect(xpos, transformY(ypos + mode.height), + mode.width, mode.height); + } + else + { + contentRect = NSMakeRect(xpos, transformY(ypos + height), + width, height); + } + + NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect + styleMask:styleMask]; + [window->ns.object setFrame:frameRect display:YES]; + + if (monitor) + { + [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; + [window->ns.object setHasShadow:NO]; + + acquireMonitor(window); + } + else + { + if (window->numer != GLFW_DONT_CARE && + window->denom != GLFW_DONT_CARE) + { + [window->ns.object setContentAspectRatio:NSMakeSize(window->numer, + window->denom)]; + } + + if (window->minwidth != GLFW_DONT_CARE && + window->minheight != GLFW_DONT_CARE) + { + [window->ns.object setContentMinSize:NSMakeSize(window->minwidth, + window->minheight)]; + } + + if (window->maxwidth != GLFW_DONT_CARE && + window->maxheight != GLFW_DONT_CARE) + { + [window->ns.object setContentMaxSize:NSMakeSize(window->maxwidth, + window->maxheight)]; + } + + if (window->floating) + [window->ns.object setLevel:NSFloatingWindowLevel]; + else + [window->ns.object setLevel:NSNormalWindowLevel]; + + [window->ns.object setHasShadow:YES]; + // HACK: Clearing NSWindowStyleMaskTitled resets and disables the window + // title property but the miniwindow title property is unaffected + [window->ns.object setTitle:[window->ns.object miniwindowTitle]]; + } +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + return [window->ns.object isKeyWindow]; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + return [window->ns.object isMiniaturized]; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + return [window->ns.object isVisible]; +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + return [window->ns.object isZoomed]; +} + +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + return ![window->ns.object isOpaque] && ![window->ns.view isOpaque]; +} + +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) +{ + [window->ns.object setStyleMask:getStyleMask(window)]; +} + +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) +{ + [window->ns.object setStyleMask:getStyleMask(window)]; + [window->ns.object makeFirstResponder:window->ns.view]; +} + +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) +{ + if (enabled) + [window->ns.object setLevel:NSFloatingWindowLevel]; + else + [window->ns.object setLevel:NSNormalWindowLevel]; +} + +void _glfwPlatformPollEvents(void) +{ + for (;;) + { + NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event == nil) + break; + + [NSApp sendEvent:event]; + } + + [_glfw.ns.autoreleasePool drain]; + _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; +} + +void _glfwPlatformWaitEvents(void) +{ + // I wanted to pass NO to dequeue:, and rely on PollEvents to + // dequeue and send. For reasons not at all clear to me, passing + // NO to dequeue: causes this method never to return. + NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny + untilDate:[NSDate distantFuture] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + [NSApp sendEvent:event]; + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout]; + NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny + untilDate:date + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event) + [NSApp sendEvent:event]; + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformPostEmptyEvent(void) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined + location:NSMakePoint(0, 0) + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + subtype:0 + data1:0 + data2:0]; + [NSApp postEvent:event atStart:YES]; + [pool drain]; +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; + + if (xpos) + *xpos = pos.x; + if (ypos) + *ypos = contentRect.size.height - pos.y - 1; +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +{ + updateCursorImage(window); + + const NSRect contentRect = [window->ns.view frame]; + const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; + + window->ns.cursorWarpDeltaX += x - pos.x; + window->ns.cursorWarpDeltaY += y - contentRect.size.height + pos.y; + + if (window->monitor) + { + CGDisplayMoveCursorToPoint(window->monitor->ns.displayID, + CGPointMake(x, y)); + } + else + { + const NSRect localRect = NSMakeRect(x, contentRect.size.height - y - 1, 0, 0); + const NSRect globalRect = [window->ns.object convertRectToScreen:localRect]; + const NSPoint globalPoint = globalRect.origin; + + CGWarpMouseCursorPosition(CGPointMake(globalPoint.x, + transformY(globalPoint.y))); + } +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + if (mode == GLFW_CURSOR_DISABLED) + { + _glfw.ns.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.ns.restoreCursorPosX, + &_glfw.ns.restoreCursorPosY); + centerCursor(window); + CGAssociateMouseAndMouseCursorPosition(false); + } + else if (_glfw.ns.disabledCursorWindow == window) + { + _glfw.ns.disabledCursorWindow = NULL; + CGAssociateMouseAndMouseCursorPosition(true); + _glfwPlatformSetCursorPos(window, + _glfw.ns.restoreCursorPosX, + _glfw.ns.restoreCursorPosY); + } + + if (cursorInClientArea(window)) + updateCursorImage(window); +} + +const char* _glfwPlatformGetScancodeName(int scancode) +{ + UInt32 deadKeyState = 0; + UniChar characters[8]; + UniCharCount characterCount = 0; + + if (UCKeyTranslate([(NSData*) _glfw.ns.unicodeData bytes], + scancode, + kUCKeyActionDisplay, + 0, + LMGetKbdType(), + kUCKeyTranslateNoDeadKeysBit, + &deadKeyState, + sizeof(characters) / sizeof(characters[0]), + &characterCount, + characters) != noErr) + { + return NULL; + } + + if (!characterCount) + return NULL; + + CFStringRef string = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, + characters, + characterCount, + kCFAllocatorNull); + CFStringGetCString(string, + _glfw.ns.keyName, + sizeof(_glfw.ns.keyName), + kCFStringEncodingUTF8); + CFRelease(string); + + return _glfw.ns.keyName; +} + +int _glfwPlatformGetKeyScancode(int key) +{ + return _glfw.ns.scancodes[key]; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + NSImage* native; + NSBitmapImageRep* rep; + + if (!initializeAppKit()) + return GLFW_FALSE; + + rep = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:NULL + pixelsWide:image->width + pixelsHigh:image->height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSCalibratedRGBColorSpace + bitmapFormat:NSAlphaNonpremultipliedBitmapFormat + bytesPerRow:image->width * 4 + bitsPerPixel:32]; + + if (rep == nil) + return GLFW_FALSE; + + memcpy([rep bitmapData], image->pixels, image->width * image->height * 4); + + native = [[NSImage alloc] initWithSize:NSMakeSize(image->width, image->height)]; + [native addRepresentation:rep]; + + cursor->ns.object = [[NSCursor alloc] initWithImage:native + hotSpot:NSMakePoint(xhot, yhot)]; + + [native release]; + [rep release]; + + if (cursor->ns.object == nil) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + if (!initializeAppKit()) + return GLFW_FALSE; + + if (shape == GLFW_ARROW_CURSOR) + cursor->ns.object = [NSCursor arrowCursor]; + else if (shape == GLFW_IBEAM_CURSOR) + cursor->ns.object = [NSCursor IBeamCursor]; + else if (shape == GLFW_CROSSHAIR_CURSOR) + cursor->ns.object = [NSCursor crosshairCursor]; + else if (shape == GLFW_HAND_CURSOR) + cursor->ns.object = [NSCursor pointingHandCursor]; + else if (shape == GLFW_HRESIZE_CURSOR) + cursor->ns.object = [NSCursor resizeLeftRightCursor]; + else if (shape == GLFW_VRESIZE_CURSOR) + cursor->ns.object = [NSCursor resizeUpDownCursor]; + + if (!cursor->ns.object) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to retrieve standard cursor"); + return GLFW_FALSE; + } + + [cursor->ns.object retain]; + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + if (cursor->ns.object) + [(NSCursor*) cursor->ns.object release]; +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + if (cursorInClientArea(window)) + updateCursorImage(window); +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil]; + + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + [pasteboard declareTypes:types owner:nil]; + [pasteboard setString:[NSString stringWithUTF8String:string] + forType:NSStringPboardType]; +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + + if (![[pasteboard types] containsObject:NSStringPboardType]) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "Cocoa: Failed to retrieve string from pasteboard"); + return NULL; + } + + NSString* object = [pasteboard stringForType:NSStringPboardType]; + if (!object) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to retrieve object from pasteboard"); + return NULL; + } + + free(_glfw.ns.clipboardString); + _glfw.ns.clipboardString = strdup([object UTF8String]); + + return _glfw.ns.clipboardString; +} + +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) +{ + if (!_glfw.vk.KHR_surface || !_glfw.vk.MVK_macos_surface) + return; + + extensions[0] = "VK_KHR_surface"; + extensions[1] = "VK_MVK_macos_surface"; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + return GLFW_TRUE; +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 + VkResult err; + VkMacOSSurfaceCreateInfoMVK sci; + PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; + + vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK) + vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK"); + if (!vkCreateMacOSSurfaceMVK) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Cocoa: Vulkan instance missing VK_MVK_macos_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + // HACK: Dynamically load Core Animation to avoid adding an extra + // dependency for the majority who don't use MoltenVK + NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"]; + if (!bundle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to find QuartzCore.framework"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + // NOTE: Create the layer here as makeBackingLayer should not return nil + window->ns.layer = [[bundle classNamed:@"CAMetalLayer"] layer]; + if (!window->ns.layer) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create layer for view"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + [window->ns.view setWantsLayer:YES]; + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; + sci.pView = window->ns.view; + + err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create Vulkan surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; +#else + return VK_ERROR_EXTENSION_NOT_PRESENT; +#endif +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(nil); + return window->ns.object; +} + diff --git a/src/external/glfw/src/context.c b/src/external/glfw/src/context.c new file mode 100644 index 00000000..3842f0a3 --- /dev/null +++ b/src/external/glfw/src/context.c @@ -0,0 +1,723 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) +{ + if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API && + ctxconfig->source != GLFW_EGL_CONTEXT_API && + ctxconfig->source != GLFW_OSMESA_CONTEXT_API) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid context creation API 0x%08X", + ctxconfig->source); + return GLFW_FALSE; + } + + if (ctxconfig->client != GLFW_NO_API && + ctxconfig->client != GLFW_OPENGL_API && + ctxconfig->client != GLFW_OPENGL_ES_API) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid client API 0x%08X", + ctxconfig->client); + return GLFW_FALSE; + } + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if ((ctxconfig->major < 1 || ctxconfig->minor < 0) || + (ctxconfig->major == 1 && ctxconfig->minor > 5) || + (ctxconfig->major == 2 && ctxconfig->minor > 1) || + (ctxconfig->major == 3 && ctxconfig->minor > 3)) + { + // OpenGL 1.0 is the smallest valid version + // OpenGL 1.x series ended with version 1.5 + // OpenGL 2.x series ended with version 2.1 + // OpenGL 3.x series ended with version 3.3 + // For now, let everything else through + + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid OpenGL version %i.%i", + ctxconfig->major, ctxconfig->minor); + return GLFW_FALSE; + } + + if (ctxconfig->profile) + { + if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE && + ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid OpenGL profile 0x%08X", + ctxconfig->profile); + return GLFW_FALSE; + } + + if (ctxconfig->major <= 2 || + (ctxconfig->major == 3 && ctxconfig->minor < 2)) + { + // Desktop OpenGL context profiles are only defined for version 3.2 + // and above + + _glfwInputError(GLFW_INVALID_VALUE, + "Context profiles are only defined for OpenGL version 3.2 and above"); + return GLFW_FALSE; + } + } + + if (ctxconfig->forward && ctxconfig->major <= 2) + { + // Forward-compatible contexts are only defined for OpenGL version 3.0 and above + _glfwInputError(GLFW_INVALID_VALUE, + "Forward-compatibility is only defined for OpenGL version 3.0 and above"); + return GLFW_FALSE; + } + } + else if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + if (ctxconfig->major < 1 || ctxconfig->minor < 0 || + (ctxconfig->major == 1 && ctxconfig->minor > 1) || + (ctxconfig->major == 2 && ctxconfig->minor > 0)) + { + // OpenGL ES 1.0 is the smallest valid version + // OpenGL ES 1.x series ended with version 1.1 + // OpenGL ES 2.x series ended with version 2.0 + // For now, let everything else through + + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid OpenGL ES version %i.%i", + ctxconfig->major, ctxconfig->minor); + return GLFW_FALSE; + } + } + + if (ctxconfig->robustness) + { + if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION && + ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid context robustness mode 0x%08X", + ctxconfig->robustness); + return GLFW_FALSE; + } + } + + if (ctxconfig->release) + { + if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE && + ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid context release behavior 0x%08X", + ctxconfig->release); + return GLFW_FALSE; + } + } + + return GLFW_TRUE; +} + +const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, + const _GLFWfbconfig* alternatives, + unsigned int count) +{ + unsigned int i; + unsigned int missing, leastMissing = UINT_MAX; + unsigned int colorDiff, leastColorDiff = UINT_MAX; + unsigned int extraDiff, leastExtraDiff = UINT_MAX; + const _GLFWfbconfig* current; + const _GLFWfbconfig* closest = NULL; + + for (i = 0; i < count; i++) + { + current = alternatives + i; + + if (desired->stereo > 0 && current->stereo == 0) + { + // Stereo is a hard constraint + continue; + } + + if (desired->doublebuffer != current->doublebuffer) + { + // Double buffering is a hard constraint + continue; + } + + // Count number of missing buffers + { + missing = 0; + + if (desired->alphaBits > 0 && current->alphaBits == 0) + missing++; + + if (desired->depthBits > 0 && current->depthBits == 0) + missing++; + + if (desired->stencilBits > 0 && current->stencilBits == 0) + missing++; + + if (desired->auxBuffers > 0 && + current->auxBuffers < desired->auxBuffers) + { + missing += desired->auxBuffers - current->auxBuffers; + } + + if (desired->samples > 0 && current->samples == 0) + { + // Technically, several multisampling buffers could be + // involved, but that's a lower level implementation detail and + // not important to us here, so we count them as one + missing++; + } + + if (desired->transparent != current->transparent) + missing++; + } + + // These polynomials make many small channel size differences matter + // less than one large channel size difference + + // Calculate color channel size difference value + { + colorDiff = 0; + + if (desired->redBits != GLFW_DONT_CARE) + { + colorDiff += (desired->redBits - current->redBits) * + (desired->redBits - current->redBits); + } + + if (desired->greenBits != GLFW_DONT_CARE) + { + colorDiff += (desired->greenBits - current->greenBits) * + (desired->greenBits - current->greenBits); + } + + if (desired->blueBits != GLFW_DONT_CARE) + { + colorDiff += (desired->blueBits - current->blueBits) * + (desired->blueBits - current->blueBits); + } + } + + // Calculate non-color channel size difference value + { + extraDiff = 0; + + if (desired->alphaBits != GLFW_DONT_CARE) + { + extraDiff += (desired->alphaBits - current->alphaBits) * + (desired->alphaBits - current->alphaBits); + } + + if (desired->depthBits != GLFW_DONT_CARE) + { + extraDiff += (desired->depthBits - current->depthBits) * + (desired->depthBits - current->depthBits); + } + + if (desired->stencilBits != GLFW_DONT_CARE) + { + extraDiff += (desired->stencilBits - current->stencilBits) * + (desired->stencilBits - current->stencilBits); + } + + if (desired->accumRedBits != GLFW_DONT_CARE) + { + extraDiff += (desired->accumRedBits - current->accumRedBits) * + (desired->accumRedBits - current->accumRedBits); + } + + if (desired->accumGreenBits != GLFW_DONT_CARE) + { + extraDiff += (desired->accumGreenBits - current->accumGreenBits) * + (desired->accumGreenBits - current->accumGreenBits); + } + + if (desired->accumBlueBits != GLFW_DONT_CARE) + { + extraDiff += (desired->accumBlueBits - current->accumBlueBits) * + (desired->accumBlueBits - current->accumBlueBits); + } + + if (desired->accumAlphaBits != GLFW_DONT_CARE) + { + extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) * + (desired->accumAlphaBits - current->accumAlphaBits); + } + + if (desired->samples != GLFW_DONT_CARE) + { + extraDiff += (desired->samples - current->samples) * + (desired->samples - current->samples); + } + + if (desired->sRGB && !current->sRGB) + extraDiff++; + } + + // Figure out if the current one is better than the best one found so far + // Least number of missing buffers is the most important heuristic, + // then color buffer size match and lastly size match for other buffers + + if (missing < leastMissing) + closest = current; + else if (missing == leastMissing) + { + if ((colorDiff < leastColorDiff) || + (colorDiff == leastColorDiff && extraDiff < leastExtraDiff)) + { + closest = current; + } + } + + if (current == closest) + { + leastMissing = missing; + leastColorDiff = colorDiff; + leastExtraDiff = extraDiff; + } + } + + return closest; +} + +GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) +{ + int i; + _GLFWwindow* window; + const char* version; + const char* prefixes[] = + { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + window = _glfwPlatformGetTls(&_glfw.contextSlot); + + window->context.source = ctxconfig->source; + window->context.client = GLFW_OPENGL_API; + + window->context.GetIntegerv = (PFNGLGETINTEGERVPROC) + window->context.getProcAddress("glGetIntegerv"); + window->context.GetString = (PFNGLGETSTRINGPROC) + window->context.getProcAddress("glGetString"); + if (!window->context.GetIntegerv || !window->context.GetString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); + return GLFW_FALSE; + } + + version = (const char*) window->context.GetString(GL_VERSION); + if (!version) + { + if (ctxconfig->client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OpenGL version string retrieval is broken"); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OpenGL ES version string retrieval is broken"); + } + + return GLFW_FALSE; + } + + for (i = 0; prefixes[i]; i++) + { + const size_t length = strlen(prefixes[i]); + + if (strncmp(version, prefixes[i], length) == 0) + { + version += length; + window->context.client = GLFW_OPENGL_ES_API; + break; + } + } + + if (!sscanf(version, "%d.%d.%d", + &window->context.major, + &window->context.minor, + &window->context.revision)) + { + if (window->context.client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "No version found in OpenGL version string"); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "No version found in OpenGL ES version string"); + } + + return GLFW_FALSE; + } + + if (window->context.major < ctxconfig->major || + (window->context.major == ctxconfig->major && + window->context.minor < ctxconfig->minor)) + { + // The desired OpenGL version is greater than the actual version + // This only happens if the machine lacks {GLX|WGL}_ARB_create_context + // /and/ the user has requested an OpenGL version greater than 1.0 + + // For API consistency, we emulate the behavior of the + // {GLX|WGL}_ARB_create_context extension and fail here + + if (window->context.client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "Requested OpenGL version %i.%i, got version %i.%i", + ctxconfig->major, ctxconfig->minor, + window->context.major, window->context.minor); + } + else + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "Requested OpenGL ES version %i.%i, got version %i.%i", + ctxconfig->major, ctxconfig->minor, + window->context.major, window->context.minor); + } + + return GLFW_FALSE; + } + + if (window->context.major >= 3) + { + // OpenGL 3.0+ uses a different function for extension string retrieval + // We cache it here instead of in glfwExtensionSupported mostly to alert + // users as early as possible that their build may be broken + + window->context.GetStringi = (PFNGLGETSTRINGIPROC) + window->context.getProcAddress("glGetStringi"); + if (!window->context.GetStringi) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Entry point retrieval is broken"); + return GLFW_FALSE; + } + } + + if (window->context.client == GLFW_OPENGL_API) + { + // Read back context flags (OpenGL 3.0 and above) + if (window->context.major >= 3) + { + GLint flags; + window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags); + + if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) + window->context.forward = GLFW_TRUE; + + if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) + window->context.debug = GLFW_TRUE; + else if (glfwExtensionSupported("GL_ARB_debug_output") && + ctxconfig->debug) + { + // HACK: This is a workaround for older drivers (pre KHR_debug) + // not setting the debug bit in the context flags for + // debug contexts + window->context.debug = GLFW_TRUE; + } + + if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR) + window->context.noerror = GLFW_TRUE; + } + + // Read back OpenGL context profile (OpenGL 3.2 and above) + if (window->context.major >= 4 || + (window->context.major == 3 && window->context.minor >= 2)) + { + GLint mask; + window->context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); + + if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) + window->context.profile = GLFW_OPENGL_COMPAT_PROFILE; + else if (mask & GL_CONTEXT_CORE_PROFILE_BIT) + window->context.profile = GLFW_OPENGL_CORE_PROFILE; + else if (glfwExtensionSupported("GL_ARB_compatibility")) + { + // HACK: This is a workaround for the compatibility profile bit + // not being set in the context flags if an OpenGL 3.2+ + // context was created without having requested a specific + // version + window->context.profile = GLFW_OPENGL_COMPAT_PROFILE; + } + } + + // Read back robustness strategy + if (glfwExtensionSupported("GL_ARB_robustness")) + { + // NOTE: We avoid using the context flags for detection, as they are + // only present from 3.0 while the extension applies from 1.1 + + GLint strategy; + window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, + &strategy); + + if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) + window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; + else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) + window->context.robustness = GLFW_NO_RESET_NOTIFICATION; + } + } + else + { + // Read back robustness strategy + if (glfwExtensionSupported("GL_EXT_robustness")) + { + // NOTE: The values of these constants match those of the OpenGL ARB + // one, so we can reuse them here + + GLint strategy; + window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, + &strategy); + + if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) + window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; + else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) + window->context.robustness = GLFW_NO_RESET_NOTIFICATION; + } + } + + if (glfwExtensionSupported("GL_KHR_context_flush_control")) + { + GLint behavior; + window->context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior); + + if (behavior == GL_NONE) + window->context.release = GLFW_RELEASE_BEHAVIOR_NONE; + else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH) + window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH; + } + + // Clearing the front buffer to black to avoid garbage pixels left over from + // previous uses of our bit of VRAM + { + PFNGLCLEARPROC glClear = (PFNGLCLEARPROC) + window->context.getProcAddress("glClear"); + glClear(GL_COLOR_BUFFER_BIT); + window->context.swapBuffers(window); + } + + return GLFW_TRUE; +} + +GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions) +{ + const char* start = extensions; + + for (;;) + { + const char* where; + const char* terminator; + + where = strstr(start, string); + if (!where) + return GLFW_FALSE; + + terminator = where + strlen(string); + if (where == start || *(where - 1) == ' ') + { + if (*terminator == ' ' || *terminator == '\0') + break; + } + + start = terminator; + } + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot); + + _GLFW_REQUIRE_INIT(); + + if (window && window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return; + } + + if (previous) + { + if (!window || window->context.source != previous->context.source) + previous->context.makeCurrent(NULL); + } + + if (window) + window->context.makeCurrent(window); +} + +GLFWAPI GLFWwindow* glfwGetCurrentContext(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfwPlatformGetTls(&_glfw.contextSlot); +} + +GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return; + } + + window->context.swapBuffers(window); +} + +GLFWAPI void glfwSwapInterval(int interval) +{ + _GLFWwindow* window; + + _GLFW_REQUIRE_INIT(); + + window = _glfwPlatformGetTls(&_glfw.contextSlot); + if (!window) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); + return; + } + + window->context.swapInterval(interval); +} + +GLFWAPI int glfwExtensionSupported(const char* extension) +{ + _GLFWwindow* window; + assert(extension != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + window = _glfwPlatformGetTls(&_glfw.contextSlot); + if (!window) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); + return GLFW_FALSE; + } + + if (*extension == '\0') + { + _glfwInputError(GLFW_INVALID_VALUE, "Extension name is empty string"); + return GLFW_FALSE; + } + + if (window->context.major >= 3) + { + int i; + GLint count; + + // Check if extension is in the modern OpenGL extensions string list + + window->context.GetIntegerv(GL_NUM_EXTENSIONS, &count); + + for (i = 0; i < count; i++) + { + const char* en = (const char*) + window->context.GetStringi(GL_EXTENSIONS, i); + if (!en) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Extension string retrieval is broken"); + return GLFW_FALSE; + } + + if (strcmp(en, extension) == 0) + return GLFW_TRUE; + } + } + else + { + // Check if extension is in the old style OpenGL extensions string + + const char* extensions = (const char*) + window->context.GetString(GL_EXTENSIONS); + if (!extensions) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Extension string retrieval is broken"); + return GLFW_FALSE; + } + + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + // Check if extension is in the platform-specific string + return window->context.extensionSupported(extension); +} + +GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) +{ + _GLFWwindow* window; + assert(procname != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + window = _glfwPlatformGetTls(&_glfw.contextSlot); + if (!window) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); + return NULL; + } + + return window->context.getProcAddress(procname); +} + diff --git a/src/external/glfw/src/egl_context.c b/src/external/glfw/src/egl_context.c new file mode 100644 index 00000000..b2d11a47 --- /dev/null +++ b/src/external/glfw/src/egl_context.c @@ -0,0 +1,786 @@ +//======================================================================== +// GLFW 3.3 EGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include + + +// Return a description of the specified EGL error +// +static const char* getEGLErrorString(EGLint error) +{ + switch (error) + { + case EGL_SUCCESS: + return "Success"; + case EGL_NOT_INITIALIZED: + return "EGL is not or could not be initialized"; + case EGL_BAD_ACCESS: + return "EGL cannot access a requested resource"; + case EGL_BAD_ALLOC: + return "EGL failed to allocate resources for the requested operation"; + case EGL_BAD_ATTRIBUTE: + return "An unrecognized attribute or attribute value was passed in the attribute list"; + case EGL_BAD_CONTEXT: + return "An EGLContext argument does not name a valid EGL rendering context"; + case EGL_BAD_CONFIG: + return "An EGLConfig argument does not name a valid EGL frame buffer configuration"; + case EGL_BAD_CURRENT_SURFACE: + return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid"; + case EGL_BAD_DISPLAY: + return "An EGLDisplay argument does not name a valid EGL display connection"; + case EGL_BAD_SURFACE: + return "An EGLSurface argument does not name a valid surface configured for GL rendering"; + case EGL_BAD_MATCH: + return "Arguments are inconsistent"; + case EGL_BAD_PARAMETER: + return "One or more argument values are invalid"; + case EGL_BAD_NATIVE_PIXMAP: + return "A NativePixmapType argument does not refer to a valid native pixmap"; + case EGL_BAD_NATIVE_WINDOW: + return "A NativeWindowType argument does not refer to a valid native window"; + case EGL_CONTEXT_LOST: + return "The application must destroy all contexts and reinitialise"; + default: + return "ERROR: UNKNOWN EGL ERROR"; + } +} + +// Returns the specified attribute of the specified EGLConfig +// +static int getEGLConfigAttrib(EGLConfig config, int attrib) +{ + int value; + eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value); + return value; +} + +// Return the EGLConfig most closely matching the specified hints +// +static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* desired, + EGLConfig* result) +{ + EGLConfig* nativeConfigs; + _GLFWfbconfig* usableConfigs; + const _GLFWfbconfig* closest; + int i, nativeCount, usableCount; + + eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); + if (!nativeCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned"); + return GLFW_FALSE; + } + + nativeConfigs = calloc(nativeCount, sizeof(EGLConfig)); + eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount); + + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableCount = 0; + + for (i = 0; i < nativeCount; i++) + { + const EGLConfig n = nativeConfigs[i]; + _GLFWfbconfig* u = usableConfigs + usableCount; + + // Only consider RGB(A) EGLConfigs + if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER) + continue; + + // Only consider window EGLConfigs + if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT)) + continue; + +#if defined(_GLFW_X11) + XVisualInfo vi = {0}; + + // Only consider EGLConfigs with associated Visuals + vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); + if (!vi.visualid) + continue; + + if (desired->transparent) + { + int count; + XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display, + VisualIDMask, &vi, + &count); + if (vis) + { + u->transparent = _glfwIsVisualTransparentX11(vis[0].visual); + XFree(vis); + } + } +#endif // _GLFW_X11 + + if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + if (ctxconfig->major == 1) + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT)) + continue; + } + else + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT)) + continue; + } + } + else if (ctxconfig->client == GLFW_OPENGL_API) + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT)) + continue; + } + + u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE); + u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE); + u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE); + + u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE); + u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE); + u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE); + + u->samples = getEGLConfigAttrib(n, EGL_SAMPLES); + u->doublebuffer = GLFW_TRUE; + + u->handle = (uintptr_t) n; + usableCount++; + } + + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + if (closest) + *result = (EGLConfig) closest->handle; + + free(nativeConfigs); + free(usableConfigs); + + return closest != NULL; +} + +static void makeContextCurrentEGL(_GLFWwindow* window) +{ + if (window) + { + if (!eglMakeCurrent(_glfw.egl.display, + window->context.egl.surface, + window->context.egl.surface, + window->context.egl.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to make context current: %s", + getEGLErrorString(eglGetError())); + return; + } + } + else + { + if (!eglMakeCurrent(_glfw.egl.display, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + EGL_NO_CONTEXT)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to clear current context: %s", + getEGLErrorString(eglGetError())); + return; + } + } + + _glfwPlatformSetTls(&_glfw.contextSlot, window); +} + +static void swapBuffersEGL(_GLFWwindow* window) +{ + if (window != _glfwPlatformGetTls(&_glfw.contextSlot)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: The context must be current on the calling thread when swapping buffers"); + return; + } + + eglSwapBuffers(_glfw.egl.display, window->context.egl.surface); +} + +static void swapIntervalEGL(int interval) +{ + eglSwapInterval(_glfw.egl.display, interval); +} + +static int extensionSupportedEGL(const char* extension) +{ + const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddressEGL(const char* procname) +{ + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + + if (window->context.egl.client) + { + GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client, + procname); + if (proc) + return proc; + } + + return eglGetProcAddress(procname); +} + +static void destroyContextEGL(_GLFWwindow* window) +{ +#if defined(_GLFW_X11) + // NOTE: Do not unload libGL.so.1 while the X11 display is still open, + // as it will make XCloseDisplay segfault + if (window->context.client != GLFW_OPENGL_API) +#endif // _GLFW_X11 + { + if (window->context.egl.client) + { + _glfw_dlclose(window->context.egl.client); + window->context.egl.client = NULL; + } + } + + if (window->context.egl.surface) + { + eglDestroySurface(_glfw.egl.display, window->context.egl.surface); + window->context.egl.surface = EGL_NO_SURFACE; + } + + if (window->context.egl.handle) + { + eglDestroyContext(_glfw.egl.display, window->context.egl.handle); + window->context.egl.handle = EGL_NO_CONTEXT; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize EGL +// +GLFWbool _glfwInitEGL(void) +{ + int i; + const char* sonames[] = + { +#if defined(_GLFW_EGL_LIBRARY) + _GLFW_EGL_LIBRARY, +#elif defined(_GLFW_WIN32) + "libEGL.dll", + "EGL.dll", +#elif defined(_GLFW_COCOA) + "libEGL.dylib", +#elif defined(__CYGWIN__) + "libEGL-1.so", +#else + "libEGL.so.1", +#endif + NULL + }; + + if (_glfw.egl.handle) + return GLFW_TRUE; + + for (i = 0; sonames[i]; i++) + { + _glfw.egl.handle = _glfw_dlopen(sonames[i]); + if (_glfw.egl.handle) + break; + } + + if (!_glfw.egl.handle) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found"); + return GLFW_FALSE; + } + + _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0); + + _glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib) + _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib"); + _glfw.egl.GetConfigs = (PFN_eglGetConfigs) + _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs"); + _glfw.egl.GetDisplay = (PFN_eglGetDisplay) + _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay"); + _glfw.egl.GetError = (PFN_eglGetError) + _glfw_dlsym(_glfw.egl.handle, "eglGetError"); + _glfw.egl.Initialize = (PFN_eglInitialize) + _glfw_dlsym(_glfw.egl.handle, "eglInitialize"); + _glfw.egl.Terminate = (PFN_eglTerminate) + _glfw_dlsym(_glfw.egl.handle, "eglTerminate"); + _glfw.egl.BindAPI = (PFN_eglBindAPI) + _glfw_dlsym(_glfw.egl.handle, "eglBindAPI"); + _glfw.egl.CreateContext = (PFN_eglCreateContext) + _glfw_dlsym(_glfw.egl.handle, "eglCreateContext"); + _glfw.egl.DestroySurface = (PFN_eglDestroySurface) + _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface"); + _glfw.egl.DestroyContext = (PFN_eglDestroyContext) + _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext"); + _glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface) + _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface"); + _glfw.egl.MakeCurrent = (PFN_eglMakeCurrent) + _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent"); + _glfw.egl.SwapBuffers = (PFN_eglSwapBuffers) + _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers"); + _glfw.egl.SwapInterval = (PFN_eglSwapInterval) + _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval"); + _glfw.egl.QueryString = (PFN_eglQueryString) + _glfw_dlsym(_glfw.egl.handle, "eglQueryString"); + _glfw.egl.GetProcAddress = (PFN_eglGetProcAddress) + _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress"); + + if (!_glfw.egl.GetConfigAttrib || + !_glfw.egl.GetConfigs || + !_glfw.egl.GetDisplay || + !_glfw.egl.GetError || + !_glfw.egl.Initialize || + !_glfw.egl.Terminate || + !_glfw.egl.BindAPI || + !_glfw.egl.CreateContext || + !_glfw.egl.DestroySurface || + !_glfw.egl.DestroyContext || + !_glfw.egl.CreateWindowSurface || + !_glfw.egl.MakeCurrent || + !_glfw.egl.SwapBuffers || + !_glfw.egl.SwapInterval || + !_glfw.egl.QueryString || + !_glfw.egl.GetProcAddress) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to load required entry points"); + + _glfwTerminateEGL(); + return GLFW_FALSE; + } + + _glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY); + if (_glfw.egl.display == EGL_NO_DISPLAY) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to get EGL display: %s", + getEGLErrorString(eglGetError())); + + _glfwTerminateEGL(); + return GLFW_FALSE; + } + + if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to initialize EGL: %s", + getEGLErrorString(eglGetError())); + + _glfwTerminateEGL(); + return GLFW_FALSE; + } + + _glfw.egl.KHR_create_context = + extensionSupportedEGL("EGL_KHR_create_context"); + _glfw.egl.KHR_create_context_no_error = + extensionSupportedEGL("EGL_KHR_create_context_no_error"); + _glfw.egl.KHR_gl_colorspace = + extensionSupportedEGL("EGL_KHR_gl_colorspace"); + _glfw.egl.KHR_get_all_proc_addresses = + extensionSupportedEGL("EGL_KHR_get_all_proc_addresses"); + _glfw.egl.KHR_context_flush_control = + extensionSupportedEGL("EGL_KHR_context_flush_control"); + + return GLFW_TRUE; +} + +// Terminate EGL +// +void _glfwTerminateEGL(void) +{ + if (_glfw.egl.display) + { + eglTerminate(_glfw.egl.display); + _glfw.egl.display = EGL_NO_DISPLAY; + } + + if (_glfw.egl.handle) + { + _glfw_dlclose(_glfw.egl.handle); + _glfw.egl.handle = NULL; + } +} + +#define setAttrib(a, v) \ +{ \ + assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[index++] = a; \ + attribs[index++] = v; \ +} + +// Create the OpenGL or OpenGL ES context +// +GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + EGLint attribs[40]; + EGLConfig config; + EGLContext share = NULL; + int index = 0; + + if (!_glfw.egl.display) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available"); + return GLFW_FALSE; + } + + if (ctxconfig->share) + share = ctxconfig->share->context.egl.handle; + + if (!chooseEGLConfig(ctxconfig, fbconfig, &config)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "EGL: Failed to find a suitable EGLConfig"); + return GLFW_FALSE; + } + + if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + if (!eglBindAPI(EGL_OPENGL_ES_API)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to bind OpenGL ES: %s", + getEGLErrorString(eglGetError())); + return GLFW_FALSE; + } + } + else + { + if (!eglBindAPI(EGL_OPENGL_API)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to bind OpenGL: %s", + getEGLErrorString(eglGetError())); + return GLFW_FALSE; + } + } + + if (_glfw.egl.KHR_create_context) + { + int mask = 0, flags = 0; + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if (ctxconfig->forward) + flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; + + if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) + mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; + else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; + } + + if (ctxconfig->debug) + flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; + + if (ctxconfig->robustness) + { + if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) + { + setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_NO_RESET_NOTIFICATION_KHR); + } + else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) + { + setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_LOSE_CONTEXT_ON_RESET_KHR); + } + + flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; + } + + if (ctxconfig->noerror) + { + if (_glfw.egl.KHR_create_context_no_error) + setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); + } + + if (ctxconfig->major != 1 || ctxconfig->minor != 0) + { + setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); + setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); + } + + if (mask) + setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); + + if (flags) + setAttrib(EGL_CONTEXT_FLAGS_KHR, flags); + } + else + { + if (ctxconfig->client == GLFW_OPENGL_ES_API) + setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); + } + + if (_glfw.egl.KHR_context_flush_control) + { + if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); + } + else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); + } + } + + setAttrib(EGL_NONE, EGL_NONE); + + window->context.egl.handle = eglCreateContext(_glfw.egl.display, + config, share, attribs); + + if (window->context.egl.handle == EGL_NO_CONTEXT) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "EGL: Failed to create context: %s", + getEGLErrorString(eglGetError())); + return GLFW_FALSE; + } + + // Set up attributes for surface creation + { + int index = 0; + + if (fbconfig->sRGB) + { + if (_glfw.egl.KHR_gl_colorspace) + setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); + } + + setAttrib(EGL_NONE, EGL_NONE); + } + + window->context.egl.surface = + eglCreateWindowSurface(_glfw.egl.display, + config, + _GLFW_EGL_NATIVE_WINDOW, + attribs); + if (window->context.egl.surface == EGL_NO_SURFACE) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to create window surface: %s", + getEGLErrorString(eglGetError())); + return GLFW_FALSE; + } + + window->context.egl.config = config; + + // Load the appropriate client library + if (!_glfw.egl.KHR_get_all_proc_addresses) + { + int i; + const char** sonames; + const char* es1sonames[] = + { +#if defined(_GLFW_GLESV1_LIBRARY) + _GLFW_GLESV1_LIBRARY, +#elif defined(_GLFW_WIN32) + "GLESv1_CM.dll", + "libGLES_CM.dll", +#elif defined(_GLFW_COCOA) + "libGLESv1_CM.dylib", +#else + "libGLESv1_CM.so.1", + "libGLES_CM.so.1", +#endif + NULL + }; + const char* es2sonames[] = + { +#if defined(_GLFW_GLESV2_LIBRARY) + _GLFW_GLESV2_LIBRARY, +#elif defined(_GLFW_WIN32) + "GLESv2.dll", + "libGLESv2.dll", +#elif defined(_GLFW_COCOA) + "libGLESv2.dylib", +#elif defined(__CYGWIN__) + "libGLESv2-2.so", +#else + "libGLESv2.so.2", +#endif + NULL + }; + const char* glsonames[] = + { +#if defined(_GLFW_OPENGL_LIBRARY) + _GLFW_OPENGL_LIBRARY, +#elif defined(_GLFW_WIN32) +#elif defined(_GLFW_COCOA) +#else + "libGL.so.1", +#endif + NULL + }; + + if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + if (ctxconfig->major == 1) + sonames = es1sonames; + else + sonames = es2sonames; + } + else + sonames = glsonames; + + for (i = 0; sonames[i]; i++) + { + // HACK: Match presence of lib prefix to increase chance of finding + // a matching pair in the jungle that is Win32 EGL/GLES + if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0)) + continue; + + window->context.egl.client = _glfw_dlopen(sonames[i]); + if (window->context.egl.client) + break; + } + + if (!window->context.egl.client) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to load client library"); + return GLFW_FALSE; + } + } + + window->context.makeCurrent = makeContextCurrentEGL; + window->context.swapBuffers = swapBuffersEGL; + window->context.swapInterval = swapIntervalEGL; + window->context.extensionSupported = extensionSupportedEGL; + window->context.getProcAddress = getProcAddressEGL; + window->context.destroy = destroyContextEGL; + + return GLFW_TRUE; +} + +#undef setAttrib + +// Returns the Visual and depth of the chosen EGLConfig +// +#if defined(_GLFW_X11) +GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig, + Visual** visual, int* depth) +{ + XVisualInfo* result; + XVisualInfo desired; + EGLConfig native; + EGLint visualID = 0, count = 0; + const long vimask = VisualScreenMask | VisualIDMask; + + if (!chooseEGLConfig(ctxconfig, fbconfig, &native)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "EGL: Failed to find a suitable EGLConfig"); + return GLFW_FALSE; + } + + eglGetConfigAttrib(_glfw.egl.display, native, + EGL_NATIVE_VISUAL_ID, &visualID); + + desired.screen = _glfw.x11.screen; + desired.visualid = visualID; + + result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count); + if (!result) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to retrieve Visual for EGLConfig"); + return GLFW_FALSE; + } + + *visual = result->visual; + *depth = result->depth; + + XFree(result); + return GLFW_TRUE; +} +#endif // _GLFW_X11 + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI EGLDisplay glfwGetEGLDisplay(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY); + return _glfw.egl.display; +} + +GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return EGL_NO_CONTEXT; + } + + return window->context.egl.handle; +} + +GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return EGL_NO_SURFACE; + } + + return window->context.egl.surface; +} + diff --git a/src/external/glfw/src/egl_context.h b/src/external/glfw/src/egl_context.h new file mode 100644 index 00000000..aa339baa --- /dev/null +++ b/src/external/glfw/src/egl_context.h @@ -0,0 +1,219 @@ +//======================================================================== +// GLFW 3.3 EGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#if defined(_GLFW_USE_EGLPLATFORM_H) + #include +#elif defined(_GLFW_WIN32) + #define EGLAPIENTRY __stdcall +typedef HDC EGLNativeDisplayType; +typedef HWND EGLNativeWindowType; +#elif defined(_GLFW_COCOA) + #define EGLAPIENTRY +typedef void* EGLNativeDisplayType; +typedef id EGLNativeWindowType; +#elif defined(_GLFW_X11) + #define EGLAPIENTRY +typedef Display* EGLNativeDisplayType; +typedef Window EGLNativeWindowType; +#elif defined(_GLFW_WAYLAND) + #define EGLAPIENTRY +typedef struct wl_display* EGLNativeDisplayType; +typedef struct wl_egl_window* EGLNativeWindowType; +#elif defined(_GLFW_MIR) + #define EGLAPIENTRY +typedef MirEGLNativeDisplayType EGLNativeDisplayType; +typedef MirEGLNativeWindowType EGLNativeWindowType; +#else + #error "No supported EGL platform selected" +#endif + +#define EGL_SUCCESS 0x3000 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300a +#define EGL_BAD_NATIVE_WINDOW 0x300b +#define EGL_BAD_PARAMETER 0x300c +#define EGL_BAD_SURFACE 0x300d +#define EGL_CONTEXT_LOST 0x300e +#define EGL_COLOR_BUFFER_TYPE 0x303f +#define EGL_RGB_BUFFER 0x308e +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_WINDOW_BIT 0x0004 +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENGL_ES2_BIT 0x0004 +#define EGL_OPENGL_BIT 0x0008 +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_RED_SIZE 0x3024 +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_SAMPLES 0x3031 +#define EGL_OPENGL_ES_API 0x30a0 +#define EGL_OPENGL_API 0x30a2 +#define EGL_NONE 0x3038 +#define EGL_EXTENSIONS 0x3055 +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 +#define EGL_NATIVE_VISUAL_ID 0x302e +#define EGL_NO_SURFACE ((EGLSurface) 0) +#define EGL_NO_DISPLAY ((EGLDisplay) 0) +#define EGL_NO_CONTEXT ((EGLContext) 0) +#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0) + +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd +#define EGL_NO_RESET_NOTIFICATION_KHR 0x31be +#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 +#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb +#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd +#define EGL_CONTEXT_FLAGS_KHR 0x30fc +#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3 +#define EGL_GL_COLORSPACE_KHR 0x309d +#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 + +typedef int EGLint; +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef void* EGLConfig; +typedef void* EGLContext; +typedef void* EGLDisplay; +typedef void* EGLSurface; + +// EGL function pointer typedefs +typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*); +typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType); +typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglTerminate)(EGLDisplay); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglBindAPI)(EGLenum); +typedef EGLContext (EGLAPIENTRY * PFN_eglCreateContext)(EGLDisplay,EGLConfig,EGLContext,const EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroySurface)(EGLDisplay,EGLSurface); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroyContext)(EGLDisplay,EGLContext); +typedef EGLSurface (EGLAPIENTRY * PFN_eglCreateWindowSurface)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglMakeCurrent)(EGLDisplay,EGLSurface,EGLSurface,EGLContext); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapBuffers)(EGLDisplay,EGLSurface); +typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint); +typedef const char* (EGLAPIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint); +typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*); +#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib +#define eglGetConfigs _glfw.egl.GetConfigs +#define eglGetDisplay _glfw.egl.GetDisplay +#define eglGetError _glfw.egl.GetError +#define eglInitialize _glfw.egl.Initialize +#define eglTerminate _glfw.egl.Terminate +#define eglBindAPI _glfw.egl.BindAPI +#define eglCreateContext _glfw.egl.CreateContext +#define eglDestroySurface _glfw.egl.DestroySurface +#define eglDestroyContext _glfw.egl.DestroyContext +#define eglCreateWindowSurface _glfw.egl.CreateWindowSurface +#define eglMakeCurrent _glfw.egl.MakeCurrent +#define eglSwapBuffers _glfw.egl.SwapBuffers +#define eglSwapInterval _glfw.egl.SwapInterval +#define eglQueryString _glfw.egl.QueryString +#define eglGetProcAddress _glfw.egl.GetProcAddress + +#define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl +#define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl + + +// EGL-specific per-context data +// +typedef struct _GLFWcontextEGL +{ + EGLConfig config; + EGLContext handle; + EGLSurface surface; + + void* client; + +} _GLFWcontextEGL; + +// EGL-specific global data +// +typedef struct _GLFWlibraryEGL +{ + EGLDisplay display; + EGLint major, minor; + GLFWbool prefix; + + GLFWbool KHR_create_context; + GLFWbool KHR_create_context_no_error; + GLFWbool KHR_gl_colorspace; + GLFWbool KHR_get_all_proc_addresses; + GLFWbool KHR_context_flush_control; + + void* handle; + + PFN_eglGetConfigAttrib GetConfigAttrib; + PFN_eglGetConfigs GetConfigs; + PFN_eglGetDisplay GetDisplay; + PFN_eglGetError GetError; + PFN_eglInitialize Initialize; + PFN_eglTerminate Terminate; + PFN_eglBindAPI BindAPI; + PFN_eglCreateContext CreateContext; + PFN_eglDestroySurface DestroySurface; + PFN_eglDestroyContext DestroyContext; + PFN_eglCreateWindowSurface CreateWindowSurface; + PFN_eglMakeCurrent MakeCurrent; + PFN_eglSwapBuffers SwapBuffers; + PFN_eglSwapInterval SwapInterval; + PFN_eglQueryString QueryString; + PFN_eglGetProcAddress GetProcAddress; + +} _GLFWlibraryEGL; + + +GLFWbool _glfwInitEGL(void); +void _glfwTerminateEGL(void); +GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +#if defined(_GLFW_X11) +GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig, + Visual** visual, int* depth); +#endif /*_GLFW_X11*/ + diff --git a/src/external/glfw/src/glfw3.pc.in b/src/external/glfw/src/glfw3.pc.in new file mode 100644 index 00000000..f2e4d976 --- /dev/null +++ b/src/external/glfw/src/glfw3.pc.in @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +includedir=${prefix}/include +libdir=${exec_prefix}/lib@LIB_SUFFIX@ + +Name: GLFW +Description: A multi-platform library for OpenGL, window and input +Version: @GLFW_VERSION_FULL@ +URL: http://www.glfw.org/ +Requires.private: @GLFW_PKG_DEPS@ +Libs: -L${libdir} -l@GLFW_LIB_NAME@ +Libs.private: @GLFW_PKG_LIBS@ +Cflags: -I${includedir} diff --git a/src/external/glfw/src/glfw3Config.cmake.in b/src/external/glfw/src/glfw3Config.cmake.in new file mode 100644 index 00000000..1fa200e2 --- /dev/null +++ b/src/external/glfw/src/glfw3Config.cmake.in @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/glfw3Targets.cmake") diff --git a/src/external/glfw/src/glfw_config.h.in b/src/external/glfw/src/glfw_config.h.in new file mode 100644 index 00000000..bc9f5d3e --- /dev/null +++ b/src/external/glfw/src/glfw_config.h.in @@ -0,0 +1,57 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// As glfw_config.h.in, this file is used by CMake to produce the +// glfw_config.h configuration header file. If you are adding a feature +// requiring conditional compilation, this is where to add the macro. +//======================================================================== +// As glfw_config.h, this file defines compile-time option macros for a +// specific platform and development environment. If you are using the +// GLFW CMake files, modify glfw_config.h.in instead of this file. If you +// are using your own build system, make this file define the appropriate +// macros in whatever way is suitable. +//======================================================================== + +// Define this to 1 if building GLFW for X11 +#cmakedefine _GLFW_X11 +// Define this to 1 if building GLFW for Win32 +#cmakedefine _GLFW_WIN32 +// Define this to 1 if building GLFW for Cocoa +#cmakedefine _GLFW_COCOA +// Define this to 1 if building GLFW for Wayland +#cmakedefine _GLFW_WAYLAND +// Define this to 1 if building GLFW for Mir +#cmakedefine _GLFW_MIR +// Define this to 1 if building GLFW for OSMesa +#cmakedefine _GLFW_OSMESA + +// Define this to 1 if building as a shared library / dynamic library / DLL +#cmakedefine _GLFW_BUILD_DLL +// Define this to 1 to use Vulkan loader linked statically into application +#cmakedefine _GLFW_VULKAN_STATIC + +// Define this to 1 to force use of high-performance GPU on hybrid systems +#cmakedefine _GLFW_USE_HYBRID_HPG + diff --git a/src/external/glfw/src/glx_context.c b/src/external/glfw/src/glx_context.c new file mode 100644 index 00000000..708663a9 --- /dev/null +++ b/src/external/glfw/src/glx_context.c @@ -0,0 +1,698 @@ +//======================================================================== +// GLFW 3.3 GLX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + +#ifndef GLXBadProfileARB + #define GLXBadProfileARB 13 +#endif + + +// Returns the specified attribute of the specified GLXFBConfig +// +static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib) +{ + int value; + glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value); + return value; +} + +// Return the GLXFBConfig most closely matching the specified hints +// +static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, + GLXFBConfig* result) +{ + GLXFBConfig* nativeConfigs; + _GLFWfbconfig* usableConfigs; + const _GLFWfbconfig* closest; + int i, nativeCount, usableCount; + const char* vendor; + GLFWbool trustWindowBit = GLFW_TRUE; + + // HACK: This is a (hopefully temporary) workaround for Chromium + // (VirtualBox GL) not setting the window bit on any GLXFBConfigs + vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR); + if (vendor && strcmp(vendor, "Chromium") == 0) + trustWindowBit = GLFW_FALSE; + + nativeConfigs = + glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount); + if (!nativeConfigs || !nativeCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned"); + return GLFW_FALSE; + } + + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableCount = 0; + + for (i = 0; i < nativeCount; i++) + { + const GLXFBConfig n = nativeConfigs[i]; + _GLFWfbconfig* u = usableConfigs + usableCount; + + // Only consider RGBA GLXFBConfigs + if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT)) + continue; + + // Only consider window GLXFBConfigs + if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT)) + { + if (trustWindowBit) + continue; + } + + if (desired->transparent) + { + XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n); + if (vi) + { + u->transparent = _glfwIsVisualTransparentX11(vi->visual); + XFree(vi); + } + } + + u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE); + u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE); + u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE); + + u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE); + u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE); + u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE); + + u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE); + u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE); + u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE); + u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE); + + u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS); + + if (getGLXFBConfigAttrib(n, GLX_STEREO)) + u->stereo = GLFW_TRUE; + if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER)) + u->doublebuffer = GLFW_TRUE; + + if (_glfw.glx.ARB_multisample) + u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES); + + if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB) + u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB); + + u->handle = (uintptr_t) n; + usableCount++; + } + + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + if (closest) + *result = (GLXFBConfig) closest->handle; + + XFree(nativeConfigs); + free(usableConfigs); + + return closest != NULL; +} + +// Create the OpenGL context using legacy API +// +static GLXContext createLegacyContextGLX(_GLFWwindow* window, + GLXFBConfig fbconfig, + GLXContext share) +{ + return glXCreateNewContext(_glfw.x11.display, + fbconfig, + GLX_RGBA_TYPE, + share, + True); +} + +static void makeContextCurrentGLX(_GLFWwindow* window) +{ + if (window) + { + if (!glXMakeCurrent(_glfw.x11.display, + window->context.glx.window, + window->context.glx.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to make context current"); + return; + } + } + else + { + if (!glXMakeCurrent(_glfw.x11.display, None, NULL)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to clear current context"); + return; + } + } + + _glfwPlatformSetTls(&_glfw.contextSlot, window); +} + +static void swapBuffersGLX(_GLFWwindow* window) +{ + glXSwapBuffers(_glfw.x11.display, window->context.glx.window); +} + +static void swapIntervalGLX(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + + if (_glfw.glx.EXT_swap_control) + { + _glfw.glx.SwapIntervalEXT(_glfw.x11.display, + window->context.glx.window, + interval); + } + else if (_glfw.glx.MESA_swap_control) + _glfw.glx.SwapIntervalMESA(interval); + else if (_glfw.glx.SGI_swap_control) + { + if (interval > 0) + _glfw.glx.SwapIntervalSGI(interval); + } +} + +static int extensionSupportedGLX(const char* extension) +{ + const char* extensions = + glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddressGLX(const char* procname) +{ + if (_glfw.glx.GetProcAddress) + return _glfw.glx.GetProcAddress((const GLubyte*) procname); + else if (_glfw.glx.GetProcAddressARB) + return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); + else + return dlsym(_glfw.glx.handle, procname); +} + +// Destroy the OpenGL context +// +static void destroyContextGLX(_GLFWwindow* window) +{ + if (window->context.glx.window) + { + glXDestroyWindow(_glfw.x11.display, window->context.glx.window); + window->context.glx.window = None; + } + + if (window->context.glx.handle) + { + glXDestroyContext(_glfw.x11.display, window->context.glx.handle); + window->context.glx.handle = NULL; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize GLX +// +GLFWbool _glfwInitGLX(void) +{ + int i; + const char* sonames[] = + { +#if defined(_GLFW_GLX_LIBRARY) + _GLFW_GLX_LIBRARY, +#elif defined(__CYGWIN__) + "libGL-1.so", +#else + "libGL.so.1", + "libGL.so", +#endif + NULL + }; + + if (_glfw.glx.handle) + return GLFW_TRUE; + + for (i = 0; sonames[i]; i++) + { + _glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.glx.handle) + break; + } + + if (!_glfw.glx.handle) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX"); + return GLFW_FALSE; + } + + _glfw.glx.GetFBConfigs = + dlsym(_glfw.glx.handle, "glXGetFBConfigs"); + _glfw.glx.GetFBConfigAttrib = + dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib"); + _glfw.glx.GetClientString = + dlsym(_glfw.glx.handle, "glXGetClientString"); + _glfw.glx.QueryExtension = + dlsym(_glfw.glx.handle, "glXQueryExtension"); + _glfw.glx.QueryVersion = + dlsym(_glfw.glx.handle, "glXQueryVersion"); + _glfw.glx.DestroyContext = + dlsym(_glfw.glx.handle, "glXDestroyContext"); + _glfw.glx.MakeCurrent = + dlsym(_glfw.glx.handle, "glXMakeCurrent"); + _glfw.glx.SwapBuffers = + dlsym(_glfw.glx.handle, "glXSwapBuffers"); + _glfw.glx.QueryExtensionsString = + dlsym(_glfw.glx.handle, "glXQueryExtensionsString"); + _glfw.glx.CreateNewContext = + dlsym(_glfw.glx.handle, "glXCreateNewContext"); + _glfw.glx.CreateWindow = + dlsym(_glfw.glx.handle, "glXCreateWindow"); + _glfw.glx.DestroyWindow = + dlsym(_glfw.glx.handle, "glXDestroyWindow"); + _glfw.glx.GetProcAddress = + dlsym(_glfw.glx.handle, "glXGetProcAddress"); + _glfw.glx.GetProcAddressARB = + dlsym(_glfw.glx.handle, "glXGetProcAddressARB"); + _glfw.glx.GetVisualFromFBConfig = + dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig"); + + if (!_glfw.glx.GetFBConfigs || + !_glfw.glx.GetFBConfigAttrib || + !_glfw.glx.GetClientString || + !_glfw.glx.QueryExtension || + !_glfw.glx.QueryVersion || + !_glfw.glx.DestroyContext || + !_glfw.glx.MakeCurrent || + !_glfw.glx.SwapBuffers || + !_glfw.glx.QueryExtensionsString || + !_glfw.glx.CreateNewContext || + !_glfw.glx.CreateWindow || + !_glfw.glx.DestroyWindow || + !_glfw.glx.GetProcAddress || + !_glfw.glx.GetProcAddressARB || + !_glfw.glx.GetVisualFromFBConfig) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to load required entry points"); + return GLFW_FALSE; + } + + if (!glXQueryExtension(_glfw.x11.display, + &_glfw.glx.errorBase, + &_glfw.glx.eventBase)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found"); + return GLFW_FALSE; + } + + if (!glXQueryVersion(_glfw.x11.display, &_glfw.glx.major, &_glfw.glx.minor)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: Failed to query GLX version"); + return GLFW_FALSE; + } + + if (_glfw.glx.major == 1 && _glfw.glx.minor < 3) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: GLX version 1.3 is required"); + return GLFW_FALSE; + } + + if (extensionSupportedGLX("GLX_EXT_swap_control")) + { + _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) + getProcAddressGLX("glXSwapIntervalEXT"); + + if (_glfw.glx.SwapIntervalEXT) + _glfw.glx.EXT_swap_control = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_SGI_swap_control")) + { + _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) + getProcAddressGLX("glXSwapIntervalSGI"); + + if (_glfw.glx.SwapIntervalSGI) + _glfw.glx.SGI_swap_control = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_MESA_swap_control")) + { + _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) + getProcAddressGLX("glXSwapIntervalMESA"); + + if (_glfw.glx.SwapIntervalMESA) + _glfw.glx.MESA_swap_control = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_ARB_multisample")) + _glfw.glx.ARB_multisample = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB")) + _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB")) + _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_create_context")) + { + _glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) + getProcAddressGLX("glXCreateContextAttribsARB"); + + if (_glfw.glx.CreateContextAttribsARB) + _glfw.glx.ARB_create_context = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_ARB_create_context_robustness")) + _glfw.glx.ARB_create_context_robustness = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_create_context_profile")) + _glfw.glx.ARB_create_context_profile = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile")) + _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_create_context_no_error")) + _glfw.glx.ARB_create_context_no_error = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_context_flush_control")) + _glfw.glx.ARB_context_flush_control = GLFW_TRUE; + + return GLFW_TRUE; +} + +// Terminate GLX +// +void _glfwTerminateGLX(void) +{ + // NOTE: This function must not call any X11 functions, as it is called + // after XCloseDisplay (see _glfwPlatformTerminate for details) + + if (_glfw.glx.handle) + { + dlclose(_glfw.glx.handle); + _glfw.glx.handle = NULL; + } +} + +#define setAttrib(a, v) \ +{ \ + assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[index++] = a; \ + attribs[index++] = v; \ +} + +// Create the OpenGL or OpenGL ES context +// +GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + int attribs[40]; + GLXFBConfig native = NULL; + GLXContext share = NULL; + + if (ctxconfig->share) + share = ctxconfig->share->context.glx.handle; + + if (!chooseGLXFBConfig(fbconfig, &native)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "GLX: Failed to find a suitable GLXFBConfig"); + return GLFW_FALSE; + } + + if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + if (!_glfw.glx.ARB_create_context || + !_glfw.glx.ARB_create_context_profile || + !_glfw.glx.EXT_create_context_es2_profile) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable"); + return GLFW_FALSE; + } + } + + if (ctxconfig->forward) + { + if (!_glfw.glx.ARB_create_context) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable"); + return GLFW_FALSE; + } + } + + if (ctxconfig->profile) + { + if (!_glfw.glx.ARB_create_context || + !_glfw.glx.ARB_create_context_profile) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable"); + return GLFW_FALSE; + } + } + + _glfwGrabErrorHandlerX11(); + + if (_glfw.glx.ARB_create_context) + { + int index = 0, mask = 0, flags = 0; + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if (ctxconfig->forward) + flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) + mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } + else + mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; + + if (ctxconfig->debug) + flags |= GLX_CONTEXT_DEBUG_BIT_ARB; + + if (ctxconfig->robustness) + { + if (_glfw.glx.ARB_create_context_robustness) + { + if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) + { + setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_NO_RESET_NOTIFICATION_ARB); + } + else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) + { + setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_LOSE_CONTEXT_ON_RESET_ARB); + } + + flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + } + + if (ctxconfig->release) + { + if (_glfw.glx.ARB_context_flush_control) + { + if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + } + else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + } + } + } + + if (ctxconfig->noerror) + { + if (_glfw.glx.ARB_create_context_no_error) + setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + } + + // NOTE: Only request an explicitly versioned context when necessary, as + // explicitly requesting version 1.0 does not always return the + // highest version supported by the driver + if (ctxconfig->major != 1 || ctxconfig->minor != 0) + { + setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + } + + if (mask) + setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); + + if (flags) + setAttrib(GLX_CONTEXT_FLAGS_ARB, flags); + + setAttrib(None, None); + + window->context.glx.handle = + _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, + native, + share, + True, + attribs); + + // HACK: This is a fallback for broken versions of the Mesa + // implementation of GLX_ARB_create_context_profile that fail + // default 1.0 context creation with a GLXBadProfileARB error in + // violation of the extension spec + if (!window->context.glx.handle) + { + if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && + ctxconfig->client == GLFW_OPENGL_API && + ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && + ctxconfig->forward == GLFW_FALSE) + { + window->context.glx.handle = + createLegacyContextGLX(window, native, share); + } + } + } + else + { + window->context.glx.handle = + createLegacyContextGLX(window, native, share); + } + + _glfwReleaseErrorHandlerX11(); + + if (!window->context.glx.handle) + { + _glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context"); + return GLFW_FALSE; + } + + window->context.glx.window = + glXCreateWindow(_glfw.x11.display, native, window->x11.handle, NULL); + if (!window->context.glx.window) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window"); + return GLFW_FALSE; + } + + window->context.makeCurrent = makeContextCurrentGLX; + window->context.swapBuffers = swapBuffersGLX; + window->context.swapInterval = swapIntervalGLX; + window->context.extensionSupported = extensionSupportedGLX; + window->context.getProcAddress = getProcAddressGLX; + window->context.destroy = destroyContextGLX; + + return GLFW_TRUE; +} + +#undef setAttrib + +// Returns the Visual and depth of the chosen GLXFBConfig +// +GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig, + Visual** visual, int* depth) +{ + GLXFBConfig native; + XVisualInfo* result; + + if (!chooseGLXFBConfig(fbconfig, &native)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "GLX: Failed to find a suitable GLXFBConfig"); + return GLFW_FALSE; + } + + result = glXGetVisualFromFBConfig(_glfw.x11.display, native); + if (!result) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to retrieve Visual for GLXFBConfig"); + return GLFW_FALSE; + } + + *visual = result->visual; + *depth = result->depth; + + XFree(result); + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return NULL; + } + + return window->context.glx.handle; +} + +GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return None; + } + + return window->context.glx.window; +} + diff --git a/src/external/glfw/src/glx_context.h b/src/external/glfw/src/glx_context.h new file mode 100644 index 00000000..f767cb14 --- /dev/null +++ b/src/external/glfw/src/glx_context.h @@ -0,0 +1,181 @@ +//======================================================================== +// GLFW 3.3 GLX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define GLX_VENDOR 1 +#define GLX_RGBA_BIT 0x00000001 +#define GLX_WINDOW_BIT 0x00000001 +#define GLX_DRAWABLE_TYPE 0x8010 +#define GLX_RENDER_TYPE 0x8011 +#define GLX_RGBA_TYPE 0x8014 +#define GLX_DOUBLEBUFFER 5 +#define GLX_STEREO 6 +#define GLX_AUX_BUFFERS 7 +#define GLX_RED_SIZE 8 +#define GLX_GREEN_SIZE 9 +#define GLX_BLUE_SIZE 10 +#define GLX_ALPHA_SIZE 11 +#define GLX_DEPTH_SIZE 12 +#define GLX_STENCIL_SIZE 13 +#define GLX_ACCUM_RED_SIZE 14 +#define GLX_ACCUM_GREEN_SIZE 15 +#define GLX_ACCUM_BLUE_SIZE 16 +#define GLX_ACCUM_ALPHA_SIZE 17 +#define GLX_SAMPLES 0x186a1 +#define GLX_VISUAL_ID 0x800b + +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2 +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 + +typedef XID GLXWindow; +typedef XID GLXDrawable; +typedef struct __GLXFBConfig* GLXFBConfig; +typedef struct __GLXcontext* GLXContext; +typedef void (*__GLXextproc)(void); + +typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*); +typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int); +typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*); +typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*); +typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext); +typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext); +typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable); +typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int); +typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*); +typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool); +typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName); +typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int); +typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig); +typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*); +typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow); + +typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int); +typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int); +typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*); + +// libGL.so function pointer typedefs +#define glXGetFBConfigs _glfw.glx.GetFBConfigs +#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib +#define glXGetClientString _glfw.glx.GetClientString +#define glXQueryExtension _glfw.glx.QueryExtension +#define glXQueryVersion _glfw.glx.QueryVersion +#define glXDestroyContext _glfw.glx.DestroyContext +#define glXMakeCurrent _glfw.glx.MakeCurrent +#define glXSwapBuffers _glfw.glx.SwapBuffers +#define glXQueryExtensionsString _glfw.glx.QueryExtensionsString +#define glXCreateNewContext _glfw.glx.CreateNewContext +#define glXGetVisualFromFBConfig _glfw.glx.GetVisualFromFBConfig +#define glXCreateWindow _glfw.glx.CreateWindow +#define glXDestroyWindow _glfw.glx.DestroyWindow + +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx + + +// GLX-specific per-context data +// +typedef struct _GLFWcontextGLX +{ + GLXContext handle; + GLXWindow window; + +} _GLFWcontextGLX; + +// GLX-specific global data +// +typedef struct _GLFWlibraryGLX +{ + int major, minor; + int eventBase; + int errorBase; + + // dlopen handle for libGL.so.1 + void* handle; + + // GLX 1.3 functions + PFNGLXGETFBCONFIGSPROC GetFBConfigs; + PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib; + PFNGLXGETCLIENTSTRINGPROC GetClientString; + PFNGLXQUERYEXTENSIONPROC QueryExtension; + PFNGLXQUERYVERSIONPROC QueryVersion; + PFNGLXDESTROYCONTEXTPROC DestroyContext; + PFNGLXMAKECURRENTPROC MakeCurrent; + PFNGLXSWAPBUFFERSPROC SwapBuffers; + PFNGLXQUERYEXTENSIONSSTRINGPROC QueryExtensionsString; + PFNGLXCREATENEWCONTEXTPROC CreateNewContext; + PFNGLXGETVISUALFROMFBCONFIGPROC GetVisualFromFBConfig; + PFNGLXCREATEWINDOWPROC CreateWindow; + PFNGLXDESTROYWINDOWPROC DestroyWindow; + + // GLX 1.4 and extension functions + PFNGLXGETPROCADDRESSPROC GetProcAddress; + PFNGLXGETPROCADDRESSPROC GetProcAddressARB; + PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI; + PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT; + PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA; + PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLFWbool SGI_swap_control; + GLFWbool EXT_swap_control; + GLFWbool MESA_swap_control; + GLFWbool ARB_multisample; + GLFWbool ARB_framebuffer_sRGB; + GLFWbool EXT_framebuffer_sRGB; + GLFWbool ARB_create_context; + GLFWbool ARB_create_context_profile; + GLFWbool ARB_create_context_robustness; + GLFWbool EXT_create_context_es2_profile; + GLFWbool ARB_create_context_no_error; + GLFWbool ARB_context_flush_control; + +} _GLFWlibraryGLX; + +GLFWbool _glfwInitGLX(void); +void _glfwTerminateGLX(void); +GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContextGLX(_GLFWwindow* window); +GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig, + Visual** visual, int* depth); + diff --git a/src/external/glfw/src/init.c b/src/external/glfw/src/init.c new file mode 100644 index 00000000..19a13e0d --- /dev/null +++ b/src/external/glfw/src/init.c @@ -0,0 +1,317 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" +#include "mappings.h" + +#include +#include +#include +#include +#include + + +// The global variables below comprise all global data in GLFW. +// Any other global variable is a bug. + +// Global state shared between compilation units of GLFW +// +_GLFWlibrary _glfw = { GLFW_FALSE }; + +// These are outside of _glfw so they can be used before initialization and +// after termination +// +static _GLFWerror _glfwMainThreadError; +static GLFWerrorfun _glfwErrorCallback; +static _GLFWinitconfig _glfwInitHints = +{ + GLFW_TRUE, // hat buttons + { + GLFW_TRUE, // macOS menu bar + GLFW_TRUE // macOS bundle chdir + }, + { + "", // X11 WM_CLASS name + "" // X11 WM_CLASS class + } +}; + +// Returns a generic string representation of the specified error +// +static const char* getErrorString(int code) +{ + switch (code) + { + case GLFW_NOT_INITIALIZED: + return "The GLFW library is not initialized"; + case GLFW_NO_CURRENT_CONTEXT: + return "There is no current context"; + case GLFW_INVALID_ENUM: + return "Invalid argument for enum parameter"; + case GLFW_INVALID_VALUE: + return "Invalid value for parameter"; + case GLFW_OUT_OF_MEMORY: + return "Out of memory"; + case GLFW_API_UNAVAILABLE: + return "The requested API is unavailable"; + case GLFW_VERSION_UNAVAILABLE: + return "The requested API version is unavailable"; + case GLFW_PLATFORM_ERROR: + return "An undocumented platform-specific error occurred"; + case GLFW_FORMAT_UNAVAILABLE: + return "The requested format is unavailable"; + case GLFW_NO_WINDOW_CONTEXT: + return "The specified window has no context"; + default: + return "ERROR: UNKNOWN GLFW ERROR"; + } +} + +// Terminate the library +// +static void terminate(void) +{ + int i; + + memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks)); + + while (_glfw.windowListHead) + glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead); + + while (_glfw.cursorListHead) + glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead); + + for (i = 0; i < _glfw.monitorCount; i++) + { + _GLFWmonitor* monitor = _glfw.monitors[i]; + if (monitor->originalRamp.size) + _glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp); + _glfwFreeMonitor(monitor); + } + + free(_glfw.monitors); + _glfw.monitors = NULL; + _glfw.monitorCount = 0; + + free(_glfw.mappings); + _glfw.mappings = NULL; + _glfw.mappingCount = 0; + + _glfwTerminateVulkan(); + _glfwPlatformTerminate(); + + _glfw.initialized = GLFW_FALSE; + + while (_glfw.errorListHead) + { + _GLFWerror* error = _glfw.errorListHead; + _glfw.errorListHead = error->next; + free(error); + } + + _glfwPlatformDestroyTls(&_glfw.contextSlot); + _glfwPlatformDestroyTls(&_glfw.errorSlot); + _glfwPlatformDestroyMutex(&_glfw.errorLock); + + memset(&_glfw, 0, sizeof(_glfw)); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputError(int code, const char* format, ...) +{ + _GLFWerror* error; + char description[_GLFW_MESSAGE_SIZE]; + + if (format) + { + va_list vl; + + va_start(vl, format); + vsnprintf(description, sizeof(description), format, vl); + va_end(vl); + + description[sizeof(description) - 1] = '\0'; + } + else + strcpy(description, getErrorString(code)); + + if (_glfw.initialized) + { + error = _glfwPlatformGetTls(&_glfw.errorSlot); + if (!error) + { + error = calloc(1, sizeof(_GLFWerror)); + _glfwPlatformSetTls(&_glfw.errorSlot, error); + _glfwPlatformLockMutex(&_glfw.errorLock); + error->next = _glfw.errorListHead; + _glfw.errorListHead = error; + _glfwPlatformUnlockMutex(&_glfw.errorLock); + } + } + else + error = &_glfwMainThreadError; + + error->code = code; + strcpy(error->description, description); + + if (_glfwErrorCallback) + _glfwErrorCallback(code, description); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwInit(void) +{ + if (_glfw.initialized) + return GLFW_TRUE; + + memset(&_glfw, 0, sizeof(_glfw)); + _glfw.hints.init = _glfwInitHints; + + if (!_glfwPlatformInit()) + { + terminate(); + return GLFW_FALSE; + } + + if (!_glfwPlatformCreateMutex(&_glfw.errorLock)) + return GLFW_FALSE; + if (!_glfwPlatformCreateTls(&_glfw.errorSlot)) + return GLFW_FALSE; + if (!_glfwPlatformCreateTls(&_glfw.contextSlot)) + return GLFW_FALSE; + + _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); + + _glfw.initialized = GLFW_TRUE; + _glfw.timer.offset = _glfwPlatformGetTimerValue(); + + glfwDefaultWindowHints(); + glfwUpdateGamepadMappings(_glfwDefaultMappings); + + return GLFW_TRUE; +} + +GLFWAPI void glfwTerminate(void) +{ + if (!_glfw.initialized) + return; + + terminate(); +} + +GLFWAPI void glfwInitHint(int hint, int value) +{ + switch (hint) + { + case GLFW_JOYSTICK_HAT_BUTTONS: + _glfwInitHints.hatButtons = value; + return; + case GLFW_COCOA_CHDIR_RESOURCES: + _glfwInitHints.ns.chdir = value; + return; + case GLFW_COCOA_MENUBAR: + _glfwInitHints.ns.menubar = value; + return; + } + + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid integer type init hint 0x%08X", hint); +} + +GLFWAPI void glfwInitHintString(int hint, const char* value) +{ + assert(value != NULL); + + switch (hint) + { + case GLFW_X11_WM_CLASS_NAME: + strncpy(_glfwInitHints.x11.className, value, + sizeof(_glfwInitHints.x11.className) - 1); + break; + case GLFW_X11_WM_CLASS_CLASS: + strncpy(_glfwInitHints.x11.classClass, value, + sizeof(_glfwInitHints.x11.classClass) - 1); + break; + } + + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid string type init hint 0x%08X", hint); +} + +GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) +{ + if (major != NULL) + *major = GLFW_VERSION_MAJOR; + if (minor != NULL) + *minor = GLFW_VERSION_MINOR; + if (rev != NULL) + *rev = GLFW_VERSION_REVISION; +} + +GLFWAPI const char* glfwGetVersionString(void) +{ + return _glfwPlatformGetVersionString(); +} + +GLFWAPI int glfwGetError(const char** description) +{ + _GLFWerror* error; + int code = GLFW_NO_ERROR; + + if (description) + *description = NULL; + + if (_glfw.initialized) + error = _glfwPlatformGetTls(&_glfw.errorSlot); + else + error = &_glfwMainThreadError; + + if (error) + { + code = error->code; + error->code = GLFW_NO_ERROR; + if (description && code) + *description = error->description; + } + + return code; +} + +GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) +{ + _GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun); + return cbfun; +} + diff --git a/src/external/glfw/src/input.c b/src/external/glfw/src/input.c new file mode 100644 index 00000000..7d9ff774 --- /dev/null +++ b/src/external/glfw/src/input.c @@ -0,0 +1,1151 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +// Internal key state used for sticky keys +#define _GLFW_STICK 3 + +// Internal constants for gamepad mapping source types +#define _GLFW_JOYSTICK_AXIS 1 +#define _GLFW_JOYSTICK_BUTTON 2 +#define _GLFW_JOYSTICK_HATBIT 3 + +// Finds a mapping based on joystick GUID +// +static _GLFWmapping* findMapping(const char* guid) +{ + int i; + + for (i = 0; i < _glfw.mappingCount; i++) + { + if (strcmp(_glfw.mappings[i].guid, guid) == 0) + return _glfw.mappings + i; + } + + return NULL; +} + +// Parses an SDL_GameControllerDB line and adds it to the mapping list +// +static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) +{ + const char* c = string; + size_t i, length; + struct + { + const char* name; + _GLFWmapelement* element; + } fields[] = + { + { "platform", NULL }, + { "a", mapping->buttons + GLFW_GAMEPAD_BUTTON_A }, + { "b", mapping->buttons + GLFW_GAMEPAD_BUTTON_B }, + { "x", mapping->buttons + GLFW_GAMEPAD_BUTTON_X }, + { "y", mapping->buttons + GLFW_GAMEPAD_BUTTON_Y }, + { "back", mapping->buttons + GLFW_GAMEPAD_BUTTON_BACK }, + { "start", mapping->buttons + GLFW_GAMEPAD_BUTTON_START }, + { "guide", mapping->buttons + GLFW_GAMEPAD_BUTTON_GUIDE }, + { "leftshoulder", mapping->buttons + GLFW_GAMEPAD_BUTTON_LEFT_BUMPER }, + { "rightshoulder", mapping->buttons + GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER }, + { "leftstick", mapping->buttons + GLFW_GAMEPAD_BUTTON_LEFT_THUMB }, + { "rightstick", mapping->buttons + GLFW_GAMEPAD_BUTTON_RIGHT_THUMB }, + { "dpup", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_UP }, + { "dpright", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_RIGHT }, + { "dpdown", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_DOWN }, + { "dpleft", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_LEFT }, + { "lefttrigger", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_TRIGGER }, + { "righttrigger", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER }, + { "leftx", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_X }, + { "lefty", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_Y }, + { "rightx", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_X }, + { "righty", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_Y } + }; + + length = strcspn(c, ","); + if (length != 32 || c[length] != ',') + { + _glfwInputError(GLFW_INVALID_VALUE, NULL); + return GLFW_FALSE; + } + + memcpy(mapping->guid, c, length); + c += length + 1; + + length = strcspn(c, ","); + if (length >= sizeof(mapping->name) || c[length] != ',') + { + _glfwInputError(GLFW_INVALID_VALUE, NULL); + return GLFW_FALSE; + } + + memcpy(mapping->name, c, length); + c += length + 1; + + while (*c) + { + for (i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) + { + length = strlen(fields[i].name); + if (strncmp(c, fields[i].name, length) != 0 || c[length] != ':') + continue; + + c += length + 1; + + if (fields[i].element) + { + if (*c == 'a') + fields[i].element->type = _GLFW_JOYSTICK_AXIS; + else if (*c == 'b') + fields[i].element->type = _GLFW_JOYSTICK_BUTTON; + else if (*c == 'h') + fields[i].element->type = _GLFW_JOYSTICK_HATBIT; + else + break; + + if (fields[i].element->type == _GLFW_JOYSTICK_HATBIT) + { + const unsigned int hat = strtoul(c + 1, (char**) &c, 10); + const unsigned int bit = strtoul(c + 1, (char**) &c, 10); + fields[i].element->value = (hat << 4) | bit; + } + else + fields[i].element->value = (uint8_t) strtoul(c + 1, (char**) &c, 10); + } + else + { + length = strlen(_GLFW_PLATFORM_MAPPING_NAME); + if (strncmp(c, _GLFW_PLATFORM_MAPPING_NAME, length) != 0) + return GLFW_FALSE; + } + + break; + } + + c += strcspn(c, ","); + c += strspn(c, ","); + } + + for (i = 0; i < 32; i++) + { + if (mapping->guid[i] >= 'A' && mapping->guid[i] <= 'F') + mapping->guid[i] += 'a' - 'A'; + } + + _glfwPlatformUpdateGamepadGUID(mapping->guid); + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key >= 0 && key <= GLFW_KEY_LAST) + { + GLFWbool repeated = GLFW_FALSE; + + if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE) + return; + + if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS) + repeated = GLFW_TRUE; + + if (action == GLFW_RELEASE && window->stickyKeys) + window->keys[key] = _GLFW_STICK; + else + window->keys[key] = (char) action; + + if (repeated) + action = GLFW_REPEAT; + } + + if (window->callbacks.key) + window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods); +} + +void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain) +{ + if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) + return; + + if (window->callbacks.charmods) + window->callbacks.charmods((GLFWwindow*) window, codepoint, mods); + + if (plain) + { + if (window->callbacks.character) + window->callbacks.character((GLFWwindow*) window, codepoint); + } +} + +void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) +{ + if (window->callbacks.scroll) + window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset); +} + +void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) +{ + if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) + return; + + if (action == GLFW_RELEASE && window->stickyMouseButtons) + window->mouseButtons[button] = _GLFW_STICK; + else + window->mouseButtons[button] = (char) action; + + if (window->callbacks.mouseButton) + window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods); +} + +void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos) +{ + if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos) + return; + + window->virtualCursorPosX = xpos; + window->virtualCursorPosY = ypos; + + if (window->callbacks.cursorPos) + window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos); +} + +void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered) +{ + if (window->callbacks.cursorEnter) + window->callbacks.cursorEnter((GLFWwindow*) window, entered); +} + +void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) +{ + if (window->callbacks.drop) + window->callbacks.drop((GLFWwindow*) window, count, paths); +} + +void _glfwInputJoystick(_GLFWjoystick* js, int event) +{ + const int jid = (int) (js - _glfw.joysticks); + + if (_glfw.callbacks.joystick) + _glfw.callbacks.joystick(jid, event); +} + +void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) +{ + js->axes[axis] = value; +} + +void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value) +{ + js->buttons[button] = value; +} + +void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) +{ + const int base = js->buttonCount + hat * 4; + + js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE; + js->buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE; + js->buttons[base + 2] = (value & 0x04) ? GLFW_PRESS : GLFW_RELEASE; + js->buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE; + + js->hats[hat] = value; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWjoystick* _glfwAllocJoystick(const char* name, + const char* guid, + int axisCount, + int buttonCount, + int hatCount) +{ + int jid; + _GLFWjoystick* js; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (!_glfw.joysticks[jid].present) + break; + } + + if (jid > GLFW_JOYSTICK_LAST) + return NULL; + + js = _glfw.joysticks + jid; + js->present = GLFW_TRUE; + js->name = strdup(name); + js->axes = calloc(axisCount, sizeof(float)); + js->buttons = calloc(buttonCount + hatCount * 4, 1); + js->hats = calloc(hatCount, 1); + js->axisCount = axisCount; + js->buttonCount = buttonCount; + js->hatCount = hatCount; + js->mapping = findMapping(guid); + + strcpy(js->guid, guid); + + return js; +} + +void _glfwFreeJoystick(_GLFWjoystick* js) +{ + free(js->name); + free(js->axes); + free(js->buttons); + free(js->hats); + memset(js, 0, sizeof(_GLFWjoystick)); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(0); + + switch (mode) + { + case GLFW_CURSOR: + return window->cursorMode; + case GLFW_STICKY_KEYS: + return window->stickyKeys; + case GLFW_STICKY_MOUSE_BUTTONS: + return window->stickyMouseButtons; + } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); + return 0; +} + +GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (mode == GLFW_CURSOR) + { + if (value != GLFW_CURSOR_NORMAL && + value != GLFW_CURSOR_HIDDEN && + value != GLFW_CURSOR_DISABLED) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid cursor mode 0x%08X", + value); + return; + } + + if (window->cursorMode == value) + return; + + window->cursorMode = value; + + _glfwPlatformGetCursorPos(window, + &window->virtualCursorPosX, + &window->virtualCursorPosY); + + if (_glfwPlatformWindowFocused(window)) + _glfwPlatformSetCursorMode(window, value); + } + else if (mode == GLFW_STICKY_KEYS) + { + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window->stickyKeys == value) + return; + + if (!value) + { + int i; + + // Release all sticky keys + for (i = 0; i <= GLFW_KEY_LAST; i++) + { + if (window->keys[i] == _GLFW_STICK) + window->keys[i] = GLFW_RELEASE; + } + } + + window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE; + } + else if (mode == GLFW_STICKY_MOUSE_BUTTONS) + { + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window->stickyMouseButtons == value) + return; + + if (!value) + { + int i; + + // Release all sticky mouse buttons + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window->mouseButtons[i] == _GLFW_STICK) + window->mouseButtons[i] = GLFW_RELEASE; + } + } + + window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE; + } + else + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); +} + +GLFWAPI const char* glfwGetKeyName(int key, int scancode) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (key != GLFW_KEY_UNKNOWN) + { + if (key != GLFW_KEY_KP_EQUAL && + (key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) && + (key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2)) + { + return NULL; + } + + scancode = _glfwPlatformGetKeyScancode(key); + } + + return _glfwPlatformGetScancodeName(scancode); +} + +GLFWAPI int glfwGetKeyScancode(int key) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(-1); + + if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); + return GLFW_RELEASE; + } + + return _glfwPlatformGetKeyScancode(key); +} + +GLFWAPI int glfwGetKey(GLFWwindow* handle, int key) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); + + if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); + return GLFW_RELEASE; + } + + if (window->keys[key] == _GLFW_STICK) + { + // Sticky mode: release key now + window->keys[key] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return (int) window->keys[key]; +} + +GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); + + if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button); + return GLFW_RELEASE; + } + + if (window->mouseButtons[button] == _GLFW_STICK) + { + // Sticky mode: release mouse button now + window->mouseButtons[button] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return (int) window->mouseButtons[button]; +} + +GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + + _GLFW_REQUIRE_INIT(); + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (xpos) + *xpos = window->virtualCursorPosX; + if (ypos) + *ypos = window->virtualCursorPosY; + } + else + _glfwPlatformGetCursorPos(window, xpos, ypos); +} + +GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (xpos != xpos || xpos < -DBL_MAX || xpos > DBL_MAX || + ypos != ypos || ypos < -DBL_MAX || ypos > DBL_MAX) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid cursor position %f %f", + xpos, ypos); + return; + } + + if (!_glfwPlatformWindowFocused(window)) + return; + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + // Only update the accumulated position if the cursor is disabled + window->virtualCursorPosX = xpos; + window->virtualCursorPosY = ypos; + } + else + { + // Update system cursor position + _glfwPlatformSetCursorPos(window, xpos, ypos); + } +} + +GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) +{ + _GLFWcursor* cursor; + + assert(image != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + cursor = calloc(1, sizeof(_GLFWcursor)); + cursor->next = _glfw.cursorListHead; + _glfw.cursorListHead = cursor; + + if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot)) + { + glfwDestroyCursor((GLFWcursor*) cursor); + return NULL; + } + + return (GLFWcursor*) cursor; +} + +GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) +{ + _GLFWcursor* cursor; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (shape != GLFW_ARROW_CURSOR && + shape != GLFW_IBEAM_CURSOR && + shape != GLFW_CROSSHAIR_CURSOR && + shape != GLFW_HAND_CURSOR && + shape != GLFW_HRESIZE_CURSOR && + shape != GLFW_VRESIZE_CURSOR) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape); + return NULL; + } + + cursor = calloc(1, sizeof(_GLFWcursor)); + cursor->next = _glfw.cursorListHead; + _glfw.cursorListHead = cursor; + + if (!_glfwPlatformCreateStandardCursor(cursor, shape)) + { + glfwDestroyCursor((GLFWcursor*) cursor); + return NULL; + } + + return (GLFWcursor*) cursor; +} + +GLFWAPI void glfwDestroyCursor(GLFWcursor* handle) +{ + _GLFWcursor* cursor = (_GLFWcursor*) handle; + + _GLFW_REQUIRE_INIT(); + + if (cursor == NULL) + return; + + // Make sure the cursor is not being used by any window + { + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) + { + if (window->cursor == cursor) + glfwSetCursor((GLFWwindow*) window, NULL); + } + } + + _glfwPlatformDestroyCursor(cursor); + + // Unlink cursor from global linked list + { + _GLFWcursor** prev = &_glfw.cursorListHead; + + while (*prev != cursor) + prev = &((*prev)->next); + + *prev = cursor->next; + } + + free(cursor); +} + +GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) +{ + _GLFWwindow* window = (_GLFWwindow*) windowHandle; + _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + window->cursor = cursor; + + _glfwPlatformSetCursor(window, cursor); +} + +GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun); + return cbfun; +} + +GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun); + return cbfun; +} + +GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun); + return cbfun; +} + +GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, + GLFWmousebuttonfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun); + return cbfun; +} + +GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle, + GLFWcursorposfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun); + return cbfun; +} + +GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle, + GLFWcursorenterfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun); + return cbfun; +} + +GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, + GLFWscrollfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun); + return cbfun; +} + +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun); + return cbfun; +} + +GLFWAPI int glfwJoystickPresent(int jid) +{ + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return GLFW_FALSE; + } + + js = _glfw.joysticks + jid; + if (!js->present) + return GLFW_FALSE; + + return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); +} + +GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) +{ + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + assert(count != NULL); + + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return NULL; + } + + js = _glfw.joysticks + jid; + if (!js->present) + return NULL; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES)) + return NULL; + + *count = js->axisCount; + return js->axes; +} + +GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count) +{ + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + assert(count != NULL); + + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return NULL; + } + + js = _glfw.joysticks + jid; + if (!js->present) + return NULL; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) + return NULL; + + if (_glfw.hints.init.hatButtons) + *count = js->buttonCount + js->hatCount * 4; + else + *count = js->buttonCount; + + return js->buttons; +} + +GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count) +{ + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + assert(count != NULL); + + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return NULL; + } + + js = _glfw.joysticks + jid; + if (!js->present) + return NULL; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) + return NULL; + + *count = js->hatCount; + return js->hats; +} + +GLFWAPI const char* glfwGetJoystickName(int jid) +{ + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return NULL; + } + + js = _glfw.joysticks + jid; + if (!js->present) + return NULL; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + return NULL; + + return js->name; +} + +GLFWAPI const char* glfwGetJoystickGUID(int jid) +{ + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return NULL; + } + + js = _glfw.joysticks + jid; + if (!js->present) + return NULL; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + return NULL; + + return js->guid; +} + +GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun); + return cbfun; +} + +GLFWAPI int glfwUpdateGamepadMappings(const char* string) +{ + int jid; + const char* c = string; + + assert(string != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + while (*c) + { + if (isxdigit(*c)) + { + char line[1024]; + + const size_t length = strcspn(c, "\r\n"); + if (length < sizeof(line)) + { + _GLFWmapping mapping = {{0}}; + + memcpy(line, c, length); + line[length] = '\0'; + + if (parseMapping(&mapping, line)) + { + _GLFWmapping* previous = findMapping(mapping.guid); + if (previous) + *previous = mapping; + else + { + _glfw.mappingCount++; + _glfw.mappings = + realloc(_glfw.mappings, + sizeof(_GLFWmapping) * _glfw.mappingCount); + _glfw.mappings[_glfw.mappingCount - 1] = mapping; + } + } + } + + c += length; + } + else + { + c += strcspn(c, "\r\n"); + c += strspn(c, "\r\n"); + } + } + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + _GLFWjoystick* js = _glfw.joysticks + jid; + if (js->present) + js->mapping = findMapping(js->guid); + } + + return GLFW_TRUE; +} + +GLFWAPI int glfwJoystickIsGamepad(int jid) +{ + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return GLFW_FALSE; + } + + js = _glfw.joysticks + jid; + if (!js->present) + return GLFW_FALSE; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + return GLFW_FALSE; + + return js->mapping != NULL; +} + +GLFWAPI const char* glfwGetGamepadName(int jid) +{ + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return NULL; + } + + js = _glfw.joysticks + jid; + if (!js->present) + return NULL; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + return NULL; + + if (!js->mapping) + return NULL; + + return js->mapping->name; +} + +GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) +{ + int i; + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + assert(state != NULL); + + memset(state, 0, sizeof(GLFWgamepadstate)); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return GLFW_FALSE; + } + + js = _glfw.joysticks + jid; + if (!js->present) + return GLFW_FALSE; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL)) + return GLFW_FALSE; + + if (!js->mapping) + return GLFW_FALSE; + + for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) + { + if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_AXIS) + { + if (fabs(js->axes[js->mapping->buttons[i].value]) > 0.5) + state->buttons[i] = GLFW_PRESS; + } + else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT) + { + const unsigned int hat = js->mapping->buttons[i].value >> 4; + const unsigned int bit = js->mapping->buttons[i].value & 0xf; + if (js->hats[hat] & bit) + state->buttons[i] = GLFW_PRESS; + } + else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_BUTTON) + state->buttons[i] = js->buttons[js->mapping->buttons[i].value]; + } + + for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) + { + if (js->mapping->axes[i].type == _GLFW_JOYSTICK_AXIS) + state->axes[i] = js->axes[js->mapping->axes[i].value]; + else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT) + { + const unsigned int hat = js->mapping->buttons[i].value >> 4; + const unsigned int bit = js->mapping->buttons[i].value & 0xf; + if (js->hats[hat] & bit) + state->axes[i] = 1.f; + } + else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_BUTTON) + state->axes[i] = (float) js->buttons[js->mapping->axes[i].value]; + } + + return GLFW_TRUE; +} + +GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(string != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetClipboardString(window, string); +} + +GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfwPlatformGetClipboardString(window); +} + +GLFWAPI double glfwGetTime(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0.0); + return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) / + _glfwPlatformGetTimerFrequency(); +} + +GLFWAPI void glfwSetTime(double time) +{ + _GLFW_REQUIRE_INIT(); + + if (time != time || time < 0.0 || time > 18446744073.0) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time); + return; + } + + _glfw.timer.offset = _glfwPlatformGetTimerValue() - + (uint64_t) (time * _glfwPlatformGetTimerFrequency()); +} + +GLFWAPI uint64_t glfwGetTimerValue(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return _glfwPlatformGetTimerValue(); +} + +GLFWAPI uint64_t glfwGetTimerFrequency(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return _glfwPlatformGetTimerFrequency(); +} + diff --git a/src/external/glfw/src/internal.h b/src/external/glfw/src/internal.h new file mode 100644 index 00000000..485d9434 --- /dev/null +++ b/src/external/glfw/src/internal.h @@ -0,0 +1,1016 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#pragma once + +#if defined(_GLFW_USE_CONFIG_H) + #include "glfw_config.h" +#endif + +#if defined(GLFW_INCLUDE_GLCOREARB) || \ + defined(GLFW_INCLUDE_ES1) || \ + defined(GLFW_INCLUDE_ES2) || \ + defined(GLFW_INCLUDE_ES3) || \ + defined(GLFW_INCLUDE_ES31) || \ + defined(GLFW_INCLUDE_ES32) || \ + defined(GLFW_INCLUDE_NONE) || \ + defined(GLFW_INCLUDE_GLEXT) || \ + defined(GLFW_INCLUDE_GLU) || \ + defined(GLFW_INCLUDE_VULKAN) || \ + defined(GLFW_DLL) + #error "You must not define any header option macros when compiling GLFW" +#endif + +#define GLFW_INCLUDE_NONE +#include "../include/GLFW/glfw3.h" + +#define _GLFW_INSERT_FIRST 0 +#define _GLFW_INSERT_LAST 1 + +#define _GLFW_POLL_PRESENCE 0 +#define _GLFW_POLL_AXES 1 +#define _GLFW_POLL_BUTTONS 2 +#define _GLFW_POLL_ALL (_GLFW_POLL_AXES | _GLFW_POLL_BUTTONS) + +#define _GLFW_MESSAGE_SIZE 1024 + +typedef int GLFWbool; + +typedef struct _GLFWerror _GLFWerror; +typedef struct _GLFWinitconfig _GLFWinitconfig; +typedef struct _GLFWwndconfig _GLFWwndconfig; +typedef struct _GLFWctxconfig _GLFWctxconfig; +typedef struct _GLFWfbconfig _GLFWfbconfig; +typedef struct _GLFWcontext _GLFWcontext; +typedef struct _GLFWwindow _GLFWwindow; +typedef struct _GLFWlibrary _GLFWlibrary; +typedef struct _GLFWmonitor _GLFWmonitor; +typedef struct _GLFWcursor _GLFWcursor; +typedef struct _GLFWmapelement _GLFWmapelement; +typedef struct _GLFWmapping _GLFWmapping; +typedef struct _GLFWjoystick _GLFWjoystick; +typedef struct _GLFWtls _GLFWtls; +typedef struct _GLFWmutex _GLFWmutex; + +typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*); +typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*); +typedef void (* _GLFWswapintervalfun)(int); +typedef int (* _GLFWextensionsupportedfun)(const char*); +typedef GLFWglproc (* _GLFWgetprocaddressfun)(const char*); +typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*); + +#define GL_VERSION 0x1f02 +#define GL_NONE 0 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_EXTENSIONS 0x1f03 +#define GL_NUM_EXTENSIONS 0x821d +#define GL_CONTEXT_FLAGS 0x821e +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82fb +#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82fc +#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 + +typedef int GLint; +typedef unsigned int GLuint; +typedef unsigned int GLenum; +typedef unsigned int GLbitfield; +typedef unsigned char GLubyte; + +typedef void (APIENTRY * PFNGLCLEARPROC)(GLbitfield); +typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC)(GLenum); +typedef void (APIENTRY * PFNGLGETINTEGERVPROC)(GLenum,GLint*); +typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint); + +#define VK_NULL_HANDLE 0 + +typedef void* VkInstance; +typedef void* VkPhysicalDevice; +typedef uint64_t VkSurfaceKHR; +typedef uint32_t VkFlags; +typedef uint32_t VkBool32; + +typedef enum VkStructureType +{ + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, + VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, + VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, + VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, + VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000053000, + VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkStructureType; + +typedef enum VkResult +{ + VK_SUCCESS = 0, + VK_NOT_READY = 1, + VK_TIMEOUT = 2, + VK_EVENT_SET = 3, + VK_EVENT_RESET = 4, + VK_INCOMPLETE = 5, + VK_ERROR_OUT_OF_HOST_MEMORY = -1, + VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, + VK_ERROR_INITIALIZATION_FAILED = -3, + VK_ERROR_DEVICE_LOST = -4, + VK_ERROR_MEMORY_MAP_FAILED = -5, + VK_ERROR_LAYER_NOT_PRESENT = -6, + VK_ERROR_EXTENSION_NOT_PRESENT = -7, + VK_ERROR_FEATURE_NOT_PRESENT = -8, + VK_ERROR_INCOMPATIBLE_DRIVER = -9, + VK_ERROR_TOO_MANY_OBJECTS = -10, + VK_ERROR_FORMAT_NOT_SUPPORTED = -11, + VK_ERROR_SURFACE_LOST_KHR = -1000000000, + VK_SUBOPTIMAL_KHR = 1000001003, + VK_ERROR_OUT_OF_DATE_KHR = -1000001004, + VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, + VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, + VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, + VK_RESULT_MAX_ENUM = 0x7FFFFFFF +} VkResult; + +typedef struct VkAllocationCallbacks VkAllocationCallbacks; + +typedef struct VkExtensionProperties +{ + char extensionName[256]; + uint32_t specVersion; +} VkExtensionProperties; + +typedef void (APIENTRY * PFN_vkVoidFunction)(void); + +#if defined(_GLFW_VULKAN_STATIC) + PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance,const char*); + VkResult vkEnumerateInstanceExtensionProperties(const char*,uint32_t*,VkExtensionProperties*); +#else + typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*); + typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*); + #define vkEnumerateInstanceExtensionProperties _glfw.vk.EnumerateInstanceExtensionProperties + #define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr +#endif + +#if defined(_GLFW_COCOA) + #include "cocoa_platform.h" +#elif defined(_GLFW_WIN32) + #include "win32_platform.h" +#elif defined(_GLFW_X11) + #include "x11_platform.h" +#elif defined(_GLFW_WAYLAND) + #include "wl_platform.h" +#elif defined(_GLFW_MIR) + #include "mir_platform.h" +#elif defined(_GLFW_OSMESA) + #include "null_platform.h" +#else + #error "No supported window creation API selected" +#endif + + +//======================================================================== +// Doxygen group definitions +//======================================================================== + +/*! @defgroup platform Platform interface + * @brief The interface implemented by the platform-specific code. + * + * The platform API is the interface exposed by the platform-specific code for + * each platform and is called by the shared code of the public API It mirrors + * the public API except it uses objects instead of handles. + */ +/*! @defgroup event Event interface + * @brief The interface used by the platform-specific code to report events. + * + * The event API is used by the platform-specific code to notify the shared + * code of events that can be translated into state changes and/or callback + * calls. + */ +/*! @defgroup utility Utility functions + * @brief Various utility functions for internal use. + * + * These functions are shared code and may be used by any part of GLFW + * Each platform may add its own utility functions, but those must only be + * called by the platform-specific code + */ + + +//======================================================================== +// Helper macros +//======================================================================== + +// Constructs a version number string from the public header macros +#define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r +#define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r) +#define _GLFW_VERSION_NUMBER _GLFW_MAKE_VERSION(GLFW_VERSION_MAJOR, \ + GLFW_VERSION_MINOR, \ + GLFW_VERSION_REVISION) + +// Checks for whether the library has been initialized +#define _GLFW_REQUIRE_INIT() \ + if (!_glfw.initialized) \ + { \ + _glfwInputError(GLFW_NOT_INITIALIZED, NULL); \ + return; \ + } +#define _GLFW_REQUIRE_INIT_OR_RETURN(x) \ + if (!_glfw.initialized) \ + { \ + _glfwInputError(GLFW_NOT_INITIALIZED, NULL); \ + return x; \ + } + +// Swaps the provided pointers +#define _GLFW_SWAP_POINTERS(x, y) \ + { \ + void* t; \ + t = x; \ + x = y; \ + y = t; \ + } + + +//======================================================================== +// Platform-independent structures +//======================================================================== + +struct _GLFWerror +{ + _GLFWerror* next; + int code; + char description[_GLFW_MESSAGE_SIZE]; +}; + +/*! @brief Initialization configuration. + * + * Parameters relating to the initialization of the library. + */ +struct _GLFWinitconfig +{ + GLFWbool hatButtons; + struct { + GLFWbool menubar; + GLFWbool chdir; + } ns; + struct { + char className[256]; + char classClass[256]; + } x11; +}; + +/*! @brief Window configuration. + * + * Parameters relating to the creation of the window but not directly related + * to the framebuffer. This is used to pass window creation parameters from + * shared code to the platform API. + */ +struct _GLFWwndconfig +{ + int width; + int height; + const char* title; + GLFWbool resizable; + GLFWbool visible; + GLFWbool decorated; + GLFWbool focused; + GLFWbool autoIconify; + GLFWbool floating; + GLFWbool maximized; + GLFWbool centerCursor; + struct { + GLFWbool retina; + GLFWbool frame; + } ns; +}; + +/*! @brief Context configuration. + * + * Parameters relating to the creation of the context but not directly related + * to the framebuffer. This is used to pass context creation parameters from + * shared code to the platform API. + */ +struct _GLFWctxconfig +{ + int client; + int source; + int major; + int minor; + GLFWbool forward; + GLFWbool debug; + GLFWbool noerror; + int profile; + int robustness; + int release; + _GLFWwindow* share; + struct { + GLFWbool offline; + } nsgl; +}; + +/*! @brief Framebuffer configuration. + * + * This describes buffers and their sizes. It also contains + * a platform-specific ID used to map back to the backend API object. + * + * It is used to pass framebuffer parameters from shared code to the platform + * API and also to enumerate and select available framebuffer configs. + */ +struct _GLFWfbconfig +{ + int redBits; + int greenBits; + int blueBits; + int alphaBits; + int depthBits; + int stencilBits; + int accumRedBits; + int accumGreenBits; + int accumBlueBits; + int accumAlphaBits; + int auxBuffers; + GLFWbool stereo; + int samples; + GLFWbool sRGB; + GLFWbool doublebuffer; + GLFWbool transparent; + uintptr_t handle; +}; + +/*! @brief Context structure. + */ +struct _GLFWcontext +{ + int client; + int source; + int major, minor, revision; + GLFWbool forward, debug, noerror; + int profile; + int robustness; + int release; + + PFNGLGETSTRINGIPROC GetStringi; + PFNGLGETINTEGERVPROC GetIntegerv; + PFNGLGETSTRINGPROC GetString; + + _GLFWmakecontextcurrentfun makeCurrent; + _GLFWswapbuffersfun swapBuffers; + _GLFWswapintervalfun swapInterval; + _GLFWextensionsupportedfun extensionSupported; + _GLFWgetprocaddressfun getProcAddress; + _GLFWdestroycontextfun destroy; + + // This is defined in the context API's context.h + _GLFW_PLATFORM_CONTEXT_STATE; + // This is defined in egl_context.h + _GLFW_EGL_CONTEXT_STATE; + // This is defined in osmesa_context.h + _GLFW_OSMESA_CONTEXT_STATE; +}; + +/*! @brief Window and context structure. + */ +struct _GLFWwindow +{ + struct _GLFWwindow* next; + + // Window settings and state + GLFWbool resizable; + GLFWbool decorated; + GLFWbool autoIconify; + GLFWbool floating; + GLFWbool shouldClose; + void* userPointer; + GLFWvidmode videoMode; + _GLFWmonitor* monitor; + _GLFWcursor* cursor; + + int minwidth, minheight; + int maxwidth, maxheight; + int numer, denom; + + GLFWbool stickyKeys; + GLFWbool stickyMouseButtons; + int cursorMode; + char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1]; + char keys[GLFW_KEY_LAST + 1]; + // Virtual cursor position when cursor is disabled + double virtualCursorPosX, virtualCursorPosY; + + _GLFWcontext context; + + struct { + GLFWwindowposfun pos; + GLFWwindowsizefun size; + GLFWwindowclosefun close; + GLFWwindowrefreshfun refresh; + GLFWwindowfocusfun focus; + GLFWwindowiconifyfun iconify; + GLFWwindowmaximizefun maximize; + GLFWframebuffersizefun fbsize; + GLFWmousebuttonfun mouseButton; + GLFWcursorposfun cursorPos; + GLFWcursorenterfun cursorEnter; + GLFWscrollfun scroll; + GLFWkeyfun key; + GLFWcharfun character; + GLFWcharmodsfun charmods; + GLFWdropfun drop; + } callbacks; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_WINDOW_STATE; +}; + +/*! @brief Monitor structure. + */ +struct _GLFWmonitor +{ + char* name; + + // Physical dimensions in millimeters. + int widthMM, heightMM; + + // The window whose video mode is current on this monitor + _GLFWwindow* window; + + GLFWvidmode* modes; + int modeCount; + GLFWvidmode currentMode; + + GLFWgammaramp originalRamp; + GLFWgammaramp currentRamp; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_MONITOR_STATE; +}; + +/*! @brief Cursor structure + */ +struct _GLFWcursor +{ + _GLFWcursor* next; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_CURSOR_STATE; +}; + +/*! @brief Gamepad mapping element structure + */ +struct _GLFWmapelement +{ + uint8_t type; + uint8_t value; +}; + +/*! @brief Gamepad mapping structure + */ +struct _GLFWmapping +{ + char name[128]; + char guid[33]; + _GLFWmapelement buttons[15]; + _GLFWmapelement axes[6]; +}; + +/*! @brief Joystick structure + */ +struct _GLFWjoystick +{ + GLFWbool present; + float* axes; + int axisCount; + unsigned char* buttons; + int buttonCount; + unsigned char* hats; + int hatCount; + char* name; + char guid[33]; + _GLFWmapping* mapping; + + // This is defined in the joystick API's joystick.h + _GLFW_PLATFORM_JOYSTICK_STATE; +}; + +/*! @brief Thread local storage structure. + */ +struct _GLFWtls +{ + // This is defined in the platform's thread.h + _GLFW_PLATFORM_TLS_STATE; +}; + +/*! @brief Mutex structure. + */ +struct _GLFWmutex +{ + // This is defined in the platform's thread.h + _GLFW_PLATFORM_MUTEX_STATE; +}; + +/*! @brief Library global data. + */ +struct _GLFWlibrary +{ + GLFWbool initialized; + + struct { + _GLFWinitconfig init; + _GLFWfbconfig framebuffer; + _GLFWwndconfig window; + _GLFWctxconfig context; + int refreshRate; + } hints; + + _GLFWerror* errorListHead; + _GLFWcursor* cursorListHead; + _GLFWwindow* windowListHead; + + _GLFWmonitor** monitors; + int monitorCount; + + _GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1]; + _GLFWmapping* mappings; + int mappingCount; + + _GLFWtls errorSlot; + _GLFWtls contextSlot; + _GLFWmutex errorLock; + + struct { + uint64_t offset; + // This is defined in the platform's time.h + _GLFW_PLATFORM_LIBRARY_TIMER_STATE; + } timer; + + struct { + GLFWbool available; + void* handle; + char* extensions[2]; +#if !defined(_GLFW_VULKAN_STATIC) + PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; + PFN_vkGetInstanceProcAddr GetInstanceProcAddr; +#endif + GLFWbool KHR_surface; +#if defined(_GLFW_WIN32) + GLFWbool KHR_win32_surface; +#elif defined(_GLFW_COCOA) + GLFWbool MVK_macos_surface; +#elif defined(_GLFW_X11) + GLFWbool KHR_xlib_surface; + GLFWbool KHR_xcb_surface; +#elif defined(_GLFW_WAYLAND) + GLFWbool KHR_wayland_surface; +#elif defined(_GLFW_MIR) + GLFWbool KHR_mir_surface; +#endif + } vk; + + struct { + GLFWmonitorfun monitor; + GLFWjoystickfun joystick; + } callbacks; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_LIBRARY_WINDOW_STATE; + // This is defined in the context API's context.h + _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE; + // This is defined in the platform's joystick.h + _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE; + // This is defined in egl_context.h + _GLFW_EGL_LIBRARY_CONTEXT_STATE; + // This is defined in osmesa_context.h + _GLFW_OSMESA_LIBRARY_CONTEXT_STATE; +}; + + +//======================================================================== +// Global state shared between compilation units of GLFW +//======================================================================== + +/*! @brief All global data shared between compilation units. + */ +extern _GLFWlibrary _glfw; + + +//======================================================================== +// Platform API functions +//======================================================================== + +/*! @addtogroup platform @{ */ + +int _glfwPlatformInit(void); +void _glfwPlatformTerminate(void); +const char* _glfwPlatformGetVersionString(void); + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos); +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos); +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode); +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape); +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor); +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor); + +const char* _glfwPlatformGetScancodeName(int scancode); +int _glfwPlatformGetKeyScancode(int key); + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos); +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale); +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count); +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string); +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window); + +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode); +void _glfwPlatformUpdateGamepadGUID(char* guid); + +uint64_t _glfwPlatformGetTimerValue(void); +uint64_t _glfwPlatformGetTimerFrequency(void); + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwPlatformDestroyWindow(_GLFWwindow* window); +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title); +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images); +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos); +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos); +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height); +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height); +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom); +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height); +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale); +void _glfwPlatformIconifyWindow(_GLFWwindow* window); +void _glfwPlatformRestoreWindow(_GLFWwindow* window); +void _glfwPlatformMaximizeWindow(_GLFWwindow* window); +void _glfwPlatformShowWindow(_GLFWwindow* window); +void _glfwPlatformHideWindow(_GLFWwindow* window); +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window); +void _glfwPlatformFocusWindow(_GLFWwindow* window); +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); +int _glfwPlatformWindowFocused(_GLFWwindow* window); +int _glfwPlatformWindowIconified(_GLFWwindow* window); +int _glfwPlatformWindowVisible(_GLFWwindow* window); +int _glfwPlatformWindowMaximized(_GLFWwindow* window); +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window); +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled); + +void _glfwPlatformPollEvents(void); +void _glfwPlatformWaitEvents(void); +void _glfwPlatformWaitEventsTimeout(double timeout); +void _glfwPlatformPostEmptyEvent(void); + +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions); +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); + +GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls); +void _glfwPlatformDestroyTls(_GLFWtls* tls); +void* _glfwPlatformGetTls(_GLFWtls* tls); +void _glfwPlatformSetTls(_GLFWtls* tls, void* value); + +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex); +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex); +void _glfwPlatformLockMutex(_GLFWmutex* mutex); +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex); + +/*! @} */ + + +//======================================================================== +// Event API functions +//======================================================================== + +/*! @brief Notifies shared code that a window has lost or received input focus. + * @param[in] window The window that received the event. + * @param[in] focused `GLFW_TRUE` if the window received focus, or `GLFW_FALSE` + * if it lost focus. + * @ingroup event + */ +void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused); + +/*! @brief Notifies shared code that a window has moved. + * @param[in] window The window that received the event. + * @param[in] xpos The new x-coordinate of the client area of the window. + * @param[in] ypos The new y-coordinate of the client area of the window. + * @ingroup event + */ +void _glfwInputWindowPos(_GLFWwindow* window, int xpos, int ypos); + +/*! @brief Notifies shared code that a window has been resized. + * @param[in] window The window that received the event. + * @param[in] width The new width of the client area of the window. + * @param[in] height The new height of the client area of the window. + * @ingroup event + */ +void _glfwInputWindowSize(_GLFWwindow* window, int width, int height); + +/*! @brief Notifies shared code that a window framebuffer has been resized. + * @param[in] window The window that received the event. + * @param[in] width The new width, in pixels, of the framebuffer. + * @param[in] height The new height, in pixels, of the framebuffer. + * @ingroup event + */ +void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height); + +/*! @brief Notifies shared code that a window has been iconified or restored. + * @param[in] window The window that received the event. + * @param[in] iconified `GLFW_TRUE` if the window was iconified, or + * `GLFW_FALSE` if it was restored. + * @ingroup event + */ +void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified); + +/*! @brief Notifies shared code that a window has been maximized or restored. + * @param[in] window The window that received the event. + * @param[in] maximized `GLFW_TRUE` if the window was maximized, or + * `GLFW_FALSE` if it was restored. + * @ingroup event + */ +void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized); + +/*! @brief Notifies shared code that a window's contents needs updating. + * @param[in] window The window that received the event. + */ +void _glfwInputWindowDamage(_GLFWwindow* window); + +/*! @brief Notifies shared code that the user wishes to close a window. + * @param[in] window The window that received the event. + * @ingroup event + */ +void _glfwInputWindowCloseRequest(_GLFWwindow* window); + +/*! @brief Notifies shared code that a window has changed its desired monitor. + * @param[in] window The window that received the event. + * @param[in] monitor The new desired monitor, or `NULL`. + * @ingroup event + */ +void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor); + +/*! @brief Notifies shared code of a physical key event. + * @param[in] window The window that received the event. + * @param[in] key The key that was pressed or released. + * @param[in] scancode The system-specific scan code of the key. + * @param[in] action @ref GLFW_PRESS or @ref GLFW_RELEASE. + * @param[in] mods The modifiers pressed when the event was generated. + * @ingroup event + */ +void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods); + +/*! @brief Notifies shared code of a Unicode character input event. + * @param[in] window The window that received the event. + * @param[in] codepoint The Unicode code point of the input character. + * @param[in] mods Bit field describing which modifier keys were held down. + * @param[in] plain `GLFW_TRUE` if the character is regular text input, or + * `GLFW_FALSE` otherwise. + * @ingroup event + */ +void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain); + +/*! @brief Notifies shared code of a scroll event. + * @param[in] window The window that received the event. + * @param[in] xoffset The scroll offset along the x-axis. + * @param[in] yoffset The scroll offset along the y-axis. + * @ingroup event + */ +void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset); + +/*! @brief Notifies shared code of a mouse button click event. + * @param[in] window The window that received the event. + * @param[in] button The button that was pressed or released. + * @param[in] action @ref GLFW_PRESS or @ref GLFW_RELEASE. + * @param[in] mods The modifiers pressed when the event was generated. + * @ingroup event + */ +void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); + +/*! @brief Notifies shared code of a cursor motion event. + * @param[in] window The window that received the event. + * @param[in] xpos The new x-coordinate of the cursor, relative to the left + * edge of the client area of the window. + * @param[in] ypos The new y-coordinate of the cursor, relative to the top edge + * of the client area of the window. + * @ingroup event + */ +void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); + +/*! @brief Notifies shared code of a cursor enter/leave event. + * @param[in] window The window that received the event. + * @param[in] entered `GLFW_TRUE` if the cursor entered the client area of the + * window, or `GLFW_FALSE` if it left it. + * @ingroup event + */ +void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered); + +/*! @brief Notifies shared code of a monitor connection or disconnection. + * @param[in] monitor The monitor that was connected or disconnected. + * @param[in] action One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * @param[in] placement `_GLFW_INSERT_FIRST` or `_GLFW_INSERT_LAST`. + * @ingroup event + */ +void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement); + +/*! @brief Notifies shared code that a full screen window has acquired or + * released a monitor. + * @param[in] monitor The monitor that was acquired or released. + * @param[in] window The window that acquired the monitor, or `NULL`. + * @ingroup event + */ +void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window); + +/*! @brief Notifies shared code of an error. + * @param[in] code The error code most suitable for the error. + * @param[in] format The `printf` style format string of the error + * description. + * @ingroup event + */ +#if defined(__GNUC__) +void _glfwInputError(int code, const char* format, ...) __attribute__((format(printf, 2, 3))); +#else +void _glfwInputError(int code, const char* format, ...); +#endif + +/*! @brief Notifies shared code of files or directories dropped on a window. + * @param[in] window The window that received the event. + * @param[in] count The number of dropped objects. + * @param[in] names The names of the dropped objects. + * @ingroup event + */ +void _glfwInputDrop(_GLFWwindow* window, int count, const char** names); + +/*! @brief Notifies shared code of a joystick connection or disconnection. + * @param[in] js The joystick that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * @ingroup event + */ +void _glfwInputJoystick(_GLFWjoystick* js, int event); + +/*! @brief Notifies shared code of the new value of a joystick axis. + * @param[in] js The joystick whose axis to update. + * @param[in] axis The index of the axis to update. + * @param[in] value The new value of the axis. + */ +void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value); + +/*! @brief Notifies shared code of the new value of a joystick button. + * @param[in] js The joystick whose button to update. + * @param[in] button The index of the button to update. + * @param[in] value The new value of the button. + */ +void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value); + +/*! @brief Notifies shared code of the new value of a joystick hat. + * @param[in] js The joystick whose hat to update. + * @param[in] button The index of the hat to update. + * @param[in] value The new value of the hat. + */ +void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value); + + +//======================================================================== +// Utility functions +//======================================================================== + +/*! @brief Chooses the video mode most closely matching the desired one. + * @ingroup utility + */ +const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor, + const GLFWvidmode* desired); + +/*! @brief Performs lexical comparison between two @ref GLFWvidmode structures. + * @ingroup utility + */ +int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second); + +/*! @brief Splits a color depth into red, green and blue bit depths. + * @ingroup utility + */ +void _glfwSplitBPP(int bpp, int* red, int* green, int* blue); + +/*! @brief Searches an extension string for the specified extension. + * @param[in] string The extension string to search. + * @param[in] extensions The extension to search for. + * @return `GLFW_TRUE` if the extension was found, or `GLFW_FALSE` otherwise. + * @ingroup utility + */ +GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions); + +/*! @brief Chooses the framebuffer config that best matches the desired one. + * @param[in] desired The desired framebuffer config. + * @param[in] alternatives The framebuffer configs supported by the system. + * @param[in] count The number of entries in the alternatives array. + * @return The framebuffer config most closely matching the desired one, or @c + * NULL if none fulfilled the hard constraints of the desired values. + * @ingroup utility + */ +const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, + const _GLFWfbconfig* alternatives, + unsigned int count); + +/*! @brief Retrieves the attributes of the current context. + * @param[in] ctxconfig The desired context attributes. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if the context is + * unusable. + * @ingroup utility + */ +GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig); + +/*! @brief Checks whether the desired context attributes are valid. + * @param[in] ctxconfig The context attributes to check. + * @return `GLFW_TRUE` if the context attributes are valid, or `GLFW_FALSE` + * otherwise. + * @ingroup utility + * + * This function checks things like whether the specified client API version + * exists and whether all relevant options have supported and non-conflicting + * values. + */ +GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig); + +/*! @brief Allocates red, green and blue value arrays of the specified size. + * @ingroup utility + */ +void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size); + +/*! @brief Frees the red, green and blue value arrays and clears the struct. + * @ingroup utility + */ +void _glfwFreeGammaArrays(GLFWgammaramp* ramp); + +/*! @brief Allocates and returns a monitor object with the specified name + * and dimensions. + * @param[in] name The name of the monitor. + * @param[in] widthMM The width, in mm, of the monitor's display area. + * @param[in] heightMM The height, in mm, of the monitor's display area. + * @return The newly created object. + * @ingroup utility + */ +_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM); + +/*! @brief Frees a monitor object and any data associated with it. + * @ingroup utility + */ +void _glfwFreeMonitor(_GLFWmonitor* monitor); + +/*! @brief Returns an available joystick object with arrays and name allocated. + * @ingroup utility + */ +_GLFWjoystick* _glfwAllocJoystick(const char* name, + const char* guid, + int axisCount, + int buttonCount, + int hatCount); + +/*! @brief Frees arrays and name and flags the joystick object as unused. + * @ingroup utility + */ +void _glfwFreeJoystick(_GLFWjoystick* js); + +/*! @ingroup utility + */ +GLFWbool _glfwInitVulkan(int mode); + +/*! @ingroup utility + */ +void _glfwTerminateVulkan(void); + +/*! @ingroup utility + */ +const char* _glfwGetVulkanResultString(VkResult result); + diff --git a/src/external/glfw/src/linux_joystick.c b/src/external/glfw/src/linux_joystick.c new file mode 100644 index 00000000..d73961fb --- /dev/null +++ b/src/external/glfw/src/linux_joystick.c @@ -0,0 +1,429 @@ +//======================================================================== +// GLFW 3.3 Linux - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Apply an EV_KEY event to the specified joystick +// +static void handleKeyEvent(_GLFWjoystick* js, int code, int value) +{ + _glfwInputJoystickButton(js, + js->linjs.keyMap[code - BTN_MISC], + value ? GLFW_PRESS : GLFW_RELEASE); +} + +// Apply an EV_ABS event to the specified joystick +// +static void handleAbsEvent(_GLFWjoystick* js, int code, int value) +{ + const int index = js->linjs.absMap[code]; + + if (code >= ABS_HAT0X && code <= ABS_HAT3Y) + { + static const char stateMap[3][3] = + { + { GLFW_HAT_CENTERED, GLFW_HAT_UP, GLFW_HAT_DOWN }, + { GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_LEFT_DOWN }, + { GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN }, + }; + + const int hat = (code - ABS_HAT0X) / 2; + const int axis = (code - ABS_HAT0X) % 2; + int* state = js->linjs.hats[hat]; + + // NOTE: Looking at several input drivers, it seems all hat events use + // -1 for left / up, 0 for centered and 1 for right / down + if (value == 0) + state[axis] = 0; + else if (value < 0) + state[axis] = 1; + else if (value > 0) + state[axis] = 2; + + _glfwInputJoystickHat(js, index, stateMap[state[0]][state[1]]); + } + else + { + const struct input_absinfo* info = &js->linjs.absInfo[code]; + float normalized = value; + + const int range = info->maximum - info->minimum; + if (range) + { + // Normalize to 0.0 -> 1.0 + normalized = (normalized - info->minimum) / range; + // Normalize to -1.0 -> 1.0 + normalized = normalized * 2.0f - 1.0f; + } + + _glfwInputJoystickAxis(js, index, normalized); + } +} + +// Poll state of absolute axes +// +static void pollAbsState(_GLFWjoystick* js) +{ + int code; + + for (code = 0; code < ABS_CNT; code++) + { + if (js->linjs.absMap[code] < 0) + continue; + + struct input_absinfo* info = &js->linjs.absInfo[code]; + + if (ioctl(js->linjs.fd, EVIOCGABS(code), info) < 0) + continue; + + handleAbsEvent(js, code, info->value); + } +} + +#define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8))) + +// Attempt to open the specified joystick device +// +static GLFWbool openJoystickDevice(const char* path) +{ + int jid, code; + char name[256] = ""; + char guid[33] = ""; + char evBits[(EV_CNT + 7) / 8] = {0}; + char keyBits[(KEY_CNT + 7) / 8] = {0}; + char absBits[(ABS_CNT + 7) / 8] = {0}; + int axisCount = 0, buttonCount = 0, hatCount = 0; + struct input_id id; + _GLFWjoystickLinux linjs = {0}; + _GLFWjoystick* js = NULL; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (!_glfw.joysticks[jid].present) + continue; + if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) + return GLFW_FALSE; + } + + linjs.fd = open(path, O_RDONLY | O_NONBLOCK); + if (linjs.fd == -1) + return GLFW_FALSE; + + if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 || + ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 || + ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 || + ioctl(linjs.fd, EVIOCGID, &id) < 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to query input device: %s", + strerror(errno)); + close(linjs.fd); + return GLFW_FALSE; + } + + // Ensure this device supports the events expected of a joystick + if (!isBitSet(EV_KEY, evBits) || !isBitSet(EV_ABS, evBits)) + { + close(linjs.fd); + return GLFW_FALSE; + } + + if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0) + strncpy(name, "Unknown", sizeof(name)); + + // Generate a joystick GUID that matches the SDL 2.0.5+ one + if (id.vendor && id.product && id.version) + { + sprintf(guid, "%02x%02x0000%02x%02x0000%02x%02x0000%02x%02x0000", + id.bustype & 0xff, id.bustype >> 8, + id.vendor & 0xff, id.vendor >> 8, + id.product & 0xff, id.product >> 8, + id.version & 0xff, id.version >> 8); + } + else + { + sprintf(guid, "%02x%02x0000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00", + id.bustype & 0xff, id.bustype >> 8, + name[0], name[1], name[2], name[3], + name[4], name[5], name[6], name[7], + name[8], name[9], name[10]); + } + + for (code = BTN_MISC; code < KEY_CNT; code++) + { + if (!isBitSet(code, keyBits)) + continue; + + linjs.keyMap[code - BTN_MISC] = buttonCount; + buttonCount++; + } + + for (code = 0; code < ABS_CNT; code++) + { + linjs.absMap[code] = -1; + if (!isBitSet(code, absBits)) + continue; + + if (code >= ABS_HAT0X && code <= ABS_HAT3Y) + { + linjs.absMap[code] = hatCount; + hatCount++; + // Skip the Y axis + code++; + } + else + { + if (ioctl(linjs.fd, EVIOCGABS(code), &linjs.absInfo[code]) < 0) + continue; + + linjs.absMap[code] = axisCount; + axisCount++; + } + } + + js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount); + if (!js) + { + close(linjs.fd); + return GLFW_FALSE; + } + + strncpy(linjs.path, path, sizeof(linjs.path)); + memcpy(&js->linjs, &linjs, sizeof(linjs)); + + pollAbsState(js); + + _glfwInputJoystick(js, GLFW_CONNECTED); + return GLFW_TRUE; +} + +#undef isBitSet + +// Frees all resources associated with the specified joystick +// +static void closeJoystick(_GLFWjoystick* js) +{ + close(js->linjs.fd); + _glfwFreeJoystick(js); + _glfwInputJoystick(js, GLFW_DISCONNECTED); +} + +// Lexically compare joysticks by name; used by qsort +// +static int compareJoysticks(const void* fp, const void* sp) +{ + const _GLFWjoystick* fj = fp; + const _GLFWjoystick* sj = sp; + return strcmp(fj->linjs.path, sj->linjs.path); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +GLFWbool _glfwInitJoysticksLinux(void) +{ + DIR* dir; + int count = 0; + const char* dirname = "/dev/input"; + + _glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (_glfw.linjs.inotify > 0) + { + // HACK: Register for IN_ATTRIB to get notified when udev is done + // This works well in practice but the true way is libudev + + _glfw.linjs.watch = inotify_add_watch(_glfw.linjs.inotify, + dirname, + IN_CREATE | IN_ATTRIB | IN_DELETE); + } + + // Continue without device connection notifications if inotify fails + + if (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex"); + return GLFW_FALSE; + } + + dir = opendir(dirname); + if (dir) + { + struct dirent* entry; + + while ((entry = readdir(dir))) + { + regmatch_t match; + + if (regexec(&_glfw.linjs.regex, entry->d_name, 1, &match, 0) != 0) + continue; + + char path[PATH_MAX]; + + snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name); + + if (openJoystickDevice(path)) + count++; + } + + closedir(dir); + } + + // Continue with no joysticks if enumeration fails + + qsort(_glfw.joysticks, count, sizeof(_GLFWjoystick), compareJoysticks); + return GLFW_TRUE; +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticksLinux(void) +{ + int jid; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + _GLFWjoystick* js = _glfw.joysticks + jid; + if (js->present) + closeJoystick(js); + } + + regfree(&_glfw.linjs.regex); + + if (_glfw.linjs.inotify > 0) + { + if (_glfw.linjs.watch > 0) + inotify_rm_watch(_glfw.linjs.inotify, _glfw.linjs.watch); + + close(_glfw.linjs.inotify); + } +} + +void _glfwDetectJoystickConnectionLinux(void) +{ + ssize_t offset = 0; + char buffer[16384]; + + if (_glfw.linjs.inotify <= 0) + return; + + const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer)); + + while (size > offset) + { + regmatch_t match; + const struct inotify_event* e = (struct inotify_event*) (buffer + offset); + + offset += sizeof(struct inotify_event) + e->len; + + if (regexec(&_glfw.linjs.regex, e->name, 1, &match, 0) != 0) + continue; + + char path[PATH_MAX]; + snprintf(path, sizeof(path), "/dev/input/%s", e->name); + + if (e->mask & (IN_CREATE | IN_ATTRIB)) + openJoystickDevice(path); + else if (e->mask & IN_DELETE) + { + int jid; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) + { + closeJoystick(_glfw.joysticks + jid); + break; + } + } + } + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) +{ + // Read all queued events (non-blocking) + for (;;) + { + struct input_event e; + + errno = 0; + if (read(js->linjs.fd, &e, sizeof(e)) < 0) + { + // Reset the joystick slot if the device was disconnected + if (errno == ENODEV) + closeJoystick(js); + + break; + } + + if (e.type == EV_SYN) + { + if (e.code == SYN_DROPPED) + _glfw.linjs.dropped = GLFW_TRUE; + else if (e.code == SYN_REPORT) + { + _glfw.linjs.dropped = GLFW_FALSE; + pollAbsState(js); + } + } + + if (_glfw.linjs.dropped) + continue; + + if (e.type == EV_KEY) + handleKeyEvent(js, e.code, e.value); + else if (e.type == EV_ABS) + handleAbsEvent(js, e.code, e.value); + } + + return js->present; +} + +void _glfwPlatformUpdateGamepadGUID(char* guid) +{ +} + diff --git a/src/external/glfw/src/linux_joystick.h b/src/external/glfw/src/linux_joystick.h new file mode 100644 index 00000000..2eabfa13 --- /dev/null +++ b/src/external/glfw/src/linux_joystick.h @@ -0,0 +1,62 @@ +//======================================================================== +// GLFW 3.3 Linux - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include +#include +#include + +#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs + +#define _GLFW_PLATFORM_MAPPING_NAME "Linux" + +// Linux-specific joystick data +// +typedef struct _GLFWjoystickLinux +{ + int fd; + char path[PATH_MAX]; + int keyMap[KEY_CNT - BTN_MISC]; + int absMap[ABS_CNT]; + struct input_absinfo absInfo[ABS_CNT]; + int hats[4][2]; +} _GLFWjoystickLinux; + +// Linux-specific joystick API data +// +typedef struct _GLFWlibraryLinux +{ + int inotify; + int watch; + regex_t regex; + GLFWbool dropped; +} _GLFWlibraryLinux; + + +GLFWbool _glfwInitJoysticksLinux(void); +void _glfwTerminateJoysticksLinux(void); +void _glfwDetectJoystickConnectionLinux(void); + diff --git a/src/external/glfw/src/mappings.h b/src/external/glfw/src/mappings.h new file mode 100644 index 00000000..6c1b800d --- /dev/null +++ b/src/external/glfw/src/mappings.h @@ -0,0 +1,241 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// As mappings.h.in, this file is used by CMake to produce the mappings.h +// header file. If you are adding a GLFW specific gamepad mapping, this is +// where to put it. +//======================================================================== +// As mappings.h, this provides all pre-defined gamepad mappings, including +// all available in SDL_GameControllerDB. Do not edit this file. Any gamepad +// mappings not specific to GLFW should be submitted to SDL_GameControllerDB. +// This file can be re-generated from mappings.h.in and the upstream +// gamecontrollerdb.txt with the GenerateMappings.cmake script. +//======================================================================== + +// All gamepad mappings not labeled GLFW are copied from the +// SDL_GameControllerDB project under the following license: +// +// Simple DirectMedia Layer +// Copyright (C) 1997-2013 Sam Lantinga +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the +// use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +const char* _glfwDefaultMappings = +"8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" +"ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,\n" +"6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" +"0d0f6e00000000000000504944564944,HORIPAD 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" +"88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,\n" +"4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,\n" +"25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,\n" +"4c05c405000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" +"4c05cc09000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" +"4c05a00b000000000000504944564944,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" +"6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13,\n" +"4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" +"00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,\n" +"00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,\n" +"28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" +"ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,\n" +"8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5,\n" +"79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" +"4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows,\n" +"10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,\n" +"4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"300f1001000000000000504944564944,Saitek P480 Rumble Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" +"10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows,\n" +"63252305000000000000504944564944,USB Vibration Joystick (BM),platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"ff113133000000000000504944564944,Gembird JPD-DualForce,platform:Windows,a:b2,b:b3,x:b0,y:b1,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,leftstick:b10,rightstick:b11,\n" +"341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" +"c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1,\n" +"100801e5000000000000504944564944,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Windows,\n" +"79000600000000000000504944564944,NGS Phantom,a:b2,b:b3,y:b1,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" +"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,\n" +"6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" +"6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" +"6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" +"6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" +"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,\n" +"4c05000000000000c405000000000000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" +"4c05000000000000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" +"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" +"891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X,\n" +"4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X,\n" +"8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" +"4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"AD1B00000000000001F9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" +"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X,\n" +"83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"79000000000000001100000000000000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a3,lefty:a4,platform:Mac OS X,\n" +"5e04000000000000dd02000000000000,Xbox One Wired Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"5e04000000000000ea02000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"5e04000000000000e002000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b10,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X,\n" +"79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X,\n" +"2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" +"351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"81170000000000007e05000000000000,Sega Saturn,x:b0,a:b2,b:b4,y:b6,start:b13,dpleft:b15,dpdown:b16,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,lefttrigger:b10,rightshoulder:b9,righttrigger:a4,righttrigger:b11,leftx:a0,lefty:a2,platform:Mac OS X,\n" +"10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" +"d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7,\n" +"0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4,\n" +"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,\n" +"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,\n" +"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,\n" +"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000006d04000016c2000011010000,Logitech F310 Gamepad (DInput),x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,\n" +"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,\n" +"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,\n" +"030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" +"050000004c050000c405000000010000,Sony DualShock 4 BT,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,\n" +"030000004c050000cc09000011010000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" +"050000004c050000cc09000000010000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" +"030000004c050000a00b000011010000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" +"030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" +"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" +"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" +"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" +"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" +"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" +"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" +"030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,\n" +"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux,\n" +"030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,\n" +"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,\n" +"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" +"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" +"030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,\n" +"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,\n" +"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" +"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" +"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" +"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" +"050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" +"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a3,rightx:a1,righty:a4,\n" +"03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,\n" +"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" +"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" +"030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" +"03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" +"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,\n" +"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" +"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,\n" +"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7\n" +"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" +"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" +"03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" +"03000000790000001100000010010000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" +"03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux,\n" +"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" +"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux,\n" +"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" +"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,\n" +"05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" +"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1,\n" +"030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5,\n" +"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,\n" +"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" +"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,\n" +"05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" +"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" +"030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" +"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" +"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:a2,righttrigger:a5,\n" +"05000000a00500003232000001000000,8Bitdo Zero GamePad,platform:Linux,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" +"030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Linux,\n" +"03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" +"05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" +"03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1,\n" + +"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n"; + diff --git a/src/external/glfw/src/mappings.h.in b/src/external/glfw/src/mappings.h.in new file mode 100644 index 00000000..bf720670 --- /dev/null +++ b/src/external/glfw/src/mappings.h.in @@ -0,0 +1,70 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// As mappings.h.in, this file is used by CMake to produce the mappings.h +// header file. If you are adding a GLFW specific gamepad mapping, this is +// where to put it. +//======================================================================== +// As mappings.h, this provides all pre-defined gamepad mappings, including +// all available in SDL_GameControllerDB. Do not edit this file. Any gamepad +// mappings not specific to GLFW should be submitted to SDL_GameControllerDB. +// This file can be re-generated from mappings.h.in and the upstream +// gamecontrollerdb.txt with the GenerateMappings.cmake script. +//======================================================================== + +// All gamepad mappings not labeled GLFW are copied from the +// SDL_GameControllerDB project under the following license: +// +// Simple DirectMedia Layer +// Copyright (C) 1997-2013 Sam Lantinga +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the +// use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +const char* _glfwDefaultMappings = +@GLFW_GAMEPAD_MAPPINGS@ +"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" +"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n"; + diff --git a/src/external/glfw/src/mir_init.c b/src/external/glfw/src/mir_init.c new file mode 100644 index 00000000..5f9ed373 --- /dev/null +++ b/src/external/glfw/src/mir_init.c @@ -0,0 +1,240 @@ +//======================================================================== +// GLFW 3.3 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014-2017 Brandon Schaefer +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + + +// Create key code translation tables +// +static void createKeyTables(void) +{ + int scancode; + + memset(_glfw.mir.keycodes, -1, sizeof(_glfw.mir.keycodes)); + memset(_glfw.mir.scancodes, -1, sizeof(_glfw.mir.scancodes)); + + _glfw.mir.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT; + _glfw.mir.keycodes[KEY_1] = GLFW_KEY_1; + _glfw.mir.keycodes[KEY_2] = GLFW_KEY_2; + _glfw.mir.keycodes[KEY_3] = GLFW_KEY_3; + _glfw.mir.keycodes[KEY_4] = GLFW_KEY_4; + _glfw.mir.keycodes[KEY_5] = GLFW_KEY_5; + _glfw.mir.keycodes[KEY_6] = GLFW_KEY_6; + _glfw.mir.keycodes[KEY_7] = GLFW_KEY_7; + _glfw.mir.keycodes[KEY_8] = GLFW_KEY_8; + _glfw.mir.keycodes[KEY_9] = GLFW_KEY_9; + _glfw.mir.keycodes[KEY_0] = GLFW_KEY_0; + _glfw.mir.keycodes[KEY_SPACE] = GLFW_KEY_SPACE; + _glfw.mir.keycodes[KEY_MINUS] = GLFW_KEY_MINUS; + _glfw.mir.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL; + _glfw.mir.keycodes[KEY_Q] = GLFW_KEY_Q; + _glfw.mir.keycodes[KEY_W] = GLFW_KEY_W; + _glfw.mir.keycodes[KEY_E] = GLFW_KEY_E; + _glfw.mir.keycodes[KEY_R] = GLFW_KEY_R; + _glfw.mir.keycodes[KEY_T] = GLFW_KEY_T; + _glfw.mir.keycodes[KEY_Y] = GLFW_KEY_Y; + _glfw.mir.keycodes[KEY_U] = GLFW_KEY_U; + _glfw.mir.keycodes[KEY_I] = GLFW_KEY_I; + _glfw.mir.keycodes[KEY_O] = GLFW_KEY_O; + _glfw.mir.keycodes[KEY_P] = GLFW_KEY_P; + _glfw.mir.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET; + _glfw.mir.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET; + _glfw.mir.keycodes[KEY_A] = GLFW_KEY_A; + _glfw.mir.keycodes[KEY_S] = GLFW_KEY_S; + _glfw.mir.keycodes[KEY_D] = GLFW_KEY_D; + _glfw.mir.keycodes[KEY_F] = GLFW_KEY_F; + _glfw.mir.keycodes[KEY_G] = GLFW_KEY_G; + _glfw.mir.keycodes[KEY_H] = GLFW_KEY_H; + _glfw.mir.keycodes[KEY_J] = GLFW_KEY_J; + _glfw.mir.keycodes[KEY_K] = GLFW_KEY_K; + _glfw.mir.keycodes[KEY_L] = GLFW_KEY_L; + _glfw.mir.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON; + _glfw.mir.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE; + _glfw.mir.keycodes[KEY_Z] = GLFW_KEY_Z; + _glfw.mir.keycodes[KEY_X] = GLFW_KEY_X; + _glfw.mir.keycodes[KEY_C] = GLFW_KEY_C; + _glfw.mir.keycodes[KEY_V] = GLFW_KEY_V; + _glfw.mir.keycodes[KEY_B] = GLFW_KEY_B; + _glfw.mir.keycodes[KEY_N] = GLFW_KEY_N; + _glfw.mir.keycodes[KEY_M] = GLFW_KEY_M; + _glfw.mir.keycodes[KEY_COMMA] = GLFW_KEY_COMMA; + _glfw.mir.keycodes[KEY_DOT] = GLFW_KEY_PERIOD; + _glfw.mir.keycodes[KEY_SLASH] = GLFW_KEY_SLASH; + _glfw.mir.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH; + _glfw.mir.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE; + _glfw.mir.keycodes[KEY_TAB] = GLFW_KEY_TAB; + _glfw.mir.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT; + _glfw.mir.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT; + _glfw.mir.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL; + _glfw.mir.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL; + _glfw.mir.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT; + _glfw.mir.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT; + _glfw.mir.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER; + _glfw.mir.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER; + _glfw.mir.keycodes[KEY_MENU] = GLFW_KEY_MENU; + _glfw.mir.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK; + _glfw.mir.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK; + _glfw.mir.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN; + _glfw.mir.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK; + _glfw.mir.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE; + _glfw.mir.keycodes[KEY_DELETE] = GLFW_KEY_DELETE; + _glfw.mir.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE; + _glfw.mir.keycodes[KEY_ENTER] = GLFW_KEY_ENTER; + _glfw.mir.keycodes[KEY_HOME] = GLFW_KEY_HOME; + _glfw.mir.keycodes[KEY_END] = GLFW_KEY_END; + _glfw.mir.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP; + _glfw.mir.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN; + _glfw.mir.keycodes[KEY_INSERT] = GLFW_KEY_INSERT; + _glfw.mir.keycodes[KEY_LEFT] = GLFW_KEY_LEFT; + _glfw.mir.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT; + _glfw.mir.keycodes[KEY_DOWN] = GLFW_KEY_DOWN; + _glfw.mir.keycodes[KEY_UP] = GLFW_KEY_UP; + _glfw.mir.keycodes[KEY_F1] = GLFW_KEY_F1; + _glfw.mir.keycodes[KEY_F2] = GLFW_KEY_F2; + _glfw.mir.keycodes[KEY_F3] = GLFW_KEY_F3; + _glfw.mir.keycodes[KEY_F4] = GLFW_KEY_F4; + _glfw.mir.keycodes[KEY_F5] = GLFW_KEY_F5; + _glfw.mir.keycodes[KEY_F6] = GLFW_KEY_F6; + _glfw.mir.keycodes[KEY_F7] = GLFW_KEY_F7; + _glfw.mir.keycodes[KEY_F8] = GLFW_KEY_F8; + _glfw.mir.keycodes[KEY_F9] = GLFW_KEY_F9; + _glfw.mir.keycodes[KEY_F10] = GLFW_KEY_F10; + _glfw.mir.keycodes[KEY_F11] = GLFW_KEY_F11; + _glfw.mir.keycodes[KEY_F12] = GLFW_KEY_F12; + _glfw.mir.keycodes[KEY_F13] = GLFW_KEY_F13; + _glfw.mir.keycodes[KEY_F14] = GLFW_KEY_F14; + _glfw.mir.keycodes[KEY_F15] = GLFW_KEY_F15; + _glfw.mir.keycodes[KEY_F16] = GLFW_KEY_F16; + _glfw.mir.keycodes[KEY_F17] = GLFW_KEY_F17; + _glfw.mir.keycodes[KEY_F18] = GLFW_KEY_F18; + _glfw.mir.keycodes[KEY_F19] = GLFW_KEY_F19; + _glfw.mir.keycodes[KEY_F20] = GLFW_KEY_F20; + _glfw.mir.keycodes[KEY_F21] = GLFW_KEY_F21; + _glfw.mir.keycodes[KEY_F22] = GLFW_KEY_F22; + _glfw.mir.keycodes[KEY_F23] = GLFW_KEY_F23; + _glfw.mir.keycodes[KEY_F24] = GLFW_KEY_F24; + _glfw.mir.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE; + _glfw.mir.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY; + _glfw.mir.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT; + _glfw.mir.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD; + _glfw.mir.keycodes[KEY_KP0] = GLFW_KEY_KP_0; + _glfw.mir.keycodes[KEY_KP1] = GLFW_KEY_KP_1; + _glfw.mir.keycodes[KEY_KP2] = GLFW_KEY_KP_2; + _glfw.mir.keycodes[KEY_KP3] = GLFW_KEY_KP_3; + _glfw.mir.keycodes[KEY_KP4] = GLFW_KEY_KP_4; + _glfw.mir.keycodes[KEY_KP5] = GLFW_KEY_KP_5; + _glfw.mir.keycodes[KEY_KP6] = GLFW_KEY_KP_6; + _glfw.mir.keycodes[KEY_KP7] = GLFW_KEY_KP_7; + _glfw.mir.keycodes[KEY_KP8] = GLFW_KEY_KP_8; + _glfw.mir.keycodes[KEY_KP9] = GLFW_KEY_KP_9; + _glfw.mir.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL; + _glfw.mir.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL; + _glfw.mir.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER; + + for (scancode = 0; scancode < 256; scancode++) + { + if (_glfw.mir.keycodes[scancode] > 0) + _glfw.mir.scancodes[_glfw.mir.keycodes[scancode]] = scancode; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + int error; + + _glfw.mir.connection = mir_connect_sync(NULL, __PRETTY_FUNCTION__); + + if (!mir_connection_is_valid(_glfw.mir.connection)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to connect to server: %s", + mir_connection_get_error_message(_glfw.mir.connection)); + + return GLFW_FALSE; + } + + _glfw.mir.display = + mir_connection_get_egl_native_display(_glfw.mir.connection); + + createKeyTables(); + + if (!_glfwInitJoysticksLinux()) + return GLFW_FALSE; + + _glfwInitTimerPOSIX(); + + _glfw.mir.eventQueue = calloc(1, sizeof(EventQueue)); + _glfwInitEventQueueMir(_glfw.mir.eventQueue); + + error = pthread_mutex_init(&_glfw.mir.eventMutex, NULL); + if (error) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Failed to create event mutex: %s", + strerror(error)); + return GLFW_FALSE; + } + + _glfwPollMonitorsMir(); + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + _glfwTerminateEGL(); + _glfwTerminateJoysticksLinux(); + + _glfwDeleteEventQueueMir(_glfw.mir.eventQueue); + + pthread_mutex_destroy(&_glfw.mir.eventMutex); + + mir_connection_release(_glfw.mir.connection); +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " Mir EGL" +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#else + " gettimeofday" +#endif + " evdev" +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; +} + diff --git a/src/external/glfw/src/mir_monitor.c b/src/external/glfw/src/mir_monitor.c new file mode 100644 index 00000000..b300cac0 --- /dev/null +++ b/src/external/glfw/src/mir_monitor.c @@ -0,0 +1,214 @@ +//======================================================================== +// GLFW 3.3 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014-2017 Brandon Schaefer +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Poll for changes in the set of connected monitors +// +void _glfwPollMonitorsMir(void) +{ + int i; + MirDisplayConfig* displayConfig = + mir_connection_create_display_configuration(_glfw.mir.connection); + + int numOutputs = mir_display_config_get_num_outputs(displayConfig); + + for (i = 0; i < numOutputs; i++) + { + const MirOutput* output = mir_display_config_get_output(displayConfig, i); + MirOutputConnectionState state = mir_output_get_connection_state(output); + bool enabled = mir_output_is_enabled(output); + + if (enabled && state == mir_output_connection_state_connected) + { + int widthMM = mir_output_get_physical_width_mm(output); + int heightMM = mir_output_get_physical_height_mm(output); + int x = mir_output_get_position_x(output); + int y = mir_output_get_position_y(output); + int id = mir_output_get_id(output); + size_t currentMode = mir_output_get_current_mode_index(output); + const char* name = mir_output_type_name(mir_output_get_type(output)); + + _GLFWmonitor* monitor = _glfwAllocMonitor(name, + widthMM, + heightMM); + monitor->mir.x = x; + monitor->mir.y = y; + monitor->mir.outputId = id; + monitor->mir.curMode = currentMode; + monitor->modes = _glfwPlatformGetVideoModes(monitor, &monitor->modeCount); + + _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); + } + } + + mir_display_config_release(displayConfig); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + if (xpos) + *xpos = monitor->mir.x; + if (ypos) + *ypos = monitor->mir.y; +} + +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = 1.f; + if (yscale) + *yscale = 1.f; +} + +static void FillInRGBBitsFromPixelFormat(GLFWvidmode* mode, const MirPixelFormat pf) +{ + switch (pf) + { + case mir_pixel_format_rgb_565: + mode->redBits = 5; + mode->greenBits = 6; + mode->blueBits = 5; + break; + case mir_pixel_format_rgba_5551: + mode->redBits = 5; + mode->greenBits = 5; + mode->blueBits = 5; + break; + case mir_pixel_format_rgba_4444: + mode->redBits = 4; + mode->greenBits = 4; + mode->blueBits = 4; + break; + case mir_pixel_format_abgr_8888: + case mir_pixel_format_xbgr_8888: + case mir_pixel_format_argb_8888: + case mir_pixel_format_xrgb_8888: + case mir_pixel_format_bgr_888: + case mir_pixel_format_rgb_888: + default: + mode->redBits = 8; + mode->greenBits = 8; + mode->blueBits = 8; + break; + } +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + int i; + GLFWvidmode* modes = NULL; + MirDisplayConfig* displayConfig = + mir_connection_create_display_configuration(_glfw.mir.connection); + + int numOutputs = mir_display_config_get_num_outputs(displayConfig); + + for (i = 0; i < numOutputs; i++) + { + const MirOutput* output = mir_display_config_get_output(displayConfig, i); + int id = mir_output_get_id(output); + + if (id != monitor->mir.outputId) + continue; + + MirOutputConnectionState state = mir_output_get_connection_state(output); + bool enabled = mir_output_is_enabled(output); + + // We must have been disconnected + if (!enabled || state != mir_output_connection_state_connected) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Monitor no longer connected"); + return NULL; + } + + int numModes = mir_output_get_num_modes(output); + modes = calloc(numModes, sizeof(GLFWvidmode)); + + for (*found = 0; *found < numModes; (*found)++) + { + const MirOutputMode* mode = mir_output_get_mode(output, *found); + int width = mir_output_mode_get_width(mode); + int height = mir_output_mode_get_height(mode); + double refreshRate = mir_output_mode_get_refresh_rate(mode); + MirPixelFormat currentFormat = mir_output_get_current_pixel_format(output); + + modes[*found].width = width; + modes[*found].height = height; + modes[*found].refreshRate = refreshRate; + + FillInRGBBitsFromPixelFormat(&modes[*found], currentFormat); + } + + break; + } + + mir_display_config_release(displayConfig); + + return modes; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + *mode = monitor->modes[monitor->mir.curMode]; +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwGetMirMonitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return monitor->mir.outputId; +} diff --git a/src/external/glfw/src/mir_platform.h b/src/external/glfw/src/mir_platform.h new file mode 100644 index 00000000..da00a326 --- /dev/null +++ b/src/external/glfw/src/mir_platform.h @@ -0,0 +1,133 @@ +//======================================================================== +// GLFW 3.3 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014-2017 Brandon Schaefer +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include +#include +#include + +#include + +typedef VkFlags VkMirWindowCreateFlagsKHR; + +typedef struct VkMirWindowCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkMirWindowCreateFlagsKHR flags; + MirConnection* connection; + MirWindow* mirWindow; +} VkMirWindowCreateInfoKHR; + +typedef VkResult (APIENTRY *PFN_vkCreateMirWindowKHR)(VkInstance,const VkMirWindowCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice,uint32_t,MirConnection*); + +#include "posix_thread.h" +#include "posix_time.h" +#include "linux_joystick.h" +#include "xkb_unicode.h" +#include "egl_context.h" +#include "osmesa_context.h" + +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) + +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->mir.nativeWindow) +#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.mir.display) + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowMir mir +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorMir mir +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorMir mir + +#define _GLFW_PLATFORM_CONTEXT_STATE +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE + + +// Mir-specific Event Queue +// +typedef struct EventQueue +{ + TAILQ_HEAD(, EventNode) head; +} EventQueue; + +// Mir-specific per-window data +// +typedef struct _GLFWwindowMir +{ + MirWindow* window; + int width; + int height; + MirEGLNativeWindowType nativeWindow; + _GLFWcursor* currentCursor; + +} _GLFWwindowMir; + +// Mir-specific per-monitor data +// +typedef struct _GLFWmonitorMir +{ + int curMode; + int outputId; + int x; + int y; + +} _GLFWmonitorMir; + +// Mir-specific global data +// +typedef struct _GLFWlibraryMir +{ + MirConnection* connection; + MirEGLNativeDisplayType display; + EventQueue* eventQueue; + + short int keycodes[256]; + short int scancodes[GLFW_KEY_LAST + 1]; + + pthread_mutex_t eventMutex; + pthread_cond_t eventCond; + + // The window whose disabled cursor mode is active + _GLFWwindow* disabledCursorWindow; + +} _GLFWlibraryMir; + +// Mir-specific per-cursor data +// TODO: Only system cursors are implemented in Mir atm. Need to wait for support. +// +typedef struct _GLFWcursorMir +{ + MirCursorConfiguration* conf; + MirBufferStream* customCursor; + char const* cursorName; // only needed for system cursors +} _GLFWcursorMir; + + +extern void _glfwPollMonitorsMir(void); +extern void _glfwInitEventQueueMir(EventQueue* queue); +extern void _glfwDeleteEventQueueMir(EventQueue* queue); + diff --git a/src/external/glfw/src/mir_window.c b/src/external/glfw/src/mir_window.c new file mode 100644 index 00000000..c752cdb4 --- /dev/null +++ b/src/external/glfw/src/mir_window.c @@ -0,0 +1,955 @@ +//======================================================================== +// GLFW 3.3 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014-2017 Brandon Schaefer +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + + +typedef struct EventNode +{ + TAILQ_ENTRY(EventNode) entries; + const MirEvent* event; + _GLFWwindow* window; +} EventNode; + +static void deleteNode(EventQueue* queue, EventNode* node) +{ + mir_event_unref(node->event); + free(node); +} + +static GLFWbool emptyEventQueue(EventQueue* queue) +{ + return queue->head.tqh_first == NULL; +} + +// TODO The mir_event_ref is not supposed to be used but ... its needed +// in this case. Need to wait until we can read from an FD set up by mir +// for single threaded event handling. +static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context) +{ + EventNode* newNode = calloc(1, sizeof(EventNode)); + newNode->event = mir_event_ref(event); + newNode->window = context; + + return newNode; +} + +static void enqueueEvent(const MirEvent* event, _GLFWwindow* context) +{ + pthread_mutex_lock(&_glfw.mir.eventMutex); + + EventNode* newNode = newEventNode(event, context); + TAILQ_INSERT_TAIL(&_glfw.mir.eventQueue->head, newNode, entries); + + pthread_cond_signal(&_glfw.mir.eventCond); + + pthread_mutex_unlock(&_glfw.mir.eventMutex); +} + +static EventNode* dequeueEvent(EventQueue* queue) +{ + EventNode* node = NULL; + + pthread_mutex_lock(&_glfw.mir.eventMutex); + + node = queue->head.tqh_first; + + if (node) + TAILQ_REMOVE(&queue->head, node, entries); + + pthread_mutex_unlock(&_glfw.mir.eventMutex); + + return node; +} + +static MirPixelFormat findValidPixelFormat(void) +{ + unsigned int i, validFormats, mirPixelFormats = 32; + MirPixelFormat formats[mir_pixel_formats]; + + mir_connection_get_available_surface_formats(_glfw.mir.connection, formats, + mirPixelFormats, &validFormats); + + for (i = 0; i < validFormats; i++) + { + if (formats[i] == mir_pixel_format_abgr_8888 || + formats[i] == mir_pixel_format_xbgr_8888 || + formats[i] == mir_pixel_format_argb_8888 || + formats[i] == mir_pixel_format_xrgb_8888) + { + return formats[i]; + } + } + + return mir_pixel_format_invalid; +} + +static int mirModToGLFWMod(uint32_t mods) +{ + int publicMods = 0x0; + + if (mods & mir_input_event_modifier_alt) + publicMods |= GLFW_MOD_ALT; + else if (mods & mir_input_event_modifier_shift) + publicMods |= GLFW_MOD_SHIFT; + else if (mods & mir_input_event_modifier_ctrl) + publicMods |= GLFW_MOD_CONTROL; + else if (mods & mir_input_event_modifier_meta) + publicMods |= GLFW_MOD_SUPER; + + return publicMods; +} + +static int toGLFWKeyCode(uint32_t key) +{ + if (key < sizeof(_glfw.mir.keycodes) / sizeof(_glfw.mir.keycodes[0])) + return _glfw.mir.keycodes[key]; + + return GLFW_KEY_UNKNOWN; +} + +static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* window) +{ + const int action = mir_keyboard_event_action (key_event); + const int scan_code = mir_keyboard_event_scan_code(key_event); + const int key_code = mir_keyboard_event_key_code (key_event); + const int modifiers = mir_keyboard_event_modifiers(key_event); + + const int pressed = action == mir_keyboard_action_up ? GLFW_RELEASE : GLFW_PRESS; + const int mods = mirModToGLFWMod(modifiers); + const long text = _glfwKeySym2Unicode(key_code); + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + + _glfwInputKey(window, toGLFWKeyCode(scan_code), scan_code, pressed, mods); + + if (text != -1) + _glfwInputChar(window, text, mods, plain); +} + +static void handlePointerButton(_GLFWwindow* window, + int pressed, + const MirPointerEvent* pointer_event) +{ + int mods = mir_pointer_event_modifiers(pointer_event); + const int publicMods = mirModToGLFWMod(mods); + MirPointerButton button = mir_pointer_button_primary; + static uint32_t oldButtonStates = 0; + uint32_t newButtonStates = mir_pointer_event_buttons(pointer_event); + int publicButton = GLFW_MOUSE_BUTTON_LEFT; + + // XOR our old button states our new states to figure out what was added or removed + button = newButtonStates ^ oldButtonStates; + + switch (button) + { + case mir_pointer_button_primary: + publicButton = GLFW_MOUSE_BUTTON_LEFT; + break; + case mir_pointer_button_secondary: + publicButton = GLFW_MOUSE_BUTTON_RIGHT; + break; + case mir_pointer_button_tertiary: + publicButton = GLFW_MOUSE_BUTTON_MIDDLE; + break; + case mir_pointer_button_forward: + // FIXME What is the forward button? + publicButton = GLFW_MOUSE_BUTTON_4; + break; + case mir_pointer_button_back: + // FIXME What is the back button? + publicButton = GLFW_MOUSE_BUTTON_5; + break; + default: + break; + } + + oldButtonStates = newButtonStates; + + _glfwInputMouseClick(window, publicButton, pressed, publicMods); +} + +static void handlePointerMotion(_GLFWwindow* window, + const MirPointerEvent* pointer_event) +{ + const int hscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll); + const int vscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll); + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (_glfw.mir.disabledCursorWindow != window) + return; + + const int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_x); + const int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_y); + const int current_x = window->virtualCursorPosX; + const int current_y = window->virtualCursorPosY; + + _glfwInputCursorPos(window, dx + current_x, dy + current_y); + } + else + { + const int x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x); + const int y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y); + + _glfwInputCursorPos(window, x, y); + } + + if (hscroll != 0 || vscroll != 0) + _glfwInputScroll(window, hscroll, vscroll); +} + +static void handlePointerEvent(const MirPointerEvent* pointer_event, + _GLFWwindow* window) +{ + int action = mir_pointer_event_action(pointer_event); + + switch (action) + { + case mir_pointer_action_button_down: + handlePointerButton(window, GLFW_PRESS, pointer_event); + break; + case mir_pointer_action_button_up: + handlePointerButton(window, GLFW_RELEASE, pointer_event); + break; + case mir_pointer_action_motion: + handlePointerMotion(window, pointer_event); + break; + case mir_pointer_action_enter: + case mir_pointer_action_leave: + break; + default: + break; + } +} + +static void handleInput(const MirInputEvent* input_event, _GLFWwindow* window) +{ + int type = mir_input_event_get_type(input_event); + + switch (type) + { + case mir_input_event_type_key: + handleKeyEvent(mir_input_event_get_keyboard_event(input_event), window); + break; + case mir_input_event_type_pointer: + handlePointerEvent(mir_input_event_get_pointer_event(input_event), window); + break; + default: + break; + } +} + +static void handleEvent(const MirEvent* event, _GLFWwindow* window) +{ + int type = mir_event_get_type(event); + + switch (type) + { + case mir_event_type_input: + handleInput(mir_event_get_input_event(event), window); + break; + default: + break; + } +} + +static void addNewEvent(MirWindow* window, const MirEvent* event, void* context) +{ + enqueueEvent(event, context); +} + +static GLFWbool createWindow(_GLFWwindow* window) +{ + MirWindowSpec* spec; + MirBufferUsage buffer_usage = mir_buffer_usage_hardware; + MirPixelFormat pixel_format = findValidPixelFormat(); + + if (pixel_format == mir_pixel_format_invalid) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to find a correct pixel format"); + return GLFW_FALSE; + } + + spec = mir_create_normal_window_spec(_glfw.mir.connection, + window->mir.width, + window->mir.height); + + mir_window_spec_set_pixel_format(spec, pixel_format); + mir_window_spec_set_buffer_usage(spec, buffer_usage); + + window->mir.window = mir_create_window_sync(spec); + mir_window_spec_release(spec); + + if (!mir_window_is_valid(window->mir.window)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to create window: %s", + mir_window_get_error_message(window->mir.window)); + + return GLFW_FALSE; + } + + mir_window_set_event_handler(window->mir.window, addNewEvent, window); + + return GLFW_TRUE; +} + +static void setWindowConfinement(_GLFWwindow* window, MirPointerConfinementState state) +{ + MirWindowSpec* spec; + + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_pointer_confinement(spec, state); + + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInitEventQueueMir(EventQueue* queue) +{ + TAILQ_INIT(&queue->head); +} + +void _glfwDeleteEventQueueMir(EventQueue* queue) +{ + if (queue) + { + EventNode* node, *node_next; + node = queue->head.tqh_first; + + while (node != NULL) + { + node_next = node->entries.tqe_next; + + TAILQ_REMOVE(&queue->head, node, entries); + deleteNode(queue, node); + + node = node_next; + } + + free(queue); + } +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (window->monitor) + { + GLFWvidmode mode; + _glfwPlatformGetVideoMode(window->monitor, &mode); + + mir_window_set_state(window->mir.window, mir_window_state_fullscreen); + + if (wndconfig->width > mode.width || wndconfig->height > mode.height) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Requested window size too large: %ix%i", + wndconfig->width, wndconfig->height); + + return GLFW_FALSE; + } + } + + window->mir.width = wndconfig->width; + window->mir.height = wndconfig->height; + window->mir.currentCursor = NULL; + + if (!createWindow(window)) + return GLFW_FALSE; + + window->mir.nativeWindow = mir_buffer_stream_get_egl_native_window( + mir_window_get_buffer_stream(window->mir.window)); + + if (ctxconfig->client != GLFW_NO_API) + { + if (ctxconfig->source == GLFW_EGL_CONTEXT_API || + ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwInitOSMesa()) + return GLFW_FALSE; + if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (_glfw.mir.disabledCursorWindow == window) + _glfw.mir.disabledCursorWindow = NULL; + + if (mir_window_is_valid(window->mir.window)) + { + mir_window_release_sync(window->mir.window); + window->mir.window= NULL; + } + + if (window->context.destroy) + window->context.destroy(window); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ + MirWindowSpec* spec; + + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_name(spec, title); + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + MirWindowSpec* spec; + + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_width (spec, width); + mir_window_spec_set_height(spec, height); + + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + MirWindowSpec* spec; + + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_max_width (spec, maxwidth); + mir_window_spec_set_max_height(spec, maxheight); + mir_window_spec_set_min_width (spec, minwidth); + mir_window_spec_set_min_height(spec, minheight); + + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->mir.width; + if (height) + *height = window->mir.height; +} + +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = 1.f; + if (yscale) + *yscale = 1.f; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + MirWindowSpec* spec; + + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_state(spec, mir_window_state_minimized); + + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + MirWindowSpec* spec; + + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_state(spec, mir_window_state_restored); + + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + MirWindowSpec* spec; + + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_state(spec, mir_window_state_maximized); + + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + MirWindowSpec* spec; + + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_state(spec, mir_window_state_hidden); + + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + MirWindowSpec* spec; + + spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_state(spec, mir_window_state_restored); + + mir_window_apply_spec(window->mir.window, spec); + mir_window_spec_release(spec); +} + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + return mir_window_get_focus_state(window->mir.window) == mir_window_focus_state_focused; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + return GLFW_FALSE; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + return mir_window_get_visibility(window->mir.window) == mir_window_visibility_exposed; +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + return mir_window_get_state(window->mir.window) == mir_window_state_maximized; +} + +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + return GLFW_FALSE; +} + +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformPollEvents(void) +{ + EventNode* node = NULL; + + while ((node = dequeueEvent(_glfw.mir.eventQueue))) + { + handleEvent(node->event, node->window); + deleteNode(_glfw.mir.eventQueue, node); + } +} + +void _glfwPlatformWaitEvents(void) +{ + pthread_mutex_lock(&_glfw.mir.eventMutex); + + while (emptyEventQueue(_glfw.mir.eventQueue)) + pthread_cond_wait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex); + + pthread_mutex_unlock(&_glfw.mir.eventMutex); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + pthread_mutex_lock(&_glfw.mir.eventMutex); + + if (emptyEventQueue(_glfw.mir.eventQueue)) + { + struct timespec time; + clock_gettime(CLOCK_REALTIME, &time); + time.tv_sec += (long) timeout; + time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9); + pthread_cond_timedwait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex, &time); + } + + pthread_mutex_unlock(&_glfw.mir.eventMutex); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformPostEmptyEvent(void) +{ +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->mir.width; + if (height) + *height = window->mir.height; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + MirBufferStream* stream; + + int i_w = image->width; + int i_h = image->height; + + stream = mir_connection_create_buffer_stream_sync(_glfw.mir.connection, + i_w, i_h, + mir_pixel_format_argb_8888, + mir_buffer_usage_software); + + cursor->mir.conf = mir_cursor_configuration_from_buffer_stream(stream, xhot, yhot); + + MirGraphicsRegion region; + mir_buffer_stream_get_graphics_region(stream, ®ion); + + unsigned char* pixels = image->pixels; + char* dest = region.vaddr; + int i; + + for (i = 0; i < i_w * i_h; i++, pixels += 4) + { + unsigned int alpha = pixels[3]; + *dest++ = (char)(pixels[2] * alpha / 255); + *dest++ = (char)(pixels[1] * alpha / 255); + *dest++ = (char)(pixels[0] * alpha / 255); + *dest++ = (char)alpha; + } + + mir_buffer_stream_swap_buffers_sync(stream); + cursor->mir.customCursor = stream; + + return GLFW_TRUE; +} + +static const char* getSystemCursorName(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return mir_arrow_cursor_name; + case GLFW_IBEAM_CURSOR: + return mir_caret_cursor_name; + case GLFW_CROSSHAIR_CURSOR: + return mir_crosshair_cursor_name; + case GLFW_HAND_CURSOR: + return mir_open_hand_cursor_name; + case GLFW_HRESIZE_CURSOR: + return mir_horizontal_resize_cursor_name; + case GLFW_VRESIZE_CURSOR: + return mir_vertical_resize_cursor_name; + } + + return NULL; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + cursor->mir.conf = NULL; + cursor->mir.customCursor = NULL; + cursor->mir.cursorName = getSystemCursorName(shape); + + return cursor->mir.cursorName != NULL; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + if (cursor->mir.conf) + mir_cursor_configuration_destroy(cursor->mir.conf); + if (cursor->mir.customCursor) + mir_buffer_stream_release_sync(cursor->mir.customCursor); +} + +static void setCursorNameForWindow(MirWindow* window, char const* name) +{ + MirWindowSpec* spec = mir_create_window_spec(_glfw.mir.connection); + mir_window_spec_set_cursor_name(spec, name); + mir_window_apply_spec(window, spec); + mir_window_spec_release(spec); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + if (cursor) + { + window->mir.currentCursor = cursor; + + if (cursor->mir.cursorName) + { + setCursorNameForWindow(window->mir.window, cursor->mir.cursorName); + } + else if (cursor->mir.conf) + { + mir_window_configure_cursor(window->mir.window, cursor->mir.conf); + } + } + else + { + setCursorNameForWindow(window->mir.window, mir_default_cursor_name); + } +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + if (mode == GLFW_CURSOR_DISABLED) + { + _glfw.mir.disabledCursorWindow = window; + setWindowConfinement(window, mir_pointer_confined_to_window); + setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name); + } + else + { + // If we were disabled before lets undo that! + if (_glfw.mir.disabledCursorWindow == window) + { + _glfw.mir.disabledCursorWindow = NULL; + setWindowConfinement(window, mir_pointer_unconfined); + } + + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + _glfwPlatformSetCursor(window, window->mir.currentCursor); + } + else if (window->cursorMode == GLFW_CURSOR_HIDDEN) + { + setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name); + } + } +} + +const char* _glfwPlatformGetScancodeName(int scancode) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + return NULL; +} + +int _glfwPlatformGetKeyScancode(int key) +{ + return _glfw.mir.scancodes[key]; +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + + return NULL; +} + +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) +{ + if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_mir_surface) + return; + + extensions[0] = "VK_KHR_surface"; + extensions[1] = "VK_KHR_mir_surface"; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + PFN_vkGetPhysicalDeviceMirPresentationSupportKHR + vkGetPhysicalDeviceMirPresentationSupportKHR = + (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR"); + if (!vkGetPhysicalDeviceMirPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Mir: Vulkan instance missing VK_KHR_mir_surface extension"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceMirPresentationSupportKHR(device, + queuefamily, + _glfw.mir.connection); +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + VkResult err; + VkMirWindowCreateInfoKHR sci; + PFN_vkCreateMirWindowKHR vkCreateMirWindowKHR; + + vkCreateMirWindowKHR = (PFN_vkCreateMirWindowKHR) + vkGetInstanceProcAddr(instance, "vkCreateMirWindowKHR"); + if (!vkCreateMirWindowKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Mir: Vulkan instance missing VK_KHR_mir_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR; + sci.connection = _glfw.mir.connection; + sci.mirWindow = window->mir.window; + + err = vkCreateMirWindowKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Failed to create Vulkan surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI MirConnection* glfwGetMirDisplay(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfw.mir.connection; +} + +GLFWAPI MirWindow* glfwGetMirWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->mir.window; +} + diff --git a/src/external/glfw/src/monitor.c b/src/external/glfw/src/monitor.c new file mode 100644 index 00000000..0dfb1958 --- /dev/null +++ b/src/external/glfw/src/monitor.c @@ -0,0 +1,467 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include +#include +#include + + +// Lexically compare video modes, used by qsort +// +static int compareVideoModes(const void* fp, const void* sp) +{ + const GLFWvidmode* fm = fp; + const GLFWvidmode* sm = sp; + const int fbpp = fm->redBits + fm->greenBits + fm->blueBits; + const int sbpp = sm->redBits + sm->greenBits + sm->blueBits; + const int farea = fm->width * fm->height; + const int sarea = sm->width * sm->height; + + // First sort on color bits per pixel + if (fbpp != sbpp) + return fbpp - sbpp; + + // Then sort on screen area + if (farea != sarea) + return farea - sarea; + + // Lastly sort on refresh rate + return fm->refreshRate - sm->refreshRate; +} + +// Retrieves the available modes for the specified monitor +// +static GLFWbool refreshVideoModes(_GLFWmonitor* monitor) +{ + int modeCount; + GLFWvidmode* modes; + + if (monitor->modes) + return GLFW_TRUE; + + modes = _glfwPlatformGetVideoModes(monitor, &modeCount); + if (!modes) + return GLFW_FALSE; + + qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes); + + free(monitor->modes); + monitor->modes = modes; + monitor->modeCount = modeCount; + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) +{ + if (action == GLFW_CONNECTED) + { + _glfw.monitorCount++; + _glfw.monitors = + realloc(_glfw.monitors, sizeof(_GLFWmonitor*) * _glfw.monitorCount); + + if (placement == _GLFW_INSERT_FIRST) + { + memmove(_glfw.monitors + 1, + _glfw.monitors, + (_glfw.monitorCount - 1) * sizeof(_GLFWmonitor*)); + _glfw.monitors[0] = monitor; + } + else + _glfw.monitors[_glfw.monitorCount - 1] = monitor; + } + else if (action == GLFW_DISCONNECTED) + { + int i; + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) + { + if (window->monitor == monitor) + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0); + } + } + + for (i = 0; i < _glfw.monitorCount; i++) + { + if (_glfw.monitors[i] == monitor) + { + _glfw.monitorCount--; + memmove(_glfw.monitors + i, + _glfw.monitors + i + 1, + (_glfw.monitorCount - i) * sizeof(_GLFWmonitor*)); + break; + } + } + } + + if (_glfw.callbacks.monitor) + _glfw.callbacks.monitor((GLFWmonitor*) monitor, action); + + if (action == GLFW_DISCONNECTED) + _glfwFreeMonitor(monitor); +} + +void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window) +{ + monitor->window = window; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM) +{ + _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor)); + monitor->widthMM = widthMM; + monitor->heightMM = heightMM; + + if (name) + monitor->name = strdup(name); + + return monitor; +} + +void _glfwFreeMonitor(_GLFWmonitor* monitor) +{ + if (monitor == NULL) + return; + + _glfwFreeGammaArrays(&monitor->originalRamp); + _glfwFreeGammaArrays(&monitor->currentRamp); + + free(monitor->modes); + free(monitor->name); + free(monitor); +} + +void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) +{ + ramp->red = calloc(size, sizeof(unsigned short)); + ramp->green = calloc(size, sizeof(unsigned short)); + ramp->blue = calloc(size, sizeof(unsigned short)); + ramp->size = size; +} + +void _glfwFreeGammaArrays(GLFWgammaramp* ramp) +{ + free(ramp->red); + free(ramp->green); + free(ramp->blue); + + memset(ramp, 0, sizeof(GLFWgammaramp)); +} + +const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor, + const GLFWvidmode* desired) +{ + int i; + unsigned int sizeDiff, leastSizeDiff = UINT_MAX; + unsigned int rateDiff, leastRateDiff = UINT_MAX; + unsigned int colorDiff, leastColorDiff = UINT_MAX; + const GLFWvidmode* current; + const GLFWvidmode* closest = NULL; + + if (!refreshVideoModes(monitor)) + return NULL; + + for (i = 0; i < monitor->modeCount; i++) + { + current = monitor->modes + i; + + colorDiff = 0; + + if (desired->redBits != GLFW_DONT_CARE) + colorDiff += abs(current->redBits - desired->redBits); + if (desired->greenBits != GLFW_DONT_CARE) + colorDiff += abs(current->greenBits - desired->greenBits); + if (desired->blueBits != GLFW_DONT_CARE) + colorDiff += abs(current->blueBits - desired->blueBits); + + sizeDiff = abs((current->width - desired->width) * + (current->width - desired->width) + + (current->height - desired->height) * + (current->height - desired->height)); + + if (desired->refreshRate != GLFW_DONT_CARE) + rateDiff = abs(current->refreshRate - desired->refreshRate); + else + rateDiff = UINT_MAX - current->refreshRate; + + if ((colorDiff < leastColorDiff) || + (colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) || + (colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff)) + { + closest = current; + leastSizeDiff = sizeDiff; + leastRateDiff = rateDiff; + leastColorDiff = colorDiff; + } + } + + return closest; +} + +int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm) +{ + return compareVideoModes(fm, sm); +} + +void _glfwSplitBPP(int bpp, int* red, int* green, int* blue) +{ + int delta; + + // We assume that by 32 the user really meant 24 + if (bpp == 32) + bpp = 24; + + // Convert "bits per pixel" to red, green & blue sizes + + *red = *green = *blue = bpp / 3; + delta = bpp - (*red * 3); + if (delta >= 1) + *green = *green + 1; + + if (delta == 2) + *red = *red + 1; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI GLFWmonitor** glfwGetMonitors(int* count) +{ + assert(count != NULL); + + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + *count = _glfw.monitorCount; + return (GLFWmonitor**) _glfw.monitors; +} + +GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (!_glfw.monitorCount) + return NULL; + + return (GLFWmonitor*) _glfw.monitors[0]; +} + +GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformGetMonitorPos(monitor, xpos, ypos); +} + +GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + if (widthMM) + *widthMM = 0; + if (heightMM) + *heightMM = 0; + + _GLFW_REQUIRE_INIT(); + + if (widthMM) + *widthMM = monitor->widthMM; + if (heightMM) + *heightMM = monitor->heightMM; +} + +GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* handle, + float* xscale, float* yscale) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + if (xscale) + *xscale = 0.f; + if (yscale) + *yscale = 0.f; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetMonitorContentScale(monitor, xscale, yscale); +} + +GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->name; +} + +GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun); + return cbfun; +} + +GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + assert(count != NULL); + + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (!refreshVideoModes(monitor)) + return NULL; + + *count = monitor->modeCount; + return monitor->modes; +} + +GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + _glfwPlatformGetVideoMode(monitor, &monitor->currentMode); + return &monitor->currentMode; +} + +GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) +{ + int i; + unsigned short values[256]; + GLFWgammaramp ramp; + assert(handle != NULL); + assert(gamma == gamma); + assert(gamma >= 0.f); + assert(gamma <= FLT_MAX); + + _GLFW_REQUIRE_INIT(); + + if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma); + return; + } + + for (i = 0; i < 256; i++) + { + double value; + + // Calculate intensity + value = i / 255.0; + // Apply gamma curve + value = pow(value, 1.0 / gamma) * 65535.0 + 0.5; + + // Clamp to value range + if (value > 65535.0) + value = 65535.0; + + values[i] = (unsigned short) value; + } + + ramp.red = values; + ramp.green = values; + ramp.blue = values; + ramp.size = 256; + + glfwSetGammaRamp(handle, &ramp); +} + +GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + _glfwFreeGammaArrays(&monitor->currentRamp); + _glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp); + + return &monitor->currentRamp; +} + +GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + assert(ramp != NULL); + assert(ramp->size > 0); + assert(ramp->red != NULL); + assert(ramp->green != NULL); + assert(ramp->blue != NULL); + + if (ramp->size <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid gamma ramp size %i", + ramp->size); + return; + } + + _GLFW_REQUIRE_INIT(); + + if (!monitor->originalRamp.size) + _glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp); + + _glfwPlatformSetGammaRamp(monitor, ramp); +} + diff --git a/src/external/glfw/src/nsgl_context.h b/src/external/glfw/src/nsgl_context.h new file mode 100644 index 00000000..18042dee --- /dev/null +++ b/src/external/glfw/src/nsgl_context.h @@ -0,0 +1,56 @@ +//======================================================================== +// GLFW 3.3 macOS - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl + + +// NSGL-specific per-context data +// +typedef struct _GLFWcontextNSGL +{ + id pixelFormat; + id object; + +} _GLFWcontextNSGL; + +// NSGL-specific global data +// +typedef struct _GLFWlibraryNSGL +{ + // dlopen handle for OpenGL.framework (for glfwGetProcAddress) + CFBundleRef framework; + +} _GLFWlibraryNSGL; + + +GLFWbool _glfwInitNSGL(void); +void _glfwTerminateNSGL(void); +GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContextNSGL(_GLFWwindow* window); + diff --git a/src/external/glfw/src/nsgl_context.m b/src/external/glfw/src/nsgl_context.m new file mode 100644 index 00000000..a7cbf00f --- /dev/null +++ b/src/external/glfw/src/nsgl_context.m @@ -0,0 +1,335 @@ +//======================================================================== +// GLFW 3.3 macOS - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +static void makeContextCurrentNSGL(_GLFWwindow* window) +{ + if (window) + [window->context.nsgl.object makeCurrentContext]; + else + [NSOpenGLContext clearCurrentContext]; + + _glfwPlatformSetTls(&_glfw.contextSlot, window); +} + +static void swapBuffersNSGL(_GLFWwindow* window) +{ + // ARP appears to be unnecessary, but this is future-proof + [window->context.nsgl.object flushBuffer]; +} + +static void swapIntervalNSGL(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + + GLint sync = interval; + [window->context.nsgl.object setValues:&sync + forParameter:NSOpenGLCPSwapInterval]; +} + +static int extensionSupportedNSGL(const char* extension) +{ + // There are no NSGL extensions + return GLFW_FALSE; +} + +static GLFWglproc getProcAddressNSGL(const char* procname) +{ + CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, + procname, + kCFStringEncodingASCII); + + GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework, + symbolName); + + CFRelease(symbolName); + + return symbol; +} + +// Destroy the OpenGL context +// +static void destroyContextNSGL(_GLFWwindow* window) +{ + [window->context.nsgl.pixelFormat release]; + window->context.nsgl.pixelFormat = nil; + + [window->context.nsgl.object release]; + window->context.nsgl.object = nil; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize OpenGL support +// +GLFWbool _glfwInitNSGL(void) +{ + if (_glfw.nsgl.framework) + return GLFW_TRUE; + + _glfw.nsgl.framework = + CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); + if (_glfw.nsgl.framework == NULL) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "NSGL: Failed to locate OpenGL framework"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Terminate OpenGL support +// +void _glfwTerminateNSGL(void) +{ +} + +// Create the OpenGL context +// +GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "NSGL: OpenGL ES is not available on macOS"); + return GLFW_FALSE; + } + + if (ctxconfig->major > 2) + { + if (ctxconfig->major == 3 && ctxconfig->minor < 2) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: The targeted version of macOS does not support OpenGL 3.0 or 3.1 but may support 3.2 and above"); + return GLFW_FALSE; + } + + if (!ctxconfig->forward || ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: The targeted version of macOS only supports forward-compatible core profile contexts for OpenGL 3.2 and above"); + return GLFW_FALSE; + } + } + + // Context robustness modes (GL_KHR_robustness) are not yet supported by + // macOS but are not a hard constraint, so ignore and continue + + // Context release behaviors (GL_KHR_context_flush_control) are not yet + // supported by macOS but are not a hard constraint, so ignore and continue + + // Debug contexts (GL_KHR_debug) are not yet supported by macOS but are not + // a hard constraint, so ignore and continue + + // No-error contexts (GL_KHR_no_error) are not yet supported by macOS but + // are not a hard constraint, so ignore and continue + +#define addAttrib(a) \ +{ \ + assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[index++] = a; \ +} +#define setAttrib(a, v) { addAttrib(a); addAttrib(v); } + + NSOpenGLPixelFormatAttribute attribs[40]; + int index = 0; + + addAttrib(NSOpenGLPFAAccelerated); + addAttrib(NSOpenGLPFAClosestPolicy); + + if (ctxconfig->nsgl.offline) + { + addAttrib(NSOpenGLPFAAllowOfflineRenderers); + // NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in + // Info.plist for unbundled applications + // HACK: This assumes that NSOpenGLPixelFormat will remain + // a straightforward wrapper of its CGL counterpart +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 100800 + addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching); +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + } + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 + if (ctxconfig->major >= 4) + { + setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); + } + else +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + if (ctxconfig->major >= 3) + { + setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); + } + + if (ctxconfig->major <= 2) + { + if (fbconfig->auxBuffers != GLFW_DONT_CARE) + setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); + + if (fbconfig->accumRedBits != GLFW_DONT_CARE && + fbconfig->accumGreenBits != GLFW_DONT_CARE && + fbconfig->accumBlueBits != GLFW_DONT_CARE && + fbconfig->accumAlphaBits != GLFW_DONT_CARE) + { + const int accumBits = fbconfig->accumRedBits + + fbconfig->accumGreenBits + + fbconfig->accumBlueBits + + fbconfig->accumAlphaBits; + + setAttrib(NSOpenGLPFAAccumSize, accumBits); + } + } + + if (fbconfig->redBits != GLFW_DONT_CARE && + fbconfig->greenBits != GLFW_DONT_CARE && + fbconfig->blueBits != GLFW_DONT_CARE) + { + int colorBits = fbconfig->redBits + + fbconfig->greenBits + + fbconfig->blueBits; + + // macOS needs non-zero color size, so set reasonable values + if (colorBits == 0) + colorBits = 24; + else if (colorBits < 15) + colorBits = 15; + + setAttrib(NSOpenGLPFAColorSize, colorBits); + } + + if (fbconfig->alphaBits != GLFW_DONT_CARE) + setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); + + if (fbconfig->depthBits != GLFW_DONT_CARE) + setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits); + + if (fbconfig->stencilBits != GLFW_DONT_CARE) + setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits); + + if (fbconfig->stereo) + { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "NSGL: Stereo rendering is deprecated"); + return GLFW_FALSE; +#else + addAttrib(NSOpenGLPFAStereo); +#endif + } + + if (fbconfig->doublebuffer) + addAttrib(NSOpenGLPFADoubleBuffer); + + if (fbconfig->samples != GLFW_DONT_CARE) + { + if (fbconfig->samples == 0) + { + setAttrib(NSOpenGLPFASampleBuffers, 0); + } + else + { + setAttrib(NSOpenGLPFASampleBuffers, 1); + setAttrib(NSOpenGLPFASamples, fbconfig->samples); + } + } + + // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB + // framebuffer, so there's no need (and no way) to request it + + addAttrib(0); + +#undef addAttrib +#undef setAttrib + + window->context.nsgl.pixelFormat = + [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; + if (window->context.nsgl.pixelFormat == nil) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "NSGL: Failed to find a suitable pixel format"); + return GLFW_FALSE; + } + + NSOpenGLContext* share = NULL; + + if (ctxconfig->share) + share = ctxconfig->share->context.nsgl.object; + + window->context.nsgl.object = + [[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat + shareContext:share]; + if (window->context.nsgl.object == nil) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: Failed to create OpenGL context"); + return GLFW_FALSE; + } + + if (fbconfig->transparent) + { + GLint opaque = 0; + [window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; + } + + [window->context.nsgl.object setView:window->ns.view]; + + window->context.makeCurrent = makeContextCurrentNSGL; + window->context.swapBuffers = swapBuffersNSGL; + window->context.swapInterval = swapIntervalNSGL; + window->context.extensionSupported = extensionSupportedNSGL; + window->context.getProcAddress = getProcAddressNSGL; + window->context.destroy = destroyContextNSGL; + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(nil); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return NULL; + } + + return window->context.nsgl.object; +} + diff --git a/src/external/glfw/src/null_init.c b/src/external/glfw/src/null_init.c new file mode 100644 index 00000000..34147388 --- /dev/null +++ b/src/external/glfw/src/null_init.c @@ -0,0 +1,50 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + _glfwInitTimerPOSIX(); + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + _glfwTerminateOSMesa(); +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " null OSMesa"; +} + diff --git a/src/external/glfw/src/null_joystick.c b/src/external/glfw/src/null_joystick.c new file mode 100644 index 00000000..afd65e15 --- /dev/null +++ b/src/external/glfw/src/null_joystick.c @@ -0,0 +1,42 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) +{ + return GLFW_FALSE; +} + +void _glfwPlatformUpdateGamepadGUID(char* guid) +{ +} + diff --git a/src/external/glfw/src/null_joystick.h b/src/external/glfw/src/null_joystick.h new file mode 100644 index 00000000..3075815d --- /dev/null +++ b/src/external/glfw/src/null_joystick.h @@ -0,0 +1,31 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define _GLFW_PLATFORM_JOYSTICK_STATE int nulljs +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int nulljs + +#define _GLFW_PLATFORM_MAPPING_NAME "" + diff --git a/src/external/glfw/src/null_monitor.c b/src/external/glfw/src/null_monitor.c new file mode 100644 index 00000000..007dd1aa --- /dev/null +++ b/src/external/glfw/src/null_monitor.c @@ -0,0 +1,64 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ +} + +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = 1.f; + if (yscale) + *yscale = 1.f; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + return NULL; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ +} + diff --git a/src/external/glfw/src/null_platform.h b/src/external/glfw/src/null_platform.h new file mode 100644 index 00000000..2d67c50c --- /dev/null +++ b/src/external/glfw/src/null_platform.h @@ -0,0 +1,62 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null + +#define _GLFW_PLATFORM_CONTEXT_STATE +#define _GLFW_PLATFORM_MONITOR_STATE +#define _GLFW_PLATFORM_CURSOR_STATE +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE +#define _GLFW_EGL_CONTEXT_STATE +#define _GLFW_EGL_LIBRARY_CONTEXT_STATE + +#include "osmesa_context.h" +#include "posix_time.h" +#include "posix_thread.h" +#include "null_joystick.h" + +#if defined(_GLFW_WIN32) + #define _glfw_dlopen(name) LoadLibraryA(name) + #define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle) + #define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name) +#else + #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) + #define _glfw_dlclose(handle) dlclose(handle) + #define _glfw_dlsym(handle, name) dlsym(handle, name) +#endif + +// Null-specific per-window data +// +typedef struct _GLFWwindowNull +{ + int width; + int height; +} _GLFWwindowNull; + diff --git a/src/external/glfw/src/null_window.c b/src/external/glfw/src/null_window.c new file mode 100644 index 00000000..3cc3905d --- /dev/null +++ b/src/external/glfw/src/null_window.c @@ -0,0 +1,307 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +static int createNativeWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig) +{ + window->null.width = wndconfig->width; + window->null.height = wndconfig->height; + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!createNativeWindow(window, wndconfig)) + return GLFW_FALSE; + + if (ctxconfig->client != GLFW_NO_API) + { + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API || + ctxconfig->source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwInitOSMesa()) + return GLFW_FALSE; + if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else + { + _glfwInputError(GLFW_API_UNAVAILABLE, "Null: EGL not available"); + return GLFW_FALSE; + } + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (window->context.destroy) + window->context.destroy(window); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, + const GLFWimage* images) +{ +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->null.width; + if (height) + *height = window->null.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + window->null.width = width; + window->null.height = height; +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d) +{ +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->null.width; + if (height) + *height = window->null.height; +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ +} + +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = 1.f; + if (yscale) + *yscale = 1.f; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + return GLFW_FALSE; +} + +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + return GLFW_FALSE; +} + +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) +{ +} + +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) +{ +} + +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) +{ +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ +} + + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ +} + +void _glfwPlatformUnhideWindow(_GLFWwindow* window) +{ +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + return GLFW_FALSE; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + return GLFW_FALSE; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + return GLFW_FALSE; +} + +void _glfwPlatformPollEvents(void) +{ +} + +void _glfwPlatformWaitEvents(void) +{ +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ +} + +void _glfwPlatformPostEmptyEvent(void) +{ +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +{ +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + return NULL; +} + +const char* _glfwPlatformGetScancodeName(int scancode) +{ + return ""; +} + +int _glfwPlatformGetKeyScancode(int key) +{ + return -1; +} + +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) +{ +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + return GLFW_FALSE; +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + // This seems like the most appropriate error to return here + return VK_ERROR_INITIALIZATION_FAILED; +} + diff --git a/src/external/glfw/src/osmesa_context.c b/src/external/glfw/src/osmesa_context.c new file mode 100644 index 00000000..a7de33f2 --- /dev/null +++ b/src/external/glfw/src/osmesa_context.c @@ -0,0 +1,370 @@ +//======================================================================== +// GLFW 3.3 OSMesa - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include +#include +#include + +#include "internal.h" + + +static void makeContextCurrentOSMesa(_GLFWwindow* window) +{ + if (window) + { + int width, height; + _glfwPlatformGetFramebufferSize(window, &width, &height); + + // Check to see if we need to allocate a new buffer + if ((window->context.osmesa.buffer == NULL) || + (width != window->context.osmesa.width) || + (height != window->context.osmesa.height)) + { + free(window->context.osmesa.buffer); + + // Allocate the new buffer (width * height * 8-bit RGBA) + window->context.osmesa.buffer = calloc(4, width * height); + window->context.osmesa.width = width; + window->context.osmesa.height = height; + } + + if (!OSMesaMakeCurrent(window->context.osmesa.handle, + window->context.osmesa.buffer, + GL_UNSIGNED_BYTE, + width, height)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OSMesa: Failed to make context current"); + return; + } + } + + _glfwPlatformSetTls(&_glfw.contextSlot, window); +} + +static GLFWglproc getProcAddressOSMesa(const char* procname) +{ + return (GLFWglproc) OSMesaGetProcAddress(procname); +} + +static void destroyContextOSMesa(_GLFWwindow* window) +{ + if (window->context.osmesa.handle) + { + OSMesaDestroyContext(window->context.osmesa.handle); + window->context.osmesa.handle = NULL; + } + + if (window->context.osmesa.buffer) + { + free(window->context.osmesa.buffer); + window->context.osmesa.width = 0; + window->context.osmesa.height = 0; + } +} + +static void swapBuffersOSMesa(_GLFWwindow* window) +{ + // No double buffering on OSMesa +} + +static void swapIntervalOSMesa(int interval) +{ + // No swap interval on OSMesa +} + +static int extensionSupportedOSMesa(const char* extension) +{ + // OSMesa does not have extensions + return GLFW_FALSE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwInitOSMesa(void) +{ + int i; + const char* sonames[] = + { +#if defined(_GLFW_OSMESA_LIBRARY) + _GLFW_OSMESA_LIBRARY, +#elif defined(_WIN32) + "libOSMesa.dll", + "OSMesa.dll", +#elif defined(__APPLE__) + "libOSMesa.8.dylib", +#elif defined(__CYGWIN__) + "libOSMesa-8.so", +#else + "libOSMesa.so.8", + "libOSMesa.so.6", +#endif + NULL + }; + + if (_glfw.osmesa.handle) + return GLFW_TRUE; + + for (i = 0; sonames[i]; i++) + { + _glfw.osmesa.handle = _glfw_dlopen(sonames[i]); + if (_glfw.osmesa.handle) + break; + } + + if (!_glfw.osmesa.handle) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found"); + return GLFW_FALSE; + } + + _glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt"); + _glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs"); + _glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext"); + _glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent"); + _glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer"); + _glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer"); + _glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress"); + + if (!_glfw.osmesa.CreateContextExt || + !_glfw.osmesa.DestroyContext || + !_glfw.osmesa.MakeCurrent || + !_glfw.osmesa.GetColorBuffer || + !_glfw.osmesa.GetDepthBuffer || + !_glfw.osmesa.GetProcAddress) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OSMesa: Failed to load required entry points"); + + _glfwTerminateOSMesa(); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwTerminateOSMesa(void) +{ + if (_glfw.osmesa.handle) + { + _glfw_dlclose(_glfw.osmesa.handle); + _glfw.osmesa.handle = NULL; + } +} + +#define setAttrib(a, v) \ +{ \ + assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[index++] = a; \ + attribs[index++] = v; \ +} + +GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + OSMesaContext share = NULL; + const int accumBits = fbconfig->accumRedBits + + fbconfig->accumGreenBits + + fbconfig->accumBlueBits + + fbconfig->accumAlphaBits; + + if (ctxconfig->client == GLFW_OPENGL_ES_API) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "OSMesa: OpenGL ES is not available on OSMesa"); + return GLFW_FALSE; + } + + if (ctxconfig->share) + share = ctxconfig->share->context.osmesa.handle; + + if (OSMesaCreateContextAttribs) + { + int index = 0, attribs[40]; + + setAttrib(OSMESA_FORMAT, OSMESA_RGBA); + setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits); + setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits); + setAttrib(OSMESA_ACCUM_BITS, accumBits); + + if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) + { + setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE); + } + else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) + { + setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); + } + + if (ctxconfig->major != 1 || ctxconfig->minor != 0) + { + setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major); + setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor); + } + + if (ctxconfig->forward) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "OSMesa: Foward-compatible contexts not supported"); + return GLFW_FALSE; + } + + setAttrib(0, 0); + + window->context.osmesa.handle = + OSMesaCreateContextAttribs(attribs, share); + } + else + { + if (ctxconfig->profile) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "OSMesa: OpenGL profiles unavailable"); + return GLFW_FALSE; + } + + window->context.osmesa.handle = + OSMesaCreateContextExt(OSMESA_RGBA, + fbconfig->depthBits, + fbconfig->stencilBits, + accumBits, + share); + } + + if (window->context.osmesa.handle == NULL) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "OSMesa: Failed to create context"); + return GLFW_FALSE; + } + + window->context.makeCurrent = makeContextCurrentOSMesa; + window->context.swapBuffers = swapBuffersOSMesa; + window->context.swapInterval = swapIntervalOSMesa; + window->context.extensionSupported = extensionSupportedOSMesa; + window->context.getProcAddress = getProcAddressOSMesa; + window->context.destroy = destroyContextOSMesa; + + return GLFW_TRUE; +} + +#undef setAttrib + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width, + int* height, int* format, void** buffer) +{ + void* mesaBuffer; + GLint mesaWidth, mesaHeight, mesaFormat; + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + if (!OSMesaGetColorBuffer(window->context.osmesa.handle, + &mesaWidth, &mesaHeight, + &mesaFormat, &mesaBuffer)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OSMesa: Failed to retrieve color buffer"); + return GLFW_FALSE; + } + + if (width) + *width = mesaWidth; + if (height) + *height = mesaHeight; + if (format) + *format = mesaFormat; + if (buffer) + *buffer = mesaBuffer; + + return GLFW_TRUE; +} + +GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle, + int* width, int* height, + int* bytesPerValue, + void** buffer) +{ + void* mesaBuffer; + GLint mesaWidth, mesaHeight, mesaBytes; + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + if (!OSMesaGetDepthBuffer(window->context.osmesa.handle, + &mesaWidth, &mesaHeight, + &mesaBytes, &mesaBuffer)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OSMesa: Failed to retrieve depth buffer"); + return GLFW_FALSE; + } + + if (width) + *width = mesaWidth; + if (height) + *height = mesaHeight; + if (bytesPerValue) + *bytesPerValue = mesaBytes; + if (buffer) + *buffer = mesaBuffer; + + return GLFW_TRUE; +} + +GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return NULL; + } + + return window->context.osmesa.handle; +} + diff --git a/src/external/glfw/src/osmesa_context.h b/src/external/glfw/src/osmesa_context.h new file mode 100644 index 00000000..e6ae5781 --- /dev/null +++ b/src/external/glfw/src/osmesa_context.h @@ -0,0 +1,94 @@ +//======================================================================== +// GLFW 3.3 OSMesa - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define OSMESA_RGBA 0x1908 +#define OSMESA_FORMAT 0x22 +#define OSMESA_DEPTH_BITS 0x30 +#define OSMESA_STENCIL_BITS 0x31 +#define OSMESA_ACCUM_BITS 0x32 +#define OSMESA_PROFILE 0x33 +#define OSMESA_CORE_PROFILE 0x34 +#define OSMESA_COMPAT_PROFILE 0x35 +#define OSMESA_CONTEXT_MAJOR_VERSION 0x36 +#define OSMESA_CONTEXT_MINOR_VERSION 0x37 + +typedef void* OSMesaContext; +typedef void (*OSMESAproc)(); + +typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext); +typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext); +typedef void (GLAPIENTRY * PFN_OSMesaDestroyContext)(OSMesaContext); +typedef int (GLAPIENTRY * PFN_OSMesaMakeCurrent)(OSMesaContext,void*,int,int,int); +typedef int (GLAPIENTRY * PFN_OSMesaGetColorBuffer)(OSMesaContext,int*,int*,int*,void**); +typedef int (GLAPIENTRY * PFN_OSMesaGetDepthBuffer)(OSMesaContext,int*,int*,int*,void**); +typedef GLFWglproc (GLAPIENTRY * PFN_OSMesaGetProcAddress)(const char*); +#define OSMesaCreateContextExt _glfw.osmesa.CreateContextExt +#define OSMesaCreateContextAttribs _glfw.osmesa.CreateContextAttribs +#define OSMesaDestroyContext _glfw.osmesa.DestroyContext +#define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent +#define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer +#define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer +#define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress + +#define _GLFW_OSMESA_CONTEXT_STATE _GLFWcontextOSMesa osmesa +#define _GLFW_OSMESA_LIBRARY_CONTEXT_STATE _GLFWlibraryOSMesa osmesa + + +// OSMesa-specific per-context data +// +typedef struct _GLFWcontextOSMesa +{ + OSMesaContext handle; + int width; + int height; + void* buffer; + +} _GLFWcontextOSMesa; + +// OSMesa-specific global data +// +typedef struct _GLFWlibraryOSMesa +{ + void* handle; + + PFN_OSMesaCreateContextExt CreateContextExt; + PFN_OSMesaCreateContextAttribs CreateContextAttribs; + PFN_OSMesaDestroyContext DestroyContext; + PFN_OSMesaMakeCurrent MakeCurrent; + PFN_OSMesaGetColorBuffer GetColorBuffer; + PFN_OSMesaGetDepthBuffer GetDepthBuffer; + PFN_OSMesaGetProcAddress GetProcAddress; + +} _GLFWlibraryOSMesa; + + +GLFWbool _glfwInitOSMesa(void); +void _glfwTerminateOSMesa(void); +GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); + diff --git a/src/external/glfw/src/posix_thread.c b/src/external/glfw/src/posix_thread.c new file mode 100644 index 00000000..ce0bc39b --- /dev/null +++ b/src/external/glfw/src/posix_thread.c @@ -0,0 +1,103 @@ +//======================================================================== +// GLFW 3.3 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) +{ + assert(tls->posix.allocated == GLFW_FALSE); + + if (pthread_key_create(&tls->posix.key, NULL) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "POSIX: Failed to create context TLS"); + return GLFW_FALSE; + } + + tls->posix.allocated = GLFW_TRUE; + return GLFW_TRUE; +} + +void _glfwPlatformDestroyTls(_GLFWtls* tls) +{ + if (tls->posix.allocated) + pthread_key_delete(tls->posix.key); + memset(tls, 0, sizeof(_GLFWtls)); +} + +void* _glfwPlatformGetTls(_GLFWtls* tls) +{ + assert(tls->posix.allocated == GLFW_TRUE); + return pthread_getspecific(tls->posix.key); +} + +void _glfwPlatformSetTls(_GLFWtls* tls, void* value) +{ + assert(tls->posix.allocated == GLFW_TRUE); + pthread_setspecific(tls->posix.key, value); +} + +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex) +{ + assert(mutex->posix.allocated == GLFW_FALSE); + + if (pthread_mutex_init(&mutex->posix.handle, NULL) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "POSIX: Failed to create mutex"); + return GLFW_FALSE; + } + + return mutex->posix.allocated = GLFW_TRUE; +} + +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex) +{ + if (mutex->posix.allocated) + pthread_mutex_destroy(&mutex->posix.handle); + memset(mutex, 0, sizeof(_GLFWmutex)); +} + +void _glfwPlatformLockMutex(_GLFWmutex* mutex) +{ + assert(mutex->posix.allocated == GLFW_TRUE); + pthread_mutex_lock(&mutex->posix.handle); +} + +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) +{ + assert(mutex->posix.allocated == GLFW_TRUE); + pthread_mutex_unlock(&mutex->posix.handle); +} + diff --git a/src/external/glfw/src/posix_thread.h b/src/external/glfw/src/posix_thread.h new file mode 100644 index 00000000..bdddf41a --- /dev/null +++ b/src/external/glfw/src/posix_thread.h @@ -0,0 +1,51 @@ +//======================================================================== +// GLFW 3.3 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include + +#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix +#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix + + +// POSIX-specific thread local storage data +// +typedef struct _GLFWtlsPOSIX +{ + GLFWbool allocated; + pthread_key_t key; + +} _GLFWtlsPOSIX; + +// POSIX-specific mutex data +// +typedef struct _GLFWmutexPOSIX +{ + GLFWbool allocated; + pthread_mutex_t handle; + +} _GLFWmutexPOSIX; + diff --git a/src/external/glfw/src/posix_time.c b/src/external/glfw/src/posix_time.c new file mode 100644 index 00000000..00b2831d --- /dev/null +++ b/src/external/glfw/src/posix_time.c @@ -0,0 +1,85 @@ +//======================================================================== +// GLFW 3.3 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimerPOSIX(void) +{ +#if defined(CLOCK_MONOTONIC) + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + { + _glfw.timer.posix.monotonic = GLFW_TRUE; + _glfw.timer.posix.frequency = 1000000000; + } + else +#endif + { + _glfw.timer.posix.monotonic = GLFW_FALSE; + _glfw.timer.posix.frequency = 1000000; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +uint64_t _glfwPlatformGetTimerValue(void) +{ +#if defined(CLOCK_MONOTONIC) + if (_glfw.timer.posix.monotonic) + { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec; + } + else +#endif + { + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; + } +} + +uint64_t _glfwPlatformGetTimerFrequency(void) +{ + return _glfw.timer.posix.frequency; +} + diff --git a/src/external/glfw/src/posix_time.h b/src/external/glfw/src/posix_time.h new file mode 100644 index 00000000..f1a69eb2 --- /dev/null +++ b/src/external/glfw/src/posix_time.h @@ -0,0 +1,44 @@ +//======================================================================== +// GLFW 3.3 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix + +#include + + +// POSIX-specific global timer data +// +typedef struct _GLFWtimerPOSIX +{ + GLFWbool monotonic; + uint64_t frequency; + +} _GLFWtimerPOSIX; + + +void _glfwInitTimerPOSIX(void); + diff --git a/src/external/glfw/src/vulkan.c b/src/external/glfw/src/vulkan.c new file mode 100644 index 00000000..1fd15fad --- /dev/null +++ b/src/external/glfw/src/vulkan.c @@ -0,0 +1,322 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + +#define _GLFW_FIND_LOADER 1 +#define _GLFW_REQUIRE_LOADER 2 + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwInitVulkan(int mode) +{ + VkResult err; + VkExtensionProperties* ep; + uint32_t i, count; + + if (_glfw.vk.available) + return GLFW_TRUE; + +#if !defined(_GLFW_VULKAN_STATIC) +#if defined(_GLFW_VULKAN_LIBRARY) + _glfw.vk.handle = _glfw_dlopen(_GLFW_VULKAN_LIBRARY); +#elif defined(_GLFW_WIN32) + _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll"); +#elif defined(_GLFW_COCOA) + _glfw.vk.handle = _glfw_dlopen("libMoltenVK.dylib"); +#else + _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1"); +#endif + if (!_glfw.vk.handle) + { + if (mode == _GLFW_REQUIRE_LOADER) + _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found"); + + return GLFW_FALSE; + } + + _glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) + _glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr"); + if (!_glfw.vk.GetInstanceProcAddr) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Loader does not export vkGetInstanceProcAddr"); + + _glfwTerminateVulkan(); + return GLFW_FALSE; + } + + _glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) + vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); + if (!_glfw.vk.EnumerateInstanceExtensionProperties) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties"); + + _glfwTerminateVulkan(); + return GLFW_FALSE; + } +#endif // _GLFW_VULKAN_STATIC + + err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); + if (err) + { + // NOTE: This happens on systems with a loader but without any Vulkan ICD + if (mode == _GLFW_REQUIRE_LOADER) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Failed to query instance extension count: %s", + _glfwGetVulkanResultString(err)); + } + + _glfwTerminateVulkan(); + return GLFW_FALSE; + } + + ep = calloc(count, sizeof(VkExtensionProperties)); + + err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep); + if (err) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Failed to query instance extensions: %s", + _glfwGetVulkanResultString(err)); + + free(ep); + _glfwTerminateVulkan(); + return GLFW_FALSE; + } + + for (i = 0; i < count; i++) + { + if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0) + _glfw.vk.KHR_surface = GLFW_TRUE; +#if defined(_GLFW_WIN32) + else if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0) + _glfw.vk.KHR_win32_surface = GLFW_TRUE; +#elif defined(_GLFW_COCOA) + else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0) + _glfw.vk.MVK_macos_surface = GLFW_TRUE; +#elif defined(_GLFW_X11) + else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0) + _glfw.vk.KHR_xlib_surface = GLFW_TRUE; + else if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0) + _glfw.vk.KHR_xcb_surface = GLFW_TRUE; +#elif defined(_GLFW_WAYLAND) + else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0) + _glfw.vk.KHR_wayland_surface = GLFW_TRUE; +#elif defined(_GLFW_MIR) + else if (strcmp(ep[i].extensionName, "VK_KHR_mir_surface") == 0) + _glfw.vk.KHR_mir_surface = GLFW_TRUE; +#endif + } + + free(ep); + + _glfw.vk.available = GLFW_TRUE; + + _glfwPlatformGetRequiredInstanceExtensions(_glfw.vk.extensions); + + return GLFW_TRUE; +} + +void _glfwTerminateVulkan(void) +{ +#if !defined(_GLFW_VULKAN_STATIC) + if (_glfw.vk.handle) + _glfw_dlclose(_glfw.vk.handle); +#endif +} + +const char* _glfwGetVulkanResultString(VkResult result) +{ + switch (result) + { + case VK_SUCCESS: + return "Success"; + case VK_NOT_READY: + return "A fence or query has not yet completed"; + case VK_TIMEOUT: + return "A wait operation has not completed in the specified time"; + case VK_EVENT_SET: + return "An event is signaled"; + case VK_EVENT_RESET: + return "An event is unsignaled"; + case VK_INCOMPLETE: + return "A return array was too small for the result"; + case VK_ERROR_OUT_OF_HOST_MEMORY: + return "A host memory allocation has failed"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + return "A device memory allocation has failed"; + case VK_ERROR_INITIALIZATION_FAILED: + return "Initialization of an object could not be completed for implementation-specific reasons"; + case VK_ERROR_DEVICE_LOST: + return "The logical or physical device has been lost"; + case VK_ERROR_MEMORY_MAP_FAILED: + return "Mapping of a memory object has failed"; + case VK_ERROR_LAYER_NOT_PRESENT: + return "A requested layer is not present or could not be loaded"; + case VK_ERROR_EXTENSION_NOT_PRESENT: + return "A requested extension is not supported"; + case VK_ERROR_FEATURE_NOT_PRESENT: + return "A requested feature is not supported"; + case VK_ERROR_INCOMPATIBLE_DRIVER: + return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible"; + case VK_ERROR_TOO_MANY_OBJECTS: + return "Too many objects of the type have already been created"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: + return "A requested format is not supported on this device"; + case VK_ERROR_SURFACE_LOST_KHR: + return "A surface is no longer available"; + case VK_SUBOPTIMAL_KHR: + return "A swapchain no longer matches the surface properties exactly, but can still be used"; + case VK_ERROR_OUT_OF_DATE_KHR: + return "A surface has changed in such a way that it is no longer compatible with the swapchain"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: + return "The display used by a swapchain does not use the same presentable image layout"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: + return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API"; + case VK_ERROR_VALIDATION_FAILED_EXT: + return "A validation layer found an error"; + default: + return "ERROR: UNKNOWN VULKAN ERROR"; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwVulkanSupported(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + return _glfwInitVulkan(_GLFW_FIND_LOADER); +} + +GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count) +{ + assert(count != NULL); + + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) + return NULL; + + if (!_glfw.vk.extensions[0]) + return NULL; + + *count = 2; + return (const char**) _glfw.vk.extensions; +} + +GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, + const char* procname) +{ + GLFWvkproc proc; + assert(procname != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) + return NULL; + + proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname); +#if defined(_GLFW_VULKAN_STATIC) + if (!proc) + { + if (strcmp(procname, "vkGetInstanceProcAddr") == 0) + return (GLFWvkproc) vkGetInstanceProcAddr; + } +#else + if (!proc) + proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname); +#endif + + return proc; +} + +GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + assert(instance != VK_NULL_HANDLE); + assert(device != VK_NULL_HANDLE); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) + return GLFW_FALSE; + + if (!_glfw.vk.extensions[0]) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Window surface creation extensions not found"); + return GLFW_FALSE; + } + + return _glfwPlatformGetPhysicalDevicePresentationSupport(instance, + device, + queuefamily); +} + +GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, + GLFWwindow* handle, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(instance != VK_NULL_HANDLE); + assert(window != NULL); + assert(surface != NULL); + + *surface = VK_NULL_HANDLE; + + _GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED); + + if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) + return VK_ERROR_INITIALIZATION_FAILED; + + if (!_glfw.vk.extensions[0]) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Window surface creation extensions not found"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface); +} + diff --git a/src/external/glfw/src/wgl_context.c b/src/external/glfw/src/wgl_context.c new file mode 100644 index 00000000..d864a47c --- /dev/null +++ b/src/external/glfw/src/wgl_context.c @@ -0,0 +1,731 @@ +//======================================================================== +// GLFW 3.3 WGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + + +// Returns the specified attribute of the specified pixel format +// +static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib) +{ + int value = 0; + + assert(_glfw.wgl.ARB_pixel_format); + + if (!_glfw.wgl.GetPixelFormatAttribivARB(window->context.wgl.dc, + pixelFormat, + 0, 1, &attrib, &value)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve pixel format attribute"); + return 0; + } + + return value; +} + +// Return a list of available and usable framebuffer configs +// +static int choosePixelFormat(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + _GLFWfbconfig* usableConfigs; + const _GLFWfbconfig* closest; + int i, pixelFormat, nativeCount, usableCount; + + if (_glfw.wgl.ARB_pixel_format) + { + nativeCount = getPixelFormatAttrib(window, + 1, + WGL_NUMBER_PIXEL_FORMATS_ARB); + } + else + { + nativeCount = DescribePixelFormat(window->context.wgl.dc, + 1, + sizeof(PIXELFORMATDESCRIPTOR), + NULL); + } + + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableCount = 0; + + for (i = 0; i < nativeCount; i++) + { + const int n = i + 1; + _GLFWfbconfig* u = usableConfigs + usableCount; + + if (_glfw.wgl.ARB_pixel_format) + { + // Get pixel format attributes through "modern" extension + + if (!getPixelFormatAttrib(window, n, WGL_SUPPORT_OPENGL_ARB) || + !getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB)) + { + continue; + } + + if (getPixelFormatAttrib(window, n, WGL_PIXEL_TYPE_ARB) != + WGL_TYPE_RGBA_ARB) + { + continue; + } + + if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) == + WGL_NO_ACCELERATION_ARB) + { + continue; + } + + u->redBits = getPixelFormatAttrib(window, n, WGL_RED_BITS_ARB); + u->greenBits = getPixelFormatAttrib(window, n, WGL_GREEN_BITS_ARB); + u->blueBits = getPixelFormatAttrib(window, n, WGL_BLUE_BITS_ARB); + u->alphaBits = getPixelFormatAttrib(window, n, WGL_ALPHA_BITS_ARB); + + u->depthBits = getPixelFormatAttrib(window, n, WGL_DEPTH_BITS_ARB); + u->stencilBits = getPixelFormatAttrib(window, n, WGL_STENCIL_BITS_ARB); + + u->accumRedBits = getPixelFormatAttrib(window, n, WGL_ACCUM_RED_BITS_ARB); + u->accumGreenBits = getPixelFormatAttrib(window, n, WGL_ACCUM_GREEN_BITS_ARB); + u->accumBlueBits = getPixelFormatAttrib(window, n, WGL_ACCUM_BLUE_BITS_ARB); + u->accumAlphaBits = getPixelFormatAttrib(window, n, WGL_ACCUM_ALPHA_BITS_ARB); + + u->auxBuffers = getPixelFormatAttrib(window, n, WGL_AUX_BUFFERS_ARB); + + if (getPixelFormatAttrib(window, n, WGL_STEREO_ARB)) + u->stereo = GLFW_TRUE; + if (getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB)) + u->doublebuffer = GLFW_TRUE; + + if (_glfw.wgl.ARB_multisample) + u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB); + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if (_glfw.wgl.ARB_framebuffer_sRGB || + _glfw.wgl.EXT_framebuffer_sRGB) + { + if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) + u->sRGB = GLFW_TRUE; + } + } + else + { + if (_glfw.wgl.EXT_colorspace) + { + if (getPixelFormatAttrib(window, n, WGL_COLORSPACE_EXT) == + WGL_COLORSPACE_SRGB_EXT) + { + u->sRGB = GLFW_TRUE; + } + } + } + } + else + { + // Get pixel format attributes through legacy PFDs + + PIXELFORMATDESCRIPTOR pfd; + + if (!DescribePixelFormat(window->context.wgl.dc, + n, + sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + continue; + } + + if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || + !(pfd.dwFlags & PFD_SUPPORT_OPENGL)) + { + continue; + } + + if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && + (pfd.dwFlags & PFD_GENERIC_FORMAT)) + { + continue; + } + + if (pfd.iPixelType != PFD_TYPE_RGBA) + continue; + + u->redBits = pfd.cRedBits; + u->greenBits = pfd.cGreenBits; + u->blueBits = pfd.cBlueBits; + u->alphaBits = pfd.cAlphaBits; + + u->depthBits = pfd.cDepthBits; + u->stencilBits = pfd.cStencilBits; + + u->accumRedBits = pfd.cAccumRedBits; + u->accumGreenBits = pfd.cAccumGreenBits; + u->accumBlueBits = pfd.cAccumBlueBits; + u->accumAlphaBits = pfd.cAccumAlphaBits; + + u->auxBuffers = pfd.cAuxBuffers; + + if (pfd.dwFlags & PFD_STEREO) + u->stereo = GLFW_TRUE; + if (pfd.dwFlags & PFD_DOUBLEBUFFER) + u->doublebuffer = GLFW_TRUE; + } + + u->handle = n; + usableCount++; + } + + if (!usableCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "WGL: The driver does not appear to support OpenGL"); + + free(usableConfigs); + return 0; + } + + closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount); + if (!closest) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "WGL: Failed to find a suitable pixel format"); + + free(usableConfigs); + return 0; + } + + pixelFormat = (int) closest->handle; + free(usableConfigs); + + return pixelFormat; +} + +static void makeContextCurrentWGL(_GLFWwindow* window) +{ + if (window) + { + if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) + _glfwPlatformSetTls(&_glfw.contextSlot, window); + else + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to make context current"); + _glfwPlatformSetTls(&_glfw.contextSlot, NULL); + } + } + else + { + if (!wglMakeCurrent(NULL, NULL)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to clear current context"); + } + + _glfwPlatformSetTls(&_glfw.contextSlot, NULL); + } +} + +static void swapBuffersWGL(_GLFWwindow* window) +{ + // HACK: Use DwmFlush when desktop composition is enabled + if (_glfwIsCompositionEnabledWin32() && !window->monitor) + { + int count = abs(window->context.wgl.interval); + while (count--) + DwmFlush(); + } + + SwapBuffers(window->context.wgl.dc); +} + +static void swapIntervalWGL(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + + window->context.wgl.interval = interval; + + // HACK: Disable WGL swap interval when desktop composition is enabled to + // avoid interfering with DWM vsync + if (_glfwIsCompositionEnabledWin32() && !window->monitor) + interval = 0; + + if (_glfw.wgl.EXT_swap_control) + _glfw.wgl.SwapIntervalEXT(interval); +} + +static int extensionSupportedWGL(const char* extension) +{ + const char* extensions; + + if (_glfw.wgl.GetExtensionsStringEXT) + { + extensions = _glfw.wgl.GetExtensionsStringEXT(); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + } + + if (_glfw.wgl.GetExtensionsStringARB) + { + extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC()); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddressWGL(const char* procname) +{ + const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname); + if (proc) + return proc; + + return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname); +} + +// Destroy the OpenGL context +// +static void destroyContextWGL(_GLFWwindow* window) +{ + if (window->context.wgl.handle) + { + wglDeleteContext(window->context.wgl.handle); + window->context.wgl.handle = NULL; + } +} + +// Initialize WGL-specific extensions +// +static void loadWGLExtensions(void) +{ + PIXELFORMATDESCRIPTOR pfd; + HGLRC rc; + HDC dc = GetDC(_glfw.win32.helperWindowHandle);; + + _glfw.wgl.extensionsLoaded = GLFW_TRUE; + + // NOTE: A dummy context has to be created for opengl32.dll to load the + // OpenGL ICD, from which we can then query WGL extensions + // NOTE: This code will accept the Microsoft GDI ICD; accelerated context + // creation failure occurs during manual pixel format enumeration + + ZeroMemory(&pfd, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + + if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to set pixel format for dummy context"); + return; + } + + rc = wglCreateContext(dc); + if (!rc) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to create dummy context"); + return; + } + + if (!wglMakeCurrent(dc, rc)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to make dummy context current"); + wglDeleteContext(rc); + return; + } + + // NOTE: Functions must be loaded first as they're needed to retrieve the + // extension string that tells us whether the functions are supported + _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) + wglGetProcAddress("wglGetExtensionsStringEXT"); + _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) + wglGetProcAddress("wglGetExtensionsStringARB"); + _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) + wglGetProcAddress("wglCreateContextAttribsARB"); + _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) + wglGetProcAddress("wglSwapIntervalEXT"); + _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) + wglGetProcAddress("wglGetPixelFormatAttribivARB"); + + // NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not + // checked below as we are already using them + _glfw.wgl.ARB_multisample = + extensionSupportedWGL("WGL_ARB_multisample"); + _glfw.wgl.ARB_framebuffer_sRGB = + extensionSupportedWGL("WGL_ARB_framebuffer_sRGB"); + _glfw.wgl.EXT_framebuffer_sRGB = + extensionSupportedWGL("WGL_EXT_framebuffer_sRGB"); + _glfw.wgl.ARB_create_context = + extensionSupportedWGL("WGL_ARB_create_context"); + _glfw.wgl.ARB_create_context_profile = + extensionSupportedWGL("WGL_ARB_create_context_profile"); + _glfw.wgl.EXT_create_context_es2_profile = + extensionSupportedWGL("WGL_EXT_create_context_es2_profile"); + _glfw.wgl.ARB_create_context_robustness = + extensionSupportedWGL("WGL_ARB_create_context_robustness"); + _glfw.wgl.ARB_create_context_no_error = + extensionSupportedWGL("WGL_ARB_create_context_no_error"); + _glfw.wgl.EXT_swap_control = + extensionSupportedWGL("WGL_EXT_swap_control"); + _glfw.wgl.EXT_colorspace = + extensionSupportedWGL("WGL_EXT_colorspace"); + _glfw.wgl.ARB_pixel_format = + extensionSupportedWGL("WGL_ARB_pixel_format"); + _glfw.wgl.ARB_context_flush_control = + extensionSupportedWGL("WGL_ARB_context_flush_control"); + + wglMakeCurrent(dc, NULL); + wglDeleteContext(rc); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize WGL +// +GLFWbool _glfwInitWGL(void) +{ + if (_glfw.wgl.instance) + return GLFW_TRUE; + + _glfw.wgl.instance = LoadLibraryA("opengl32.dll"); + if (!_glfw.wgl.instance) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to load opengl32.dll"); + return GLFW_FALSE; + } + + _glfw.wgl.CreateContext = (PFN_wglCreateContext) + GetProcAddress(_glfw.wgl.instance, "wglCreateContext"); + _glfw.wgl.DeleteContext = (PFN_wglDeleteContext) + GetProcAddress(_glfw.wgl.instance, "wglDeleteContext"); + _glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress) + GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress"); + _glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC) + GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC"); + _glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent) + GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent"); + _glfw.wgl.ShareLists = (PFN_wglShareLists) + GetProcAddress(_glfw.wgl.instance, "wglShareLists"); + + return GLFW_TRUE; +} + +// Terminate WGL +// +void _glfwTerminateWGL(void) +{ + if (_glfw.wgl.instance) + FreeLibrary(_glfw.wgl.instance); +} + +#define setAttrib(a, v) \ +{ \ + assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[index++] = a; \ + attribs[index++] = v; \ +} + +// Create the OpenGL or OpenGL ES context +// +GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + int attribs[40]; + int pixelFormat; + PIXELFORMATDESCRIPTOR pfd; + HGLRC share = NULL; + + if (!_glfw.wgl.extensionsLoaded) + loadWGLExtensions(); + + if (ctxconfig->share) + share = ctxconfig->share->context.wgl.handle; + + window->context.wgl.dc = GetDC(window->win32.handle); + if (!window->context.wgl.dc) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve DC for window"); + return GLFW_FALSE; + } + + pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig); + if (!pixelFormat) + return GLFW_FALSE; + + if (!DescribePixelFormat(window->context.wgl.dc, + pixelFormat, sizeof(pfd), &pfd)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve PFD for selected pixel format"); + return GLFW_FALSE; + } + + if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to set selected pixel format"); + return GLFW_FALSE; + } + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if (ctxconfig->forward) + { + if (!_glfw.wgl.ARB_create_context) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable"); + return GLFW_FALSE; + } + } + + if (ctxconfig->profile) + { + if (!_glfw.wgl.ARB_create_context_profile) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable"); + return GLFW_FALSE; + } + } + } + else + { + if (!_glfw.wgl.ARB_create_context || + !_glfw.wgl.ARB_create_context_profile || + !_glfw.wgl.EXT_create_context_es2_profile) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable"); + return GLFW_FALSE; + } + } + + if (_glfw.wgl.ARB_create_context) + { + int index = 0, mask = 0, flags = 0; + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if (ctxconfig->forward) + flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) + mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } + else + mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT; + + if (ctxconfig->debug) + flags |= WGL_CONTEXT_DEBUG_BIT_ARB; + + if (ctxconfig->robustness) + { + if (_glfw.wgl.ARB_create_context_robustness) + { + if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) + { + setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_NO_RESET_NOTIFICATION_ARB); + } + else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) + { + setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_LOSE_CONTEXT_ON_RESET_ARB); + } + + flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + } + + if (ctxconfig->release) + { + if (_glfw.wgl.ARB_context_flush_control) + { + if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + } + else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + } + } + } + + if (ctxconfig->noerror) + { + if (_glfw.wgl.ARB_create_context_no_error) + setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + } + + // NOTE: Only request an explicitly versioned context when necessary, as + // explicitly requesting version 1.0 does not always return the + // highest version supported by the driver + if (ctxconfig->major != 1 || ctxconfig->minor != 0) + { + setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + } + + if (flags) + setAttrib(WGL_CONTEXT_FLAGS_ARB, flags); + + if (mask) + setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); + + setAttrib(0, 0); + + window->context.wgl.handle = + _glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc, + share, attribs); + if (!window->context.wgl.handle) + { + const DWORD error = GetLastError(); + + if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) + { + if (ctxconfig->client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Driver does not support OpenGL version %i.%i", + ctxconfig->major, + ctxconfig->minor); + } + else + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Driver does not support OpenGL ES version %i.%i", + ctxconfig->major, + ctxconfig->minor); + } + } + else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Driver does not support the requested OpenGL profile"); + } + else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "WGL: The share context is not compatible with the requested context"); + } + else + { + if (ctxconfig->client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Failed to create OpenGL context"); + } + else + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Failed to create OpenGL ES context"); + } + } + + return GLFW_FALSE; + } + } + else + { + window->context.wgl.handle = wglCreateContext(window->context.wgl.dc); + if (!window->context.wgl.handle) + { + _glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE, + "WGL: Failed to create OpenGL context"); + return GLFW_FALSE; + } + + if (share) + { + if (!wglShareLists(share, window->context.wgl.handle)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to enable sharing with specified OpenGL context"); + return GLFW_FALSE; + } + } + } + + window->context.makeCurrent = makeContextCurrentWGL; + window->context.swapBuffers = swapBuffersWGL; + window->context.swapInterval = swapIntervalWGL; + window->context.extensionSupported = extensionSupportedWGL; + window->context.getProcAddress = getProcAddressWGL; + window->context.destroy = destroyContextWGL; + + return GLFW_TRUE; +} + +#undef setAttrib + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (window->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return NULL; + } + + return window->context.wgl.handle; +} + diff --git a/src/external/glfw/src/wgl_context.h b/src/external/glfw/src/wgl_context.h new file mode 100644 index 00000000..9fae9114 --- /dev/null +++ b/src/external/glfw/src/wgl_context.h @@ -0,0 +1,158 @@ +//======================================================================== +// GLFW 3.3 WGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_TYPE_RGBA_ARB 0x202b +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201a +#define WGL_ALPHA_BITS_ARB 0x201b +#define WGL_ALPHA_SHIFT_ARB 0x201c +#define WGL_ACCUM_BITS_ARB 0x201d +#define WGL_ACCUM_RED_BITS_ARB 0x201e +#define WGL_ACCUM_GREEN_BITS_ARB 0x201f +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_STEREO_ARB 0x2012 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_SAMPLES_ARB 0x2042 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 +#define WGL_COLORSPACE_EXT 0x309d +#define WGL_COLORSPACE_SRGB_EXT 0x3089 + +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 + +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*); +typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void); +typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC); +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*); + +typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC); +typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC); +typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR); +typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void); +typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC); +typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC); + +// opengl32.dll function pointer typedefs +#define wglCreateContext _glfw.wgl.CreateContext +#define wglDeleteContext _glfw.wgl.DeleteContext +#define wglGetProcAddress _glfw.wgl.GetProcAddress +#define wglGetCurrentDC _glfw.wgl.GetCurrentDC +#define wglMakeCurrent _glfw.wgl.MakeCurrent +#define wglShareLists _glfw.wgl.ShareLists + +#define _GLFW_RECREATION_NOT_NEEDED 0 +#define _GLFW_RECREATION_REQUIRED 1 +#define _GLFW_RECREATION_IMPOSSIBLE 2 + +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl + + +// WGL-specific per-context data +// +typedef struct _GLFWcontextWGL +{ + HDC dc; + HGLRC handle; + int interval; + +} _GLFWcontextWGL; + +// WGL-specific global data +// +typedef struct _GLFWlibraryWGL +{ + HINSTANCE instance; + PFN_wglCreateContext CreateContext; + PFN_wglDeleteContext DeleteContext; + PFN_wglGetProcAddress GetProcAddress; + PFN_wglGetCurrentDC GetCurrentDC; + PFN_wglMakeCurrent MakeCurrent; + PFN_wglShareLists ShareLists; + + GLFWbool extensionsLoaded; + + PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; + PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB; + PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; + PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; + PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLFWbool EXT_swap_control; + GLFWbool EXT_colorspace; + GLFWbool ARB_multisample; + GLFWbool ARB_framebuffer_sRGB; + GLFWbool EXT_framebuffer_sRGB; + GLFWbool ARB_pixel_format; + GLFWbool ARB_create_context; + GLFWbool ARB_create_context_profile; + GLFWbool EXT_create_context_es2_profile; + GLFWbool ARB_create_context_robustness; + GLFWbool ARB_create_context_no_error; + GLFWbool ARB_context_flush_control; + +} _GLFWlibraryWGL; + + +GLFWbool _glfwInitWGL(void); +void _glfwTerminateWGL(void); +GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); + diff --git a/src/external/glfw/src/win32_init.c b/src/external/glfw/src/win32_init.c new file mode 100644 index 00000000..ee7ccfda --- /dev/null +++ b/src/external/glfw/src/win32_init.c @@ -0,0 +1,583 @@ +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + +static const GUID _glfw_GUID_DEVINTERFACE_HID = + {0x4d1e55b2,0xf16f,0x11cf,{0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}}; + +#define GUID_DEVINTERFACE_HID _glfw_GUID_DEVINTERFACE_HID + +#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) + +// Executables (but not DLLs) exporting this symbol with this value will be +// automatically directed to the high-performance GPU on Nvidia Optimus systems +// with up-to-date drivers +// +__declspec(dllexport) DWORD NvOptimusEnablement = 1; + +// Executables (but not DLLs) exporting this symbol with this value will be +// automatically directed to the high-performance GPU on AMD PowerXpress systems +// with up-to-date drivers +// +__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; + +#endif // _GLFW_USE_HYBRID_HPG + +#if defined(_GLFW_BUILD_DLL) + +// GLFW DLL entry point +// +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + return TRUE; +} + +#endif // _GLFW_BUILD_DLL + +// HACK: Define versionhelpers.h functions manually as MinGW lacks the header +BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) +{ + OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp }; + DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR; + ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + return VerifyVersionInfoW(&osvi, mask, cond); +} + +// Load necessary libraries (DLLs) +// +static GLFWbool loadLibraries(void) +{ + _glfw.win32.winmm.instance = LoadLibraryA("winmm.dll"); + if (!_glfw.win32.winmm.instance) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to load winmm.dll"); + return GLFW_FALSE; + } + + _glfw.win32.winmm.GetTime = (PFN_timeGetTime) + GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime"); + + _glfw.win32.user32.instance = LoadLibraryA("user32.dll"); + if (!_glfw.win32.user32.instance) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to load user32.dll"); + return GLFW_FALSE; + } + + _glfw.win32.user32.SetProcessDPIAware_ = (PFN_SetProcessDPIAware) + GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); + _glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx) + GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); + + _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll"); + if (_glfw.win32.dinput8.instance) + { + _glfw.win32.dinput8.Create = (PFN_DirectInput8Create) + GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create"); + } + + { + int i; + const char* names[] = + { + "xinput1_4.dll", + "xinput1_3.dll", + "xinput9_1_0.dll", + "xinput1_2.dll", + "xinput1_1.dll", + NULL + }; + + for (i = 0; names[i]; i++) + { + _glfw.win32.xinput.instance = LoadLibraryA(names[i]); + if (_glfw.win32.xinput.instance) + { + _glfw.win32.xinput.GetCapabilities = (PFN_XInputGetCapabilities) + GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities"); + _glfw.win32.xinput.GetState = (PFN_XInputGetState) + GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState"); + + break; + } + } + } + + _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll"); + if (_glfw.win32.dwmapi.instance) + { + _glfw.win32.dwmapi.IsCompositionEnabled = (PFN_DwmIsCompositionEnabled) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); + _glfw.win32.dwmapi.Flush = (PFN_DwmFlush) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); + _glfw.win32.dwmapi.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow"); + } + + _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll"); + if (_glfw.win32.shcore.instance) + { + _glfw.win32.shcore.SetProcessDpiAwareness_ = (PFN_SetProcessDpiAwareness) + GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness"); + _glfw.win32.shcore.GetDpiForMonitor_ = (PFN_GetDpiForMonitor) + GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor"); + } + + return GLFW_TRUE; +} + +// Unload used libraries (DLLs) +// +static void freeLibraries(void) +{ + if (_glfw.win32.xinput.instance) + FreeLibrary(_glfw.win32.xinput.instance); + + if (_glfw.win32.dinput8.instance) + FreeLibrary(_glfw.win32.dinput8.instance); + + if (_glfw.win32.winmm.instance) + FreeLibrary(_glfw.win32.winmm.instance); + + if (_glfw.win32.user32.instance) + FreeLibrary(_glfw.win32.user32.instance); + + if (_glfw.win32.dwmapi.instance) + FreeLibrary(_glfw.win32.dwmapi.instance); + + if (_glfw.win32.shcore.instance) + FreeLibrary(_glfw.win32.shcore.instance); +} + +// Create key code translation tables +// +static void createKeyTables(void) +{ + int scancode; + + memset(_glfw.win32.keycodes, -1, sizeof(_glfw.win32.keycodes)); + memset(_glfw.win32.scancodes, -1, sizeof(_glfw.win32.scancodes)); + + _glfw.win32.keycodes[0x00B] = GLFW_KEY_0; + _glfw.win32.keycodes[0x002] = GLFW_KEY_1; + _glfw.win32.keycodes[0x003] = GLFW_KEY_2; + _glfw.win32.keycodes[0x004] = GLFW_KEY_3; + _glfw.win32.keycodes[0x005] = GLFW_KEY_4; + _glfw.win32.keycodes[0x006] = GLFW_KEY_5; + _glfw.win32.keycodes[0x007] = GLFW_KEY_6; + _glfw.win32.keycodes[0x008] = GLFW_KEY_7; + _glfw.win32.keycodes[0x009] = GLFW_KEY_8; + _glfw.win32.keycodes[0x00A] = GLFW_KEY_9; + _glfw.win32.keycodes[0x01E] = GLFW_KEY_A; + _glfw.win32.keycodes[0x030] = GLFW_KEY_B; + _glfw.win32.keycodes[0x02E] = GLFW_KEY_C; + _glfw.win32.keycodes[0x020] = GLFW_KEY_D; + _glfw.win32.keycodes[0x012] = GLFW_KEY_E; + _glfw.win32.keycodes[0x021] = GLFW_KEY_F; + _glfw.win32.keycodes[0x022] = GLFW_KEY_G; + _glfw.win32.keycodes[0x023] = GLFW_KEY_H; + _glfw.win32.keycodes[0x017] = GLFW_KEY_I; + _glfw.win32.keycodes[0x024] = GLFW_KEY_J; + _glfw.win32.keycodes[0x025] = GLFW_KEY_K; + _glfw.win32.keycodes[0x026] = GLFW_KEY_L; + _glfw.win32.keycodes[0x032] = GLFW_KEY_M; + _glfw.win32.keycodes[0x031] = GLFW_KEY_N; + _glfw.win32.keycodes[0x018] = GLFW_KEY_O; + _glfw.win32.keycodes[0x019] = GLFW_KEY_P; + _glfw.win32.keycodes[0x010] = GLFW_KEY_Q; + _glfw.win32.keycodes[0x013] = GLFW_KEY_R; + _glfw.win32.keycodes[0x01F] = GLFW_KEY_S; + _glfw.win32.keycodes[0x014] = GLFW_KEY_T; + _glfw.win32.keycodes[0x016] = GLFW_KEY_U; + _glfw.win32.keycodes[0x02F] = GLFW_KEY_V; + _glfw.win32.keycodes[0x011] = GLFW_KEY_W; + _glfw.win32.keycodes[0x02D] = GLFW_KEY_X; + _glfw.win32.keycodes[0x015] = GLFW_KEY_Y; + _glfw.win32.keycodes[0x02C] = GLFW_KEY_Z; + + _glfw.win32.keycodes[0x028] = GLFW_KEY_APOSTROPHE; + _glfw.win32.keycodes[0x02B] = GLFW_KEY_BACKSLASH; + _glfw.win32.keycodes[0x033] = GLFW_KEY_COMMA; + _glfw.win32.keycodes[0x00D] = GLFW_KEY_EQUAL; + _glfw.win32.keycodes[0x029] = GLFW_KEY_GRAVE_ACCENT; + _glfw.win32.keycodes[0x01A] = GLFW_KEY_LEFT_BRACKET; + _glfw.win32.keycodes[0x00C] = GLFW_KEY_MINUS; + _glfw.win32.keycodes[0x034] = GLFW_KEY_PERIOD; + _glfw.win32.keycodes[0x01B] = GLFW_KEY_RIGHT_BRACKET; + _glfw.win32.keycodes[0x027] = GLFW_KEY_SEMICOLON; + _glfw.win32.keycodes[0x035] = GLFW_KEY_SLASH; + _glfw.win32.keycodes[0x056] = GLFW_KEY_WORLD_2; + + _glfw.win32.keycodes[0x00E] = GLFW_KEY_BACKSPACE; + _glfw.win32.keycodes[0x153] = GLFW_KEY_DELETE; + _glfw.win32.keycodes[0x14F] = GLFW_KEY_END; + _glfw.win32.keycodes[0x01C] = GLFW_KEY_ENTER; + _glfw.win32.keycodes[0x001] = GLFW_KEY_ESCAPE; + _glfw.win32.keycodes[0x147] = GLFW_KEY_HOME; + _glfw.win32.keycodes[0x152] = GLFW_KEY_INSERT; + _glfw.win32.keycodes[0x15D] = GLFW_KEY_MENU; + _glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN; + _glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP; + _glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE; + _glfw.win32.keycodes[0x146] = GLFW_KEY_PAUSE; + _glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE; + _glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB; + _glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK; + _glfw.win32.keycodes[0x145] = GLFW_KEY_NUM_LOCK; + _glfw.win32.keycodes[0x046] = GLFW_KEY_SCROLL_LOCK; + _glfw.win32.keycodes[0x03B] = GLFW_KEY_F1; + _glfw.win32.keycodes[0x03C] = GLFW_KEY_F2; + _glfw.win32.keycodes[0x03D] = GLFW_KEY_F3; + _glfw.win32.keycodes[0x03E] = GLFW_KEY_F4; + _glfw.win32.keycodes[0x03F] = GLFW_KEY_F5; + _glfw.win32.keycodes[0x040] = GLFW_KEY_F6; + _glfw.win32.keycodes[0x041] = GLFW_KEY_F7; + _glfw.win32.keycodes[0x042] = GLFW_KEY_F8; + _glfw.win32.keycodes[0x043] = GLFW_KEY_F9; + _glfw.win32.keycodes[0x044] = GLFW_KEY_F10; + _glfw.win32.keycodes[0x057] = GLFW_KEY_F11; + _glfw.win32.keycodes[0x058] = GLFW_KEY_F12; + _glfw.win32.keycodes[0x064] = GLFW_KEY_F13; + _glfw.win32.keycodes[0x065] = GLFW_KEY_F14; + _glfw.win32.keycodes[0x066] = GLFW_KEY_F15; + _glfw.win32.keycodes[0x067] = GLFW_KEY_F16; + _glfw.win32.keycodes[0x068] = GLFW_KEY_F17; + _glfw.win32.keycodes[0x069] = GLFW_KEY_F18; + _glfw.win32.keycodes[0x06A] = GLFW_KEY_F19; + _glfw.win32.keycodes[0x06B] = GLFW_KEY_F20; + _glfw.win32.keycodes[0x06C] = GLFW_KEY_F21; + _glfw.win32.keycodes[0x06D] = GLFW_KEY_F22; + _glfw.win32.keycodes[0x06E] = GLFW_KEY_F23; + _glfw.win32.keycodes[0x076] = GLFW_KEY_F24; + _glfw.win32.keycodes[0x038] = GLFW_KEY_LEFT_ALT; + _glfw.win32.keycodes[0x01D] = GLFW_KEY_LEFT_CONTROL; + _glfw.win32.keycodes[0x02A] = GLFW_KEY_LEFT_SHIFT; + _glfw.win32.keycodes[0x15B] = GLFW_KEY_LEFT_SUPER; + _glfw.win32.keycodes[0x137] = GLFW_KEY_PRINT_SCREEN; + _glfw.win32.keycodes[0x138] = GLFW_KEY_RIGHT_ALT; + _glfw.win32.keycodes[0x11D] = GLFW_KEY_RIGHT_CONTROL; + _glfw.win32.keycodes[0x036] = GLFW_KEY_RIGHT_SHIFT; + _glfw.win32.keycodes[0x15C] = GLFW_KEY_RIGHT_SUPER; + _glfw.win32.keycodes[0x150] = GLFW_KEY_DOWN; + _glfw.win32.keycodes[0x14B] = GLFW_KEY_LEFT; + _glfw.win32.keycodes[0x14D] = GLFW_KEY_RIGHT; + _glfw.win32.keycodes[0x148] = GLFW_KEY_UP; + + _glfw.win32.keycodes[0x052] = GLFW_KEY_KP_0; + _glfw.win32.keycodes[0x04F] = GLFW_KEY_KP_1; + _glfw.win32.keycodes[0x050] = GLFW_KEY_KP_2; + _glfw.win32.keycodes[0x051] = GLFW_KEY_KP_3; + _glfw.win32.keycodes[0x04B] = GLFW_KEY_KP_4; + _glfw.win32.keycodes[0x04C] = GLFW_KEY_KP_5; + _glfw.win32.keycodes[0x04D] = GLFW_KEY_KP_6; + _glfw.win32.keycodes[0x047] = GLFW_KEY_KP_7; + _glfw.win32.keycodes[0x048] = GLFW_KEY_KP_8; + _glfw.win32.keycodes[0x049] = GLFW_KEY_KP_9; + _glfw.win32.keycodes[0x04E] = GLFW_KEY_KP_ADD; + _glfw.win32.keycodes[0x053] = GLFW_KEY_KP_DECIMAL; + _glfw.win32.keycodes[0x135] = GLFW_KEY_KP_DIVIDE; + _glfw.win32.keycodes[0x11C] = GLFW_KEY_KP_ENTER; + _glfw.win32.keycodes[0x037] = GLFW_KEY_KP_MULTIPLY; + _glfw.win32.keycodes[0x04A] = GLFW_KEY_KP_SUBTRACT; + + for (scancode = 0; scancode < 512; scancode++) + { + if (_glfw.win32.keycodes[scancode] > 0) + _glfw.win32.scancodes[_glfw.win32.keycodes[scancode]] = scancode; + } +} + +// Creates a dummy window for behind-the-scenes work +// +static HWND createHelperWindow(void) +{ + MSG msg; + HWND window = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, + _GLFW_WNDCLASSNAME, + L"GLFW message window", + WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + 0, 0, 1, 1, + NULL, NULL, + GetModuleHandleW(NULL), + NULL); + if (!window) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create helper window"); + return NULL; + } + + // HACK: The first call to ShowWindow is ignored if the parent process + // passed along a STARTUPINFO, so clear that flag with a no-op call + ShowWindow(window, SW_HIDE); + + // Register for HID device notifications + { + DEV_BROADCAST_DEVICEINTERFACE_W dbi; + ZeroMemory(&dbi, sizeof(dbi)); + dbi.dbcc_size = sizeof(dbi); + dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + dbi.dbcc_classguid = GUID_DEVINTERFACE_HID; + + RegisterDeviceNotificationW(window, + (DEV_BROADCAST_HDR*) &dbi, + DEVICE_NOTIFY_WINDOW_HANDLE); + } + + while (PeekMessageW(&msg, _glfw.win32.helperWindowHandle, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + return window; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Returns a wide string version of the specified UTF-8 string +// +WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source) +{ + WCHAR* target; + int count; + + count = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0); + if (!count) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert string from UTF-8"); + return NULL; + } + + target = calloc(count, sizeof(WCHAR)); + + if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, count)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert string from UTF-8"); + free(target); + return NULL; + } + + return target; +} + +// Returns a UTF-8 string version of the specified wide string +// +char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source) +{ + char* target; + int size; + + size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); + if (!size) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert string to UTF-8"); + return NULL; + } + + target = calloc(size, 1); + + if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert string to UTF-8"); + free(target); + return NULL; + } + + return target; +} + +// Reports the specified error, appending information about the last Win32 error +// +void _glfwInputErrorWin32(int error, const char* description) +{ + WCHAR buffer[_GLFW_MESSAGE_SIZE] = L""; + char message[_GLFW_MESSAGE_SIZE] = ""; + + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, + GetLastError() & 0xffff, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buffer, + sizeof(buffer), + NULL); + WideCharToMultiByte(CP_UTF8, 0, buffer, -1, message, sizeof(message), NULL, NULL); + + _glfwInputError(error, "%s: %s", description, message); +} + +// Updates key names according to the current keyboard layout +// +void _glfwUpdateKeyNamesWin32(void) +{ + int key; + BYTE state[256] = {0}; + + memset(_glfw.win32.keynames, 0, sizeof(_glfw.win32.keynames)); + + for (key = GLFW_KEY_SPACE; key <= GLFW_KEY_LAST; key++) + { + UINT vk; + int scancode, length; + WCHAR chars[16]; + + scancode = _glfw.win32.scancodes[key]; + if (scancode == -1) + continue; + + if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD) + { + const UINT vks[] = { + VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, + VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, + VK_NUMPAD8, VK_NUMPAD9, VK_DECIMAL, VK_DIVIDE, + VK_MULTIPLY, VK_SUBTRACT, VK_ADD + }; + + vk = vks[key - GLFW_KEY_KP_0]; + } + else + vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK); + + length = ToUnicode(vk, scancode, state, + chars, sizeof(chars) / sizeof(WCHAR), + 0); + + if (length == -1) + { + length = ToUnicode(vk, scancode, state, + chars, sizeof(chars) / sizeof(WCHAR), + 0); + } + + if (length < 1) + continue; + + WideCharToMultiByte(CP_UTF8, 0, chars, 1, + _glfw.win32.keynames[key], + sizeof(_glfw.win32.keynames[key]), + NULL, NULL); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + // To make SetForegroundWindow work as we want, we need to fiddle + // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early + // as possible in the hope of still being the foreground process) + SystemParametersInfoW(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, + &_glfw.win32.foregroundLockTimeout, 0); + SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0), + SPIF_SENDCHANGE); + + if (!loadLibraries()) + return GLFW_FALSE; + + createKeyTables(); + _glfwUpdateKeyNamesWin32(); + + if (IsWindows8Point1OrGreater()) + SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); + else if (IsWindowsVistaOrGreater()) + SetProcessDPIAware(); + + if (!_glfwRegisterWindowClassWin32()) + return GLFW_FALSE; + + _glfw.win32.helperWindowHandle = createHelperWindow(); + if (!_glfw.win32.helperWindowHandle) + return GLFW_FALSE; + + _glfwInitTimerWin32(); + _glfwInitJoysticksWin32(); + + _glfwPollMonitorsWin32(); + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + if (_glfw.win32.helperWindowHandle) + DestroyWindow(_glfw.win32.helperWindowHandle); + + _glfwUnregisterWindowClassWin32(); + + // Restore previous foreground lock timeout system setting + SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, + UIntToPtr(_glfw.win32.foregroundLockTimeout), + SPIF_SENDCHANGE); + + free(_glfw.win32.clipboardString); + free(_glfw.win32.rawInput); + + _glfwTerminateWGL(); + _glfwTerminateEGL(); + + _glfwTerminateJoysticksWin32(); + + freeLibraries(); +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " Win32 WGL EGL" +#if defined(__MINGW32__) + " MinGW" +#elif defined(_MSC_VER) + " VisualC" +#endif +#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) + " hybrid-GPU" +#endif +#if defined(_GLFW_BUILD_DLL) + " DLL" +#endif + ; +} + diff --git a/src/external/glfw/src/win32_joystick.c b/src/external/glfw/src/win32_joystick.c new file mode 100644 index 00000000..ad2dbb2f --- /dev/null +++ b/src/external/glfw/src/win32_joystick.c @@ -0,0 +1,751 @@ +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + +#define _GLFW_TYPE_AXIS 0 +#define _GLFW_TYPE_SLIDER 1 +#define _GLFW_TYPE_BUTTON 2 +#define _GLFW_TYPE_POV 3 + +// Data produced with DirectInput device object enumeration +// +typedef struct _GLFWobjenumWin32 +{ + IDirectInputDevice8W* device; + _GLFWjoyobjectWin32* objects; + int objectCount; + int axisCount; + int sliderCount; + int buttonCount; + int povCount; +} _GLFWobjenumWin32; + +// Define local copies of the necessary GUIDs +// +static const GUID _glfw_IID_IDirectInput8W = + {0xbf798031,0x483a,0x4da2,{0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00}}; +static const GUID _glfw_GUID_XAxis = + {0xa36d02e0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_YAxis = + {0xa36d02e1,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_ZAxis = + {0xa36d02e2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_RxAxis = + {0xa36d02f4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_RyAxis = + {0xa36d02f5,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_RzAxis = + {0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_Slider = + {0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; +static const GUID _glfw_GUID_POV = + {0xa36d02f2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; + +#define IID_IDirectInput8W _glfw_IID_IDirectInput8W +#define GUID_XAxis _glfw_GUID_XAxis +#define GUID_YAxis _glfw_GUID_YAxis +#define GUID_ZAxis _glfw_GUID_ZAxis +#define GUID_RxAxis _glfw_GUID_RxAxis +#define GUID_RyAxis _glfw_GUID_RyAxis +#define GUID_RzAxis _glfw_GUID_RzAxis +#define GUID_Slider _glfw_GUID_Slider +#define GUID_POV _glfw_GUID_POV + +// Object data array for our clone of c_dfDIJoystick +// Generated with https://github.com/elmindreda/c_dfDIJoystick2 +// +static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] = +{ + { &GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, + { &GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { &GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { &GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { &GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, + { NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, +}; + +// Our clone of c_dfDIJoystick +// +static const DIDATAFORMAT _glfwDataFormat = +{ + sizeof(DIDATAFORMAT), + sizeof(DIOBJECTDATAFORMAT), + DIDFT_ABSAXIS, + sizeof(DIJOYSTATE), + sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT), + _glfwObjectDataFormats +}; + +// Returns a description fitting the specified XInput capabilities +// +static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic) +{ + switch (xic->SubType) + { + case XINPUT_DEVSUBTYPE_WHEEL: + return "XInput Wheel"; + case XINPUT_DEVSUBTYPE_ARCADE_STICK: + return "XInput Arcade Stick"; + case XINPUT_DEVSUBTYPE_FLIGHT_STICK: + return "XInput Flight Stick"; + case XINPUT_DEVSUBTYPE_DANCE_PAD: + return "XInput Dance Pad"; + case XINPUT_DEVSUBTYPE_GUITAR: + return "XInput Guitar"; + case XINPUT_DEVSUBTYPE_DRUM_KIT: + return "XInput Drum Kit"; + case XINPUT_DEVSUBTYPE_GAMEPAD: + { + if (xic->Flags & XINPUT_CAPS_WIRELESS) + return "Wireless Xbox Controller"; + else + return "Xbox Controller"; + } + } + + return "Unknown XInput Device"; +} + +// Lexically compare device objects +// +static int compareJoystickObjects(const void* first, const void* second) +{ + const _GLFWjoyobjectWin32* fo = first; + const _GLFWjoyobjectWin32* so = second; + + if (fo->type != so->type) + return fo->type - so->type; + + return fo->offset - so->offset; +} + +// Checks whether the specified device supports XInput +// Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom +// +static GLFWbool supportsXInput(const GUID* guid) +{ + UINT i, count = 0; + RAWINPUTDEVICELIST* ridl; + GLFWbool result = GLFW_FALSE; + + if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0) + return GLFW_FALSE; + + ridl = calloc(count, sizeof(RAWINPUTDEVICELIST)); + + if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1) + { + free(ridl); + return GLFW_FALSE; + } + + for (i = 0; i < count; i++) + { + RID_DEVICE_INFO rdi; + char name[256]; + UINT size; + + if (ridl[i].dwType != RIM_TYPEHID) + continue; + + ZeroMemory(&rdi, sizeof(rdi)); + rdi.cbSize = sizeof(rdi); + size = sizeof(rdi); + + if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice, + RIDI_DEVICEINFO, + &rdi, &size) == -1) + { + continue; + } + + if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1) + continue; + + memset(name, 0, sizeof(name)); + size = sizeof(name); + + if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice, + RIDI_DEVICENAME, + name, &size) == -1) + { + break; + } + + name[sizeof(name) - 1] = '\0'; + if (strstr(name, "IG_")) + { + result = GLFW_TRUE; + break; + } + } + + free(ridl); + return result; +} + +// Frees all resources associated with the specified joystick +// +static void closeJoystick(_GLFWjoystick* js) +{ + if (js->win32.device) + { + IDirectInputDevice8_Unacquire(js->win32.device); + IDirectInputDevice8_Release(js->win32.device); + } + + _glfwFreeJoystick(js); + _glfwInputJoystick(js, GLFW_DISCONNECTED); +} + +// DirectInput device object enumeration callback +// Insights gleaned from SDL +// +static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi, + void* user) +{ + _GLFWobjenumWin32* data = user; + _GLFWjoyobjectWin32* object = data->objects + data->objectCount; + + if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS) + { + DIPROPRANGE dipr; + + if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0) + object->offset = DIJOFS_SLIDER(data->sliderCount); + else if (memcmp(&doi->guidType, &GUID_XAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_X; + else if (memcmp(&doi->guidType, &GUID_YAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_Y; + else if (memcmp(&doi->guidType, &GUID_ZAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_Z; + else if (memcmp(&doi->guidType, &GUID_RxAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_RX; + else if (memcmp(&doi->guidType, &GUID_RyAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_RY; + else if (memcmp(&doi->guidType, &GUID_RzAxis, sizeof(GUID)) == 0) + object->offset = DIJOFS_RZ; + else + return DIENUM_CONTINUE; + + ZeroMemory(&dipr, sizeof(dipr)); + dipr.diph.dwSize = sizeof(dipr); + dipr.diph.dwHeaderSize = sizeof(dipr.diph); + dipr.diph.dwObj = doi->dwType; + dipr.diph.dwHow = DIPH_BYID; + dipr.lMin = -32768; + dipr.lMax = 32767; + + if (FAILED(IDirectInputDevice8_SetProperty(data->device, + DIPROP_RANGE, + &dipr.diph))) + { + return DIENUM_CONTINUE; + } + + if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0) + { + object->type = _GLFW_TYPE_SLIDER; + data->sliderCount++; + } + else + { + object->type = _GLFW_TYPE_AXIS; + data->axisCount++; + } + } + else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON) + { + object->offset = DIJOFS_BUTTON(data->buttonCount); + object->type = _GLFW_TYPE_BUTTON; + data->buttonCount++; + } + else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV) + { + object->offset = DIJOFS_POV(data->povCount); + object->type = _GLFW_TYPE_POV; + data->povCount++; + } + + data->objectCount++; + return DIENUM_CONTINUE; +} + +// DirectInput device enumeration callback +// +static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) +{ + int jid = 0; + DIDEVCAPS dc; + DIPROPDWORD dipd; + IDirectInputDevice8* device; + _GLFWobjenumWin32 data; + _GLFWjoystick* js; + char guid[33]; + char name[256]; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + _GLFWjoystick* js = _glfw.joysticks + jid; + if (js->present) + { + if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0) + return DIENUM_CONTINUE; + } + } + + if (supportsXInput(&di->guidProduct)) + return DIENUM_CONTINUE; + + if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api, + &di->guidInstance, + &device, + NULL))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create device"); + return DIENUM_CONTINUE; + } + + if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to set device data format"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + ZeroMemory(&dc, sizeof(dc)); + dc.dwSize = sizeof(dc); + + if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to query device capabilities"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + ZeroMemory(&dipd, sizeof(dipd)); + dipd.diph.dwSize = sizeof(dipd); + dipd.diph.dwHeaderSize = sizeof(dipd.diph); + dipd.diph.dwHow = DIPH_DEVICE; + dipd.dwData = DIPROPAXISMODE_ABS; + + if (FAILED(IDirectInputDevice8_SetProperty(device, + DIPROP_AXISMODE, + &dipd.diph))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to set device axis mode"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + memset(&data, 0, sizeof(data)); + data.device = device; + data.objects = calloc(dc.dwAxes + dc.dwButtons + dc.dwPOVs, + sizeof(_GLFWjoyobjectWin32)); + + if (FAILED(IDirectInputDevice8_EnumObjects(device, + deviceObjectCallback, + &data, + DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to enumerate device objects"); + + IDirectInputDevice8_Release(device); + free(data.objects); + return DIENUM_CONTINUE; + } + + qsort(data.objects, data.objectCount, + sizeof(_GLFWjoyobjectWin32), + compareJoystickObjects); + + if (!WideCharToMultiByte(CP_UTF8, 0, + di->tszInstanceName, -1, + name, sizeof(name), + NULL, NULL)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert joystick name to UTF-8"); + + IDirectInputDevice8_Release(device); + free(data.objects); + return DIENUM_STOP; + } + + // Generate a joystick GUID that matches the SDL 2.0.5+ one + if (memcmp(&di->guidProduct.Data4[2], "PIDVID", 6) == 0) + { + sprintf(guid, "03000000%02x%02x0000%02x%02x000000000000", + (uint8_t) di->guidProduct.Data1, + (uint8_t) (di->guidProduct.Data1 >> 8), + (uint8_t) (di->guidProduct.Data1 >> 16), + (uint8_t) (di->guidProduct.Data1 >> 24)); + } + else + { + sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00", + name[0], name[1], name[2], name[3], + name[4], name[5], name[6], name[7], + name[8], name[9], name[10]); + } + + js = _glfwAllocJoystick(name, guid, + data.axisCount + data.sliderCount, + data.buttonCount, + data.povCount); + if (!js) + { + IDirectInputDevice8_Release(device); + free(data.objects); + return DIENUM_STOP; + } + + js->win32.device = device; + js->win32.guid = di->guidInstance; + js->win32.objects = data.objects; + js->win32.objectCount = data.objectCount; + + _glfwInputJoystick(js, GLFW_CONNECTED); + return DIENUM_CONTINUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +void _glfwInitJoysticksWin32(void) +{ + if (_glfw.win32.dinput8.instance) + { + if (FAILED(DirectInput8Create(GetModuleHandle(NULL), + DIRECTINPUT_VERSION, + &IID_IDirectInput8W, + (void**) &_glfw.win32.dinput8.api, + NULL))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create interface"); + } + } + + _glfwDetectJoystickConnectionWin32(); +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticksWin32(void) +{ + int jid; + + for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++) + closeJoystick(_glfw.joysticks + jid); + + if (_glfw.win32.dinput8.api) + IDirectInput8_Release(_glfw.win32.dinput8.api); +} + +// Checks for new joysticks after DBT_DEVICEARRIVAL +// +void _glfwDetectJoystickConnectionWin32(void) +{ + if (_glfw.win32.xinput.instance) + { + DWORD index; + + for (index = 0; index < XUSER_MAX_COUNT; index++) + { + int jid; + char guid[33]; + XINPUT_CAPABILITIES xic; + _GLFWjoystick* js; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (_glfw.joysticks[jid].present && + _glfw.joysticks[jid].win32.device == NULL && + _glfw.joysticks[jid].win32.index == index) + { + break; + } + } + + if (jid <= GLFW_JOYSTICK_LAST) + continue; + + if (XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS) + continue; + + // Generate a joystick GUID that matches the SDL 2.0.5+ one + sprintf(guid, "78696e707574%02x000000000000000000", + xic.SubType & 0xff); + + js = _glfwAllocJoystick(getDeviceDescription(&xic), guid, 6, 10, 1); + if (!js) + continue; + + js->win32.index = index; + + _glfwInputJoystick(js, GLFW_CONNECTED); + } + } + + if (_glfw.win32.dinput8.api) + { + if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api, + DI8DEVCLASS_GAMECTRL, + deviceCallback, + NULL, + DIEDFL_ALLDEVICES))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Failed to enumerate DirectInput8 devices"); + return; + } + } +} + +// Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE +// +void _glfwDetectJoystickDisconnectionWin32(void) +{ + int jid; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + _GLFWjoystick* js = _glfw.joysticks + jid; + if (js->present) + _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) +{ + if (js->win32.device) + { + int i, ai = 0, bi = 0, pi = 0; + HRESULT result; + DIJOYSTATE state; + + IDirectInputDevice8_Poll(js->win32.device); + result = IDirectInputDevice8_GetDeviceState(js->win32.device, + sizeof(state), + &state); + if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST) + { + IDirectInputDevice8_Acquire(js->win32.device); + IDirectInputDevice8_Poll(js->win32.device); + result = IDirectInputDevice8_GetDeviceState(js->win32.device, + sizeof(state), + &state); + } + + if (FAILED(result)) + { + closeJoystick(js); + return GLFW_FALSE; + } + + if (mode == _GLFW_POLL_PRESENCE) + return GLFW_TRUE; + + for (i = 0; i < js->win32.objectCount; i++) + { + const void* data = (char*) &state + js->win32.objects[i].offset; + + switch (js->win32.objects[i].type) + { + case _GLFW_TYPE_AXIS: + case _GLFW_TYPE_SLIDER: + { + const float value = (*((LONG*) data) + 0.5f) / 32767.5f; + _glfwInputJoystickAxis(js, ai, value); + ai++; + break; + } + + case _GLFW_TYPE_BUTTON: + { + const char value = (*((BYTE*) data) & 0x80) != 0; + _glfwInputJoystickButton(js, bi, value); + bi++; + break; + } + + case _GLFW_TYPE_POV: + { + const int states[9] = + { + GLFW_HAT_UP, + GLFW_HAT_RIGHT_UP, + GLFW_HAT_RIGHT, + GLFW_HAT_RIGHT_DOWN, + GLFW_HAT_DOWN, + GLFW_HAT_LEFT_DOWN, + GLFW_HAT_LEFT, + GLFW_HAT_LEFT_UP, + GLFW_HAT_CENTERED + }; + + // Screams of horror are appropriate at this point + int state = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES); + if (state < 0 || state > 8) + state = 8; + + _glfwInputJoystickHat(js, pi, states[state]); + pi++; + break; + } + } + } + } + else + { + int i, dpad = 0; + DWORD result; + XINPUT_STATE xis; + const WORD buttons[10] = + { + XINPUT_GAMEPAD_A, + XINPUT_GAMEPAD_B, + XINPUT_GAMEPAD_X, + XINPUT_GAMEPAD_Y, + XINPUT_GAMEPAD_LEFT_SHOULDER, + XINPUT_GAMEPAD_RIGHT_SHOULDER, + XINPUT_GAMEPAD_BACK, + XINPUT_GAMEPAD_START, + XINPUT_GAMEPAD_LEFT_THUMB, + XINPUT_GAMEPAD_RIGHT_THUMB + }; + + result = XInputGetState(js->win32.index, &xis); + if (result != ERROR_SUCCESS) + { + if (result == ERROR_DEVICE_NOT_CONNECTED) + closeJoystick(js); + + return GLFW_FALSE; + } + + if (mode == _GLFW_POLL_PRESENCE) + return GLFW_TRUE; + + _glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 1, (xis.Gamepad.sThumbLY + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 3, (xis.Gamepad.sThumbRY + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.f); + _glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.f); + + for (i = 0; i < 10; i++) + { + const char value = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0; + _glfwInputJoystickButton(js, i, value); + } + + if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) + dpad |= GLFW_HAT_UP; + if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) + dpad |= GLFW_HAT_RIGHT; + if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) + dpad |= GLFW_HAT_DOWN; + if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) + dpad |= GLFW_HAT_LEFT; + + _glfwInputJoystickHat(js, 0, dpad); + } + + return GLFW_TRUE; +} + +void _glfwPlatformUpdateGamepadGUID(char* guid) +{ + if (strcmp(guid + 20, "504944564944") == 0) + { + char original[33]; + strcpy(original, guid); + sprintf(guid, "03000000%.4s0000%.4s000000000000", + original, original + 4); + } +} + diff --git a/src/external/glfw/src/win32_joystick.h b/src/external/glfw/src/win32_joystick.h new file mode 100644 index 00000000..9156f6c1 --- /dev/null +++ b/src/external/glfw/src/win32_joystick.h @@ -0,0 +1,56 @@ +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickWin32 win32 +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int dummy + +#define _GLFW_PLATFORM_MAPPING_NAME "Windows" + +// Joystick element (axis, button or slider) +// +typedef struct _GLFWjoyobjectWin32 +{ + int offset; + int type; +} _GLFWjoyobjectWin32; + +// Win32-specific per-joystick data +// +typedef struct _GLFWjoystickWin32 +{ + _GLFWjoyobjectWin32* objects; + int objectCount; + IDirectInputDevice8W* device; + DWORD index; + GUID guid; +} _GLFWjoystickWin32; + + +void _glfwInitJoysticksWin32(void); +void _glfwTerminateJoysticksWin32(void); +void _glfwDetectJoystickConnectionWin32(void); +void _glfwDetectJoystickDisconnectionWin32(void); + diff --git a/src/external/glfw/src/win32_monitor.c b/src/external/glfw/src/win32_monitor.c new file mode 100644 index 00000000..74dd8252 --- /dev/null +++ b/src/external/glfw/src/win32_monitor.c @@ -0,0 +1,512 @@ +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include + + +// Callback for EnumDisplayMonitors in createMonitor +// +static BOOL CALLBACK monitorCallback(HMONITOR handle, + HDC dc, + RECT* rect, + LPARAM data) +{ + MONITORINFOEXW mi; + ZeroMemory(&mi, sizeof(mi)); + mi.cbSize = sizeof(mi); + + if (GetMonitorInfoW(handle, (MONITORINFO*) &mi)) + { + _GLFWmonitor* monitor = (_GLFWmonitor*) data; + if (wcscmp(mi.szDevice, monitor->win32.adapterName) == 0) + monitor->win32.handle = handle; + } + + return TRUE; +} + +// Create monitor from an adapter and (optionally) a display +// +static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, + DISPLAY_DEVICEW* display) +{ + _GLFWmonitor* monitor; + int widthMM, heightMM; + char* name; + HDC dc; + DEVMODEW dm; + RECT rect; + + if (display) + name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString); + else + name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString); + if (!name) + return NULL; + + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); + EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm); + + dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL); + + if (IsWindows8Point1OrGreater()) + { + widthMM = GetDeviceCaps(dc, HORZSIZE); + heightMM = GetDeviceCaps(dc, VERTSIZE); + } + else + { + widthMM = (int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX)); + heightMM = (int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY)); + } + + DeleteDC(dc); + + monitor = _glfwAllocMonitor(name, widthMM, heightMM); + free(name); + + if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED) + monitor->win32.modesPruned = GLFW_TRUE; + + wcscpy(monitor->win32.adapterName, adapter->DeviceName); + WideCharToMultiByte(CP_UTF8, 0, + adapter->DeviceName, -1, + monitor->win32.publicAdapterName, + sizeof(monitor->win32.publicAdapterName), + NULL, NULL); + + if (display) + { + wcscpy(monitor->win32.displayName, display->DeviceName); + WideCharToMultiByte(CP_UTF8, 0, + display->DeviceName, -1, + monitor->win32.publicDisplayName, + sizeof(monitor->win32.publicDisplayName), + NULL, NULL); + } + + rect.left = dm.dmPosition.x; + rect.top = dm.dmPosition.y; + rect.right = dm.dmPosition.x + dm.dmPelsWidth; + rect.bottom = dm.dmPosition.y + dm.dmPelsHeight; + + EnumDisplayMonitors(NULL, &rect, monitorCallback, (LPARAM) monitor); + return monitor; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Poll for changes in the set of connected monitors +// +void _glfwPollMonitorsWin32(void) +{ + int i, disconnectedCount; + _GLFWmonitor** disconnected = NULL; + DWORD adapterIndex, displayIndex; + DISPLAY_DEVICEW adapter, display; + _GLFWmonitor* monitor; + + disconnectedCount = _glfw.monitorCount; + if (disconnectedCount) + { + disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); + memcpy(disconnected, + _glfw.monitors, + _glfw.monitorCount * sizeof(_GLFWmonitor*)); + } + + for (adapterIndex = 0; ; adapterIndex++) + { + int type = _GLFW_INSERT_LAST; + + ZeroMemory(&adapter, sizeof(adapter)); + adapter.cb = sizeof(adapter); + + if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) + break; + + if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + type = _GLFW_INSERT_FIRST; + + for (displayIndex = 0; ; displayIndex++) + { + ZeroMemory(&display, sizeof(display)); + display.cb = sizeof(display); + + if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0)) + break; + + if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + for (i = 0; i < disconnectedCount; i++) + { + if (disconnected[i] && + wcscmp(disconnected[i]->win32.displayName, + display.DeviceName) == 0) + { + disconnected[i] = NULL; + break; + } + } + + if (i < disconnectedCount) + continue; + + monitor = createMonitor(&adapter, &display); + if (!monitor) + { + free(disconnected); + return; + } + + _glfwInputMonitor(monitor, GLFW_CONNECTED, type); + + type = _GLFW_INSERT_LAST; + } + + // HACK: If an active adapter does not have any display devices + // (as sometimes happens), add it directly as a monitor + if (displayIndex == 0) + { + for (i = 0; i < disconnectedCount; i++) + { + if (disconnected[i] && + wcscmp(disconnected[i]->win32.adapterName, + adapter.DeviceName) == 0) + { + disconnected[i] = NULL; + break; + } + } + + if (i < disconnectedCount) + continue; + + monitor = createMonitor(&adapter, NULL); + if (!monitor) + { + free(disconnected); + return; + } + + _glfwInputMonitor(monitor, GLFW_CONNECTED, type); + } + } + + for (i = 0; i < disconnectedCount; i++) + { + if (disconnected[i]) + _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); + } + + free(disconnected); +} + +// Change the current video mode +// +GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired) +{ + GLFWvidmode current; + const GLFWvidmode* best; + DEVMODEW dm; + LONG result; + + best = _glfwChooseVideoMode(monitor, desired); + _glfwPlatformGetVideoMode(monitor, ¤t); + if (_glfwCompareVideoModes(¤t, best) == 0) + return GLFW_TRUE; + + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | + DM_DISPLAYFREQUENCY; + dm.dmPelsWidth = best->width; + dm.dmPelsHeight = best->height; + dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits; + dm.dmDisplayFrequency = best->refreshRate; + + if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24) + dm.dmBitsPerPel = 32; + + result = ChangeDisplaySettingsExW(monitor->win32.adapterName, + &dm, + NULL, + CDS_FULLSCREEN, + NULL); + if (result != DISP_CHANGE_SUCCESSFUL) + { + const char* description = "Unknown error"; + + if (result == DISP_CHANGE_BADDUALVIEW) + description = "The system uses DualView"; + else if (result == DISP_CHANGE_BADFLAGS) + description = "Invalid flags"; + else if (result == DISP_CHANGE_BADMODE) + description = "Graphics mode not supported"; + else if (result == DISP_CHANGE_BADPARAM) + description = "Invalid parameter"; + else if (result == DISP_CHANGE_FAILED) + description = "Graphics mode failed"; + else if (result == DISP_CHANGE_NOTUPDATED) + description = "Failed to write to registry"; + else if (result == DISP_CHANGE_RESTART) + description = "Computer restart required"; + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to set video mode: %s", + description); + + return GLFW_FALSE; + } + + monitor->win32.modeChanged = GLFW_TRUE; + return GLFW_TRUE; +} + +// Restore the previously saved (original) video mode +// +void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) +{ + if (monitor->win32.modeChanged) + { + ChangeDisplaySettingsExW(monitor->win32.adapterName, + NULL, NULL, CDS_FULLSCREEN, NULL); + monitor->win32.modeChanged = GLFW_FALSE; + } +} + +void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale) +{ + UINT xdpi, ydpi; + + if (IsWindows8Point1OrGreater()) + GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); + else + { + const HDC dc = GetDC(NULL); + xdpi = GetDeviceCaps(dc, LOGPIXELSX); + ydpi = GetDeviceCaps(dc, LOGPIXELSY); + ReleaseDC(NULL, dc); + } + + if (xscale) + *xscale = xdpi / 96.f; + if (yscale) + *yscale = ydpi / 96.f; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + DEVMODEW dm; + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); + + EnumDisplaySettingsExW(monitor->win32.adapterName, + ENUM_CURRENT_SETTINGS, + &dm, + EDS_ROTATEDMODE); + + if (xpos) + *xpos = dm.dmPosition.x; + if (ypos) + *ypos = dm.dmPosition.y; +} + +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + _glfwGetMonitorContentScaleWin32(monitor->win32.handle, xscale, yscale); +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) +{ + int modeIndex = 0, size = 0; + GLFWvidmode* result = NULL; + + *count = 0; + + for (;;) + { + int i; + GLFWvidmode mode; + DEVMODEW dm; + + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); + + if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm)) + break; + + modeIndex++; + + // Skip modes with less than 15 BPP + if (dm.dmBitsPerPel < 15) + continue; + + mode.width = dm.dmPelsWidth; + mode.height = dm.dmPelsHeight; + mode.refreshRate = dm.dmDisplayFrequency; + _glfwSplitBPP(dm.dmBitsPerPel, + &mode.redBits, + &mode.greenBits, + &mode.blueBits); + + for (i = 0; i < *count; i++) + { + if (_glfwCompareVideoModes(result + i, &mode) == 0) + break; + } + + // Skip duplicate modes + if (i < *count) + continue; + + if (monitor->win32.modesPruned) + { + // Skip modes not supported by the connected displays + if (ChangeDisplaySettingsExW(monitor->win32.adapterName, + &dm, + NULL, + CDS_TEST, + NULL) != DISP_CHANGE_SUCCESSFUL) + { + continue; + } + } + + if (*count == size) + { + size += 128; + result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode)); + } + + (*count)++; + result[*count - 1] = mode; + } + + if (!*count) + { + // HACK: Report the current mode if no valid modes were found + result = calloc(1, sizeof(GLFWvidmode)); + _glfwPlatformGetVideoMode(monitor, result); + *count = 1; + } + + return result; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + DEVMODEW dm; + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); + + EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm); + + mode->width = dm.dmPelsWidth; + mode->height = dm.dmPelsHeight; + mode->refreshRate = dm.dmDisplayFrequency; + _glfwSplitBPP(dm.dmBitsPerPel, + &mode->redBits, + &mode->greenBits, + &mode->blueBits); +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + HDC dc; + WORD values[768]; + + dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL); + GetDeviceGammaRamp(dc, values); + DeleteDC(dc); + + _glfwAllocGammaArrays(ramp, 256); + + memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short)); + memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short)); + memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short)); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + HDC dc; + WORD values[768]; + + if (ramp->size != 256) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Gamma ramp size must be 256"); + return; + } + + memcpy(values + 0, ramp->red, 256 * sizeof(unsigned short)); + memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short)); + memcpy(values + 512, ramp->blue, 256 * sizeof(unsigned short)); + + dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL); + SetDeviceGammaRamp(dc, values); + DeleteDC(dc); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->win32.publicAdapterName; +} + +GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->win32.publicDisplayName; +} + diff --git a/src/external/glfw/src/win32_platform.h b/src/external/glfw/src/win32_platform.h new file mode 100644 index 00000000..1bfc638f --- /dev/null +++ b/src/external/glfw/src/win32_platform.h @@ -0,0 +1,409 @@ +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +// We don't need all the fancy stuff +#ifndef NOMINMAX + #define NOMINMAX +#endif + +#ifndef VC_EXTRALEAN + #define VC_EXTRALEAN +#endif + +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif + +// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for +// example to allow applications to correctly declare a GL_ARB_debug_output +// callback) but windows.h assumes no one will define APIENTRY before it does +#undef APIENTRY + +// GLFW on Windows is Unicode only and does not work in MBCS mode +#ifndef UNICODE + #define UNICODE +#endif + +// GLFW requires Windows XP or later +#if WINVER < 0x0501 + #undef WINVER + #define WINVER 0x0501 +#endif +#if _WIN32_WINNT < 0x0501 + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0501 +#endif + +// GLFW uses DirectInput8 interfaces +#define DIRECTINPUT_VERSION 0x0800 + +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) + #include + #define strdup _strdup +#endif + +// HACK: Define macros that some windows.h variants don't +#ifndef WM_MOUSEHWHEEL + #define WM_MOUSEHWHEEL 0x020E +#endif +#ifndef WM_DWMCOMPOSITIONCHANGED + #define WM_DWMCOMPOSITIONCHANGED 0x031E +#endif +#ifndef WM_COPYGLOBALDATA + #define WM_COPYGLOBALDATA 0x0049 +#endif +#ifndef WM_UNICHAR + #define WM_UNICHAR 0x0109 +#endif +#ifndef UNICODE_NOCHAR + #define UNICODE_NOCHAR 0xFFFF +#endif +#ifndef WM_DPICHANGED + #define WM_DPICHANGED 0x02E0 +#endif +#ifndef GET_XBUTTON_WPARAM + #define GET_XBUTTON_WPARAM(w) (HIWORD(w)) +#endif +#ifndef EDS_ROTATEDMODE + #define EDS_ROTATEDMODE 0x00000004 +#endif +#ifndef DISPLAY_DEVICE_ACTIVE + #define DISPLAY_DEVICE_ACTIVE 0x00000001 +#endif +#ifndef _WIN32_WINNT_WINBLUE + #define _WIN32_WINNT_WINBLUE 0x0602 +#endif + +#if WINVER < 0x0601 +typedef struct tagCHANGEFILTERSTRUCT +{ + DWORD cbSize; + DWORD ExtStatus; + +} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT; +#ifndef MSGFLT_ALLOW + #define MSGFLT_ALLOW 1 +#endif +#endif /*Windows 7*/ + +#if WINVER < 0x0600 +#define DWM_BB_ENABLE 0x00000001 +#define DWM_BB_BLURREGION 0x00000002 +typedef struct +{ + DWORD dwFlags; + BOOL fEnable; + HRGN hRgnBlur; + BOOL fTransitionOnMaximized; +} DWM_BLURBEHIND; +#endif /*Windows Vista*/ + +#ifndef DPI_ENUMS_DECLARED +typedef enum PROCESS_DPI_AWARENESS +{ + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 +} PROCESS_DPI_AWARENESS; +typedef enum MONITOR_DPI_TYPE +{ + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI +} MONITOR_DPI_TYPE; +#endif /*DPI_ENUMS_DECLARED*/ + +// HACK: Define versionhelpers.h functions manually as MinGW lacks the header +BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp); +#define IsWindowsVistaOrGreater() \ + IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), \ + LOBYTE(_WIN32_WINNT_VISTA), 0) +#define IsWindows7OrGreater() \ + IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), \ + LOBYTE(_WIN32_WINNT_WIN7), 0) +#define IsWindows8OrGreater() \ + IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), \ + LOBYTE(_WIN32_WINNT_WIN8), 0) +#define IsWindows8Point1OrGreater() \ + IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), \ + LOBYTE(_WIN32_WINNT_WINBLUE), 0) + +// HACK: Define macros that some xinput.h variants don't +#ifndef XINPUT_CAPS_WIRELESS + #define XINPUT_CAPS_WIRELESS 0x0002 +#endif +#ifndef XINPUT_DEVSUBTYPE_WHEEL + #define XINPUT_DEVSUBTYPE_WHEEL 0x02 +#endif +#ifndef XINPUT_DEVSUBTYPE_ARCADE_STICK + #define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03 +#endif +#ifndef XINPUT_DEVSUBTYPE_FLIGHT_STICK + #define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04 +#endif +#ifndef XINPUT_DEVSUBTYPE_DANCE_PAD + #define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05 +#endif +#ifndef XINPUT_DEVSUBTYPE_GUITAR + #define XINPUT_DEVSUBTYPE_GUITAR 0x06 +#endif +#ifndef XINPUT_DEVSUBTYPE_DRUM_KIT + #define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08 +#endif +#ifndef XINPUT_DEVSUBTYPE_ARCADE_PAD + #define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13 +#endif +#ifndef XUSER_MAX_COUNT + #define XUSER_MAX_COUNT 4 +#endif + +// HACK: Define macros that some dinput.h variants don't +#ifndef DIDFT_OPTIONAL + #define DIDFT_OPTIONAL 0x80000000 +#endif + +// winmm.dll function pointer typedefs +typedef DWORD (WINAPI * PFN_timeGetTime)(void); +#define timeGetTime _glfw.win32.winmm.GetTime + +// xinput.dll function pointer typedefs +typedef DWORD (WINAPI * PFN_XInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*); +typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*); +#define XInputGetCapabilities _glfw.win32.xinput.GetCapabilities +#define XInputGetState _glfw.win32.xinput.GetState + +// dinput8.dll function pointer typedefs +typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN); +#define DirectInput8Create _glfw.win32.dinput8.Create + +// user32.dll function pointer typedefs +typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void); +typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); +#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_ +#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_ + +// dwmapi.dll function pointer typedefs +typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); +typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID); +typedef HRESULT(WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND,const DWM_BLURBEHIND*); +#define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled +#define DwmFlush _glfw.win32.dwmapi.Flush +#define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow + +// shcore.dll function pointer typedefs +typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); +typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*); +#define SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness_ +#define GetDpiForMonitor _glfw.win32.shcore.GetDpiForMonitor_ + +typedef VkFlags VkWin32SurfaceCreateFlagsKHR; + +typedef struct VkWin32SurfaceCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; +} VkWin32SurfaceCreateInfoKHR; + +typedef VkResult (APIENTRY *PFN_vkCreateWin32SurfaceKHR)(VkInstance,const VkWin32SurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t); + +#include "win32_joystick.h" +#include "wgl_context.h" +#include "egl_context.h" +#include "osmesa_context.h" + +#define _GLFW_WNDCLASSNAME L"GLFW30" + +#define _glfw_dlopen(name) LoadLibraryA(name) +#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle) +#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name) + +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->win32.handle) +#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32 +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32 +#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerWin32 win32 +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32 +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32 +#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32 +#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexWin32 win32 + + +// Win32-specific per-window data +// +typedef struct _GLFWwindowWin32 +{ + HWND handle; + HICON bigIcon; + HICON smallIcon; + + GLFWbool cursorTracked; + GLFWbool frameAction; + GLFWbool iconified; + GLFWbool maximized; + // Whether to enable framebuffer transparency on DWM + GLFWbool transparent; + + // The last received cursor position, regardless of source + int lastCursorPosX, lastCursorPosY; + +} _GLFWwindowWin32; + +// Win32-specific global data +// +typedef struct _GLFWlibraryWin32 +{ + HWND helperWindowHandle; + DWORD foregroundLockTimeout; + int acquiredMonitorCount; + char* clipboardString; + short int keycodes[512]; + short int scancodes[GLFW_KEY_LAST + 1]; + char keynames[GLFW_KEY_LAST + 1][5]; + // Where to place the cursor when re-enabled + double restoreCursorPosX, restoreCursorPosY; + // The window whose disabled cursor mode is active + _GLFWwindow* disabledCursorWindow; + RAWINPUT* rawInput; + int rawInputSize; + + struct { + HINSTANCE instance; + PFN_timeGetTime GetTime; + } winmm; + + struct { + HINSTANCE instance; + PFN_DirectInput8Create Create; + IDirectInput8W* api; + } dinput8; + + struct { + HINSTANCE instance; + PFN_XInputGetCapabilities GetCapabilities; + PFN_XInputGetState GetState; + } xinput; + + struct { + HINSTANCE instance; + PFN_SetProcessDPIAware SetProcessDPIAware_; + PFN_ChangeWindowMessageFilterEx ChangeWindowMessageFilterEx_; + } user32; + + struct { + HINSTANCE instance; + PFN_DwmIsCompositionEnabled IsCompositionEnabled; + PFN_DwmFlush Flush; + PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow; + } dwmapi; + + struct { + HINSTANCE instance; + PFN_SetProcessDpiAwareness SetProcessDpiAwareness_; + PFN_GetDpiForMonitor GetDpiForMonitor_; + } shcore; + +} _GLFWlibraryWin32; + +// Win32-specific per-monitor data +// +typedef struct _GLFWmonitorWin32 +{ + HMONITOR handle; + // This size matches the static size of DISPLAY_DEVICE.DeviceName + WCHAR adapterName[32]; + WCHAR displayName[32]; + char publicAdapterName[64]; + char publicDisplayName[64]; + GLFWbool modesPruned; + GLFWbool modeChanged; + +} _GLFWmonitorWin32; + +// Win32-specific per-cursor data +// +typedef struct _GLFWcursorWin32 +{ + HCURSOR handle; + +} _GLFWcursorWin32; + +// Win32-specific global timer data +// +typedef struct _GLFWtimerWin32 +{ + GLFWbool hasPC; + uint64_t frequency; + +} _GLFWtimerWin32; + +// Win32-specific thread local storage data +// +typedef struct _GLFWtlsWin32 +{ + GLFWbool allocated; + DWORD index; + +} _GLFWtlsWin32; + +// Win32-specific mutex data +// +typedef struct _GLFWmutexWin32 +{ + GLFWbool allocated; + CRITICAL_SECTION section; + +} _GLFWmutexWin32; + + +GLFWbool _glfwRegisterWindowClassWin32(void); +void _glfwUnregisterWindowClassWin32(void); +GLFWbool _glfwIsCompositionEnabledWin32(void); + +WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source); +char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source); +void _glfwInputErrorWin32(int error, const char* description); +void _glfwUpdateKeyNamesWin32(void); + +void _glfwInitTimerWin32(void); + +void _glfwPollMonitorsWin32(void); +GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired); +void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor); +void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale); + diff --git a/src/external/glfw/src/win32_thread.c b/src/external/glfw/src/win32_thread.c new file mode 100644 index 00000000..98231c1e --- /dev/null +++ b/src/external/glfw/src/win32_thread.c @@ -0,0 +1,97 @@ +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) +{ + assert(tls->win32.allocated == GLFW_FALSE); + + tls->win32.index = TlsAlloc(); + if (tls->win32.index == TLS_OUT_OF_INDEXES) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to allocate TLS index"); + return GLFW_FALSE; + } + + tls->win32.allocated = GLFW_TRUE; + return GLFW_TRUE; +} + +void _glfwPlatformDestroyTls(_GLFWtls* tls) +{ + if (tls->win32.allocated) + TlsFree(tls->win32.index); + memset(tls, 0, sizeof(_GLFWtls)); +} + +void* _glfwPlatformGetTls(_GLFWtls* tls) +{ + assert(tls->win32.allocated == GLFW_TRUE); + return TlsGetValue(tls->win32.index); +} + +void _glfwPlatformSetTls(_GLFWtls* tls, void* value) +{ + assert(tls->win32.allocated == GLFW_TRUE); + TlsSetValue(tls->win32.index, value); +} + +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex) +{ + assert(mutex->win32.allocated == GLFW_FALSE); + InitializeCriticalSection(&mutex->win32.section); + return mutex->win32.allocated = GLFW_TRUE; +} + +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex) +{ + if (mutex->win32.allocated) + DeleteCriticalSection(&mutex->win32.section); + memset(mutex, 0, sizeof(_GLFWmutex)); +} + +void _glfwPlatformLockMutex(_GLFWmutex* mutex) +{ + assert(mutex->win32.allocated == GLFW_TRUE); + EnterCriticalSection(&mutex->win32.section); +} + +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) +{ + assert(mutex->win32.allocated == GLFW_TRUE); + LeaveCriticalSection(&mutex->win32.section); +} + diff --git a/src/external/glfw/src/win32_time.c b/src/external/glfw/src/win32_time.c new file mode 100644 index 00000000..f333cd44 --- /dev/null +++ b/src/external/glfw/src/win32_time.c @@ -0,0 +1,74 @@ +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimerWin32(void) +{ + uint64_t frequency; + + if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency)) + { + _glfw.timer.win32.hasPC = GLFW_TRUE; + _glfw.timer.win32.frequency = frequency; + } + else + { + _glfw.timer.win32.hasPC = GLFW_FALSE; + _glfw.timer.win32.frequency = 1000; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +uint64_t _glfwPlatformGetTimerValue(void) +{ + if (_glfw.timer.win32.hasPC) + { + uint64_t value; + QueryPerformanceCounter((LARGE_INTEGER*) &value); + return value; + } + else + return (uint64_t) timeGetTime(); +} + +uint64_t _glfwPlatformGetTimerFrequency(void) +{ + return _glfw.timer.win32.frequency; +} + diff --git a/src/external/glfw/src/win32_window.c b/src/external/glfw/src/win32_window.c new file mode 100644 index 00000000..6d3e76cc --- /dev/null +++ b/src/external/glfw/src/win32_window.c @@ -0,0 +1,1953 @@ +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#define _GLFW_KEY_INVALID -2 + +// Returns the window style for the specified window +// +static DWORD getWindowStyle(const _GLFWwindow* window) +{ + DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + + if (window->monitor) + style |= WS_POPUP; + else + { + style |= WS_SYSMENU | WS_MINIMIZEBOX; + + if (window->decorated) + { + style |= WS_CAPTION; + + if (window->resizable) + style |= WS_MAXIMIZEBOX | WS_THICKFRAME; + } + else + style |= WS_POPUP; + } + + return style; +} + +// Returns the extended window style for the specified window +// +static DWORD getWindowExStyle(const _GLFWwindow* window) +{ + DWORD style = WS_EX_APPWINDOW; + + if (window->monitor || window->floating) + style |= WS_EX_TOPMOST; + + return style; +} + +// Returns the image whose area most closely matches the desired one +// +static const GLFWimage* chooseImage(int count, const GLFWimage* images, + int width, int height) +{ + int i, leastDiff = INT_MAX; + const GLFWimage* closest = NULL; + + for (i = 0; i < count; i++) + { + const int currDiff = abs(images[i].width * images[i].height - + width * height); + if (currDiff < leastDiff) + { + closest = images + i; + leastDiff = currDiff; + } + } + + return closest; +} + +// Creates an RGBA icon or cursor +// +static HICON createIcon(const GLFWimage* image, + int xhot, int yhot, GLFWbool icon) +{ + int i; + HDC dc; + HICON handle; + HBITMAP color, mask; + BITMAPV5HEADER bi; + ICONINFO ii; + unsigned char* target = NULL; + unsigned char* source = image->pixels; + + ZeroMemory(&bi, sizeof(bi)); + bi.bV5Size = sizeof(bi); + bi.bV5Width = image->width; + bi.bV5Height = -image->height; + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + bi.bV5RedMask = 0x00ff0000; + bi.bV5GreenMask = 0x0000ff00; + bi.bV5BlueMask = 0x000000ff; + bi.bV5AlphaMask = 0xff000000; + + dc = GetDC(NULL); + color = CreateDIBSection(dc, + (BITMAPINFO*) &bi, + DIB_RGB_COLORS, + (void**) &target, + NULL, + (DWORD) 0); + ReleaseDC(NULL, dc); + + if (!color) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create RGBA bitmap"); + return NULL; + } + + mask = CreateBitmap(image->width, image->height, 1, 1, NULL); + if (!mask) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create mask bitmap"); + DeleteObject(color); + return NULL; + } + + for (i = 0; i < image->width * image->height; i++) + { + target[0] = source[2]; + target[1] = source[1]; + target[2] = source[0]; + target[3] = source[3]; + target += 4; + source += 4; + } + + ZeroMemory(&ii, sizeof(ii)); + ii.fIcon = icon; + ii.xHotspot = xhot; + ii.yHotspot = yhot; + ii.hbmMask = mask; + ii.hbmColor = color; + + handle = CreateIconIndirect(&ii); + + DeleteObject(color); + DeleteObject(mask); + + if (!handle) + { + if (icon) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create icon"); + } + else + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create cursor"); + } + } + + return handle; +} + +// Translate client window size to full window size according to styles +// +static void getFullWindowSize(DWORD style, DWORD exStyle, + int clientWidth, int clientHeight, + int* fullWidth, int* fullHeight) +{ + RECT rect = { 0, 0, clientWidth, clientHeight }; + AdjustWindowRectEx(&rect, style, FALSE, exStyle); + *fullWidth = rect.right - rect.left; + *fullHeight = rect.bottom - rect.top; +} + +// Enforce the client rect aspect ratio based on which edge is being dragged +// +static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) +{ + int xoff, yoff; + const float ratio = (float) window->numer / (float) window->denom; + + getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), + 0, 0, &xoff, &yoff); + + if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT || + edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) + { + area->bottom = area->top + yoff + + (int) ((area->right - area->left - xoff) / ratio); + } + else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) + { + area->top = area->bottom - yoff - + (int) ((area->right - area->left - xoff) / ratio); + } + else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) + { + area->right = area->left + xoff + + (int) ((area->bottom - area->top - yoff) * ratio); + } +} + +// Centers the cursor over the window client area +// +static void centerCursor(_GLFWwindow* window) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); +} + +// Returns whether the cursor is in the client area of the specified window +// +static GLFWbool cursorInClientArea(_GLFWwindow* window) +{ + RECT area; + POINT pos; + + if (!GetCursorPos(&pos)) + return GLFW_FALSE; + + if (WindowFromPoint(pos) != window->win32.handle) + return GLFW_FALSE; + + GetClientRect(window->win32.handle, &area); + ClientToScreen(window->win32.handle, (POINT*) &area.left); + ClientToScreen(window->win32.handle, (POINT*) &area.right); + + return PtInRect(&area, pos); +} + +// Updates the cursor image according to its cursor mode +// +static void updateCursorImage(_GLFWwindow* window) +{ + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + if (window->cursor) + SetCursor(window->cursor->win32.handle); + else + SetCursor(LoadCursorW(NULL, IDC_ARROW)); + } + else + SetCursor(NULL); +} + +// Updates the cursor clip rect +// +static void updateClipRect(_GLFWwindow* window) +{ + if (window) + { + RECT clipRect; + GetClientRect(window->win32.handle, &clipRect); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); + ClipCursor(&clipRect); + } + else + ClipCursor(NULL); +} + +// Update native window styles to match attributes +// +static void updateWindowStyles(const _GLFWwindow* window) +{ + RECT rect; + DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); + style &= ~(WS_OVERLAPPEDWINDOW | WS_POPUP); + style |= getWindowStyle(window); + + GetClientRect(window->win32.handle, &rect); + AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window)); + ClientToScreen(window->win32.handle, (POINT*) &rect.left); + ClientToScreen(window->win32.handle, (POINT*) &rect.right); + SetWindowLongW(window->win32.handle, GWL_STYLE, style); + SetWindowPos(window->win32.handle, HWND_TOP, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER); +} + +// Update window framebuffer transparency +// +static void updateFramebufferTransparency(const _GLFWwindow* window) +{ + if (!IsWindowsVistaOrGreater()) + return; + + if (_glfwIsCompositionEnabledWin32()) + { + HRGN region = CreateRectRgn(0, 0, -1, -1); + DWM_BLURBEHIND bb = {0}; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = region; + bb.fEnable = TRUE; + + if (SUCCEEDED(DwmEnableBlurBehindWindow(window->win32.handle, &bb))) + { + // Decorated windows don't repaint the transparent background + // leaving a trail behind animations + // HACK: Making the window layered with a transparency color key + // seems to fix this. Normally, when specifying + // a transparency color key to be used when composing the + // layered window, all pixels painted by the window in this + // color will be transparent. That doesn't seem to be the + // case anymore, at least when used with blur behind window + // plus negative region. + LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + exStyle |= WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); + + // Using a color key not equal to black to fix the trailing + // issue. When set to black, something is making the hit test + // not resize with the window frame. + SetLayeredWindowAttributes(window->win32.handle, + RGB(0, 193, 48), 255, LWA_COLORKEY); + } + + DeleteObject(region); + } + else + { + LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + exStyle &= ~WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); + RedrawWindow(window->win32.handle, NULL, NULL, + RDW_ERASE | RDW_INVALIDATE | RDW_FRAME); + } +} + +// Translates a GLFW standard cursor to a resource ID +// +static LPWSTR translateCursorShape(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return IDC_ARROW; + case GLFW_IBEAM_CURSOR: + return IDC_IBEAM; + case GLFW_CROSSHAIR_CURSOR: + return IDC_CROSS; + case GLFW_HAND_CURSOR: + return IDC_HAND; + case GLFW_HRESIZE_CURSOR: + return IDC_SIZEWE; + case GLFW_VRESIZE_CURSOR: + return IDC_SIZENS; + } + + return NULL; +} + +// Retrieves and translates modifier keys +// +static int getKeyMods(void) +{ + int mods = 0; + + if (GetKeyState(VK_SHIFT) & (1 << 31)) + mods |= GLFW_MOD_SHIFT; + if (GetKeyState(VK_CONTROL) & (1 << 31)) + mods |= GLFW_MOD_CONTROL; + if (GetKeyState(VK_MENU) & (1 << 31)) + mods |= GLFW_MOD_ALT; + if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31)) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Retrieves and translates modifier keys +// +static int getAsyncKeyMods(void) +{ + int mods = 0; + + if (GetAsyncKeyState(VK_SHIFT) & (1 << 31)) + mods |= GLFW_MOD_SHIFT; + if (GetAsyncKeyState(VK_CONTROL) & (1 << 31)) + mods |= GLFW_MOD_CONTROL; + if (GetAsyncKeyState(VK_MENU) & (1 << 31)) + mods |= GLFW_MOD_ALT; + if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31)) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Translates a Windows key to the corresponding GLFW key +// +static int translateKey(WPARAM wParam, LPARAM lParam) +{ + // The Ctrl keys require special handling + if (wParam == VK_CONTROL) + { + MSG next; + DWORD time; + + // Right side keys have the extended key bit set + if (lParam & 0x01000000) + return GLFW_KEY_RIGHT_CONTROL; + + // HACK: Alt Gr sends Left Ctrl and then Right Alt in close sequence + // We only want the Right Alt message, so if the next message is + // Right Alt we ignore this (synthetic) Left Ctrl message + time = GetMessageTime(); + + if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) + { + if (next.message == WM_KEYDOWN || + next.message == WM_SYSKEYDOWN || + next.message == WM_KEYUP || + next.message == WM_SYSKEYUP) + { + if (next.wParam == VK_MENU && + (next.lParam & 0x01000000) && + next.time == time) + { + // Next message is Right Alt down so discard this + return _GLFW_KEY_INVALID; + } + } + } + + return GLFW_KEY_LEFT_CONTROL; + } + + if (wParam == VK_PROCESSKEY) + { + // IME notifies that keys have been filtered by setting the virtual + // key-code to VK_PROCESSKEY + return _GLFW_KEY_INVALID; + } + + return _glfw.win32.keycodes[HIWORD(lParam) & 0x1FF]; +} + +// Make the specified window and its video mode active on its monitor +// +static GLFWbool acquireMonitor(_GLFWwindow* window) +{ + GLFWvidmode mode; + GLFWbool status; + int xpos, ypos; + + if (!_glfw.win32.acquiredMonitorCount) + SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED); + if (!window->monitor->window) + _glfw.win32.acquiredMonitorCount++; + + status = _glfwSetVideoModeWin32(window->monitor, &window->videoMode); + + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + + SetWindowPos(window->win32.handle, HWND_TOPMOST, + xpos, ypos, mode.width, mode.height, + SWP_NOACTIVATE | SWP_NOCOPYBITS); + + _glfwInputMonitorWindow(window->monitor, window); + return status; +} + +// Remove the window and restore the original video mode +// +static void releaseMonitor(_GLFWwindow* window) +{ + if (window->monitor->window != window) + return; + + _glfw.win32.acquiredMonitorCount--; + if (!_glfw.win32.acquiredMonitorCount) + SetThreadExecutionState(ES_CONTINUOUS); + + _glfwInputMonitorWindow(window->monitor, NULL); + _glfwRestoreVideoModeWin32(window->monitor); +} + +// Window callback function (handles window messages) +// +static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + _GLFWwindow* window = GetPropW(hWnd, L"GLFW"); + if (!window) + { + // This is the message handling for the hidden helper window + + switch (uMsg) + { + case WM_DISPLAYCHANGE: + _glfwPollMonitorsWin32(); + break; + + case WM_DEVICECHANGE: + { + if (wParam == DBT_DEVICEARRIVAL) + { + DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; + if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + _glfwDetectJoystickConnectionWin32(); + } + else if (wParam == DBT_DEVICEREMOVECOMPLETE) + { + DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; + if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + _glfwDetectJoystickDisconnectionWin32(); + } + + break; + } + } + + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + + switch (uMsg) + { + case WM_MOUSEACTIVATE: + { + // HACK: Postpone cursor disabling when the window was activated by + // clicking a caption button + if (HIWORD(lParam) == WM_LBUTTONDOWN) + { + if (LOWORD(lParam) == HTCLOSE || + LOWORD(lParam) == HTMINBUTTON || + LOWORD(lParam) == HTMAXBUTTON) + { + window->win32.frameAction = GLFW_TRUE; + } + } + + break; + } + + case WM_CAPTURECHANGED: + { + // HACK: Disable the cursor once the caption button action has been + // completed or cancelled + if (lParam == 0 && window->win32.frameAction) + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + + window->win32.frameAction = GLFW_FALSE; + } + + break; + } + + case WM_SETFOCUS: + { + _glfwInputWindowFocus(window, GLFW_TRUE); + + // HACK: Do not disable cursor while the user is interacting with + // a caption button + if (window->win32.frameAction) + break; + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + + return 0; + } + + case WM_KILLFOCUS: + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + + if (window->monitor && window->autoIconify) + _glfwPlatformIconifyWindow(window); + + _glfwInputWindowFocus(window, GLFW_FALSE); + return 0; + } + + case WM_SYSCOMMAND: + { + switch (wParam & 0xfff0) + { + case SC_SCREENSAVE: + case SC_MONITORPOWER: + { + if (window->monitor) + { + // We are running in full screen mode, so disallow + // screen saver and screen blanking + return 0; + } + else + break; + } + + // User trying to access application menu using ALT? + case SC_KEYMENU: + return 0; + } + break; + } + + case WM_CLOSE: + { + _glfwInputWindowCloseRequest(window); + return 0; + } + + case WM_INPUTLANGCHANGE: + { + _glfwUpdateKeyNamesWin32(); + break; + } + + case WM_CHAR: + case WM_SYSCHAR: + case WM_UNICHAR: + { + const GLFWbool plain = (uMsg != WM_SYSCHAR); + + if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR) + { + // WM_UNICHAR is not sent by Windows, but is sent by some + // third-party input method engine + // Returning TRUE here announces support for this message + return TRUE; + } + + _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), plain); + return 0; + } + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + { + const int key = translateKey(wParam, lParam); + const int scancode = (lParam >> 16) & 0x1ff; + const int action = ((lParam >> 31) & 1) ? GLFW_RELEASE : GLFW_PRESS; + const int mods = getKeyMods(); + + if (key == _GLFW_KEY_INVALID) + break; + + if (action == GLFW_RELEASE && wParam == VK_SHIFT) + { + // HACK: Release both Shift keys on Shift up event, as when both + // are pressed the first release does not emit any event + // NOTE: The other half of this is in _glfwPlatformPollEvents + _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods); + _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods); + } + else if (wParam == VK_SNAPSHOT) + { + // HACK: Key down is not reported for the Print Screen key + _glfwInputKey(window, key, scancode, GLFW_PRESS, mods); + _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); + } + else + _glfwInputKey(window, key, scancode, action, mods); + + break; + } + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_XBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + { + int i, button, action; + + if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP) + button = GLFW_MOUSE_BUTTON_LEFT; + else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP) + button = GLFW_MOUSE_BUTTON_RIGHT; + else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP) + button = GLFW_MOUSE_BUTTON_MIDDLE; + else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) + button = GLFW_MOUSE_BUTTON_4; + else + button = GLFW_MOUSE_BUTTON_5; + + if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || + uMsg == WM_MBUTTONDOWN || uMsg == WM_XBUTTONDOWN) + { + action = GLFW_PRESS; + } + else + action = GLFW_RELEASE; + + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window->mouseButtons[i] == GLFW_PRESS) + break; + } + + if (i > GLFW_MOUSE_BUTTON_LAST) + SetCapture(hWnd); + + _glfwInputMouseClick(window, button, action, getKeyMods()); + + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window->mouseButtons[i] == GLFW_PRESS) + break; + } + + if (i > GLFW_MOUSE_BUTTON_LAST) + ReleaseCapture(); + + if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP) + return TRUE; + + return 0; + } + + case WM_MOUSEMOVE: + { + const int x = GET_X_LPARAM(lParam); + const int y = GET_Y_LPARAM(lParam); + + // Disabled cursor motion input is provided by WM_INPUT + if (window->cursorMode == GLFW_CURSOR_DISABLED) + break; + + _glfwInputCursorPos(window, x, y); + + window->win32.lastCursorPosX = x; + window->win32.lastCursorPosY = y; + + if (!window->win32.cursorTracked) + { + TRACKMOUSEEVENT tme; + ZeroMemory(&tme, sizeof(tme)); + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = window->win32.handle; + TrackMouseEvent(&tme); + + window->win32.cursorTracked = GLFW_TRUE; + _glfwInputCursorEnter(window, GLFW_TRUE); + } + + return 0; + } + + case WM_INPUT: + { + UINT size; + HRAWINPUT ri = (HRAWINPUT) lParam; + RAWINPUT* data; + int dx, dy; + + // Only process input when disabled cursor mode is applied + if (_glfw.win32.disabledCursorWindow != window) + break; + + GetRawInputData(ri, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + if (size > (UINT) _glfw.win32.rawInputSize) + { + free(_glfw.win32.rawInput); + _glfw.win32.rawInput = calloc(size, 1); + _glfw.win32.rawInputSize = size; + } + + size = _glfw.win32.rawInputSize; + if (GetRawInputData(ri, RID_INPUT, + _glfw.win32.rawInput, &size, + sizeof(RAWINPUTHEADER)) == (UINT) -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to retrieve raw input data"); + break; + } + + data = _glfw.win32.rawInput; + if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) + { + dx = data->data.mouse.lLastX - window->win32.lastCursorPosX; + dy = data->data.mouse.lLastY - window->win32.lastCursorPosY; + } + else + { + dx = data->data.mouse.lLastX; + dy = data->data.mouse.lLastY; + } + + _glfwInputCursorPos(window, + window->virtualCursorPosX + dx, + window->virtualCursorPosY + dy); + + window->win32.lastCursorPosX += dx; + window->win32.lastCursorPosY += dy; + break; + } + + case WM_MOUSELEAVE: + { + window->win32.cursorTracked = GLFW_FALSE; + _glfwInputCursorEnter(window, GLFW_FALSE); + return 0; + } + + case WM_MOUSEWHEEL: + { + _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA); + return 0; + } + + case WM_MOUSEHWHEEL: + { + // This message is only sent on Windows Vista and later + // NOTE: The X-axis is inverted for consistency with macOS and X11 + _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0); + return 0; + } + + case WM_ENTERSIZEMOVE: + case WM_ENTERMENULOOP: + { + // HACK: Postpone cursor disabling while the user is moving or + // resizing the window or using the menu + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + + break; + } + + case WM_EXITSIZEMOVE: + case WM_EXITMENULOOP: + { + // HACK: Disable the cursor once the user is done moving or + // resizing the window or using the menu + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + + break; + } + + case WM_SIZE: + { + const GLFWbool iconified = wParam == SIZE_MINIMIZED; + const GLFWbool maximized = wParam == SIZE_MAXIMIZED || + (window->win32.maximized && + wParam != SIZE_RESTORED); + + if (_glfw.win32.disabledCursorWindow == window) + updateClipRect(window); + + if (window->win32.iconified != iconified) + _glfwInputWindowIconify(window, iconified); + + if (window->win32.maximized != maximized) + _glfwInputWindowMaximize(window, maximized); + + _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); + _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); + + if (window->monitor && window->win32.iconified != iconified) + { + if (iconified) + releaseMonitor(window); + else + acquireMonitor(window); + } + + window->win32.iconified = iconified; + window->win32.maximized = maximized; + return 0; + } + + case WM_MOVE: + { + if (_glfw.win32.disabledCursorWindow == window) + updateClipRect(window); + + // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as + // those macros do not handle negative window positions correctly + _glfwInputWindowPos(window, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam)); + return 0; + } + + case WM_SIZING: + { + if (window->numer == GLFW_DONT_CARE || + window->denom == GLFW_DONT_CARE) + { + break; + } + + applyAspectRatio(window, (int) wParam, (RECT*) lParam); + return TRUE; + } + + case WM_GETMINMAXINFO: + { + int xoff, yoff; + MINMAXINFO* mmi = (MINMAXINFO*) lParam; + + if (window->monitor) + break; + + getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), + 0, 0, &xoff, &yoff); + + if (window->minwidth != GLFW_DONT_CARE && + window->minheight != GLFW_DONT_CARE) + { + mmi->ptMinTrackSize.x = window->minwidth + xoff; + mmi->ptMinTrackSize.y = window->minheight + yoff; + } + + if (window->maxwidth != GLFW_DONT_CARE && + window->maxheight != GLFW_DONT_CARE) + { + mmi->ptMaxTrackSize.x = window->maxwidth + xoff; + mmi->ptMaxTrackSize.y = window->maxheight + yoff; + } + + if (!window->decorated) + { + MONITORINFO mi; + const HMONITOR mh = MonitorFromWindow(window->win32.handle, + MONITOR_DEFAULTTONEAREST); + + ZeroMemory(&mi, sizeof(mi)); + mi.cbSize = sizeof(mi); + GetMonitorInfo(mh, &mi); + + mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left; + mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top; + mmi->ptMaxSize.x = mi.rcWork.right - mi.rcWork.left; + mmi->ptMaxSize.y = mi.rcWork.bottom - mi.rcWork.top; + } + + return 0; + } + + case WM_PAINT: + { + _glfwInputWindowDamage(window); + break; + } + + case WM_ERASEBKGND: + { + return TRUE; + } + + case WM_DWMCOMPOSITIONCHANGED: + { + if (window->win32.transparent) + updateFramebufferTransparency(window); + return 0; + } + + case WM_SETCURSOR: + { + if (LOWORD(lParam) == HTCLIENT) + { + updateCursorImage(window); + return TRUE; + } + + break; + } + + case WM_DROPFILES: + { + HDROP drop = (HDROP) wParam; + POINT pt; + int i; + + const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0); + char** paths = calloc(count, sizeof(char*)); + + // Move the mouse to the position of the drop + DragQueryPoint(drop, &pt); + _glfwInputCursorPos(window, pt.x, pt.y); + + for (i = 0; i < count; i++) + { + const UINT length = DragQueryFileW(drop, i, NULL, 0); + WCHAR* buffer = calloc(length + 1, sizeof(WCHAR)); + + DragQueryFileW(drop, i, buffer, length + 1); + paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer); + + free(buffer); + } + + _glfwInputDrop(window, count, (const char**) paths); + + for (i = 0; i < count; i++) + free(paths[i]); + free(paths); + + DragFinish(drop); + return 0; + } + } + + return DefWindowProcW(hWnd, uMsg, wParam, lParam); +} + +// Creates the GLFW window +// +static int createNativeWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ + int xpos, ypos, fullWidth, fullHeight; + WCHAR* wideTitle; + DWORD style = getWindowStyle(window); + DWORD exStyle = getWindowExStyle(window); + + if (window->monitor) + { + GLFWvidmode mode; + + // NOTE: This window placement is temporary and approximate, as the + // correct position and size cannot be known until the monitor + // video mode has been picked in _glfwSetVideoModeWin32 + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + _glfwPlatformGetVideoMode(window->monitor, &mode); + fullWidth = mode.width; + fullHeight = mode.height; + } + else + { + xpos = CW_USEDEFAULT; + ypos = CW_USEDEFAULT; + + if (wndconfig->maximized) + style |= WS_MAXIMIZE; + + getFullWindowSize(style, exStyle, + wndconfig->width, wndconfig->height, + &fullWidth, &fullHeight); + } + + wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title); + if (!wideTitle) + return GLFW_FALSE; + + window->win32.handle = CreateWindowExW(exStyle, + _GLFW_WNDCLASSNAME, + wideTitle, + style, + xpos, ypos, + fullWidth, fullHeight, + NULL, // No parent window + NULL, // No window menu + GetModuleHandleW(NULL), + NULL); + + free(wideTitle); + + if (!window->win32.handle) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create window"); + return GLFW_FALSE; + } + + SetPropW(window->win32.handle, L"GLFW", window); + + if (IsWindows7OrGreater()) + { + ChangeWindowMessageFilterEx(window->win32.handle, + WM_DROPFILES, MSGFLT_ALLOW, NULL); + ChangeWindowMessageFilterEx(window->win32.handle, + WM_COPYDATA, MSGFLT_ALLOW, NULL); + ChangeWindowMessageFilterEx(window->win32.handle, + WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); + } + + DragAcceptFiles(window->win32.handle, TRUE); + + if (fbconfig->transparent) + { + updateFramebufferTransparency(window); + window->win32.transparent = GLFW_TRUE; + } + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Registers the GLFW window class +// +GLFWbool _glfwRegisterWindowClassWin32(void) +{ + WNDCLASSEXW wc; + + ZeroMemory(&wc, sizeof(wc)); + wc.cbSize = sizeof(wc); + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wc.lpfnWndProc = (WNDPROC) windowProc; + wc.hInstance = GetModuleHandleW(NULL); + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); + wc.lpszClassName = _GLFW_WNDCLASSNAME; + + // Load user-provided icon if available + wc.hIcon = LoadImageW(GetModuleHandleW(NULL), + L"GLFW_ICON", IMAGE_ICON, + 0, 0, LR_DEFAULTSIZE | LR_SHARED); + if (!wc.hIcon) + { + // No user-provided icon found, load default icon + wc.hIcon = LoadImageW(NULL, + IDI_APPLICATION, IMAGE_ICON, + 0, 0, LR_DEFAULTSIZE | LR_SHARED); + } + + if (!RegisterClassExW(&wc)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to register window class"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Unregisters the GLFW window class +// +void _glfwUnregisterWindowClassWin32(void) +{ + UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL)); +} + +// Returns whether desktop compositing is enabled +// +GLFWbool _glfwIsCompositionEnabledWin32(void) +{ + if (IsWindowsVistaOrGreater()) + { + BOOL enabled; + if (SUCCEEDED(DwmIsCompositionEnabled(&enabled))) + return enabled; + } + + return FALSE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!createNativeWindow(window, wndconfig, fbconfig)) + return GLFW_FALSE; + + if (ctxconfig->client != GLFW_NO_API) + { + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwInitWGL()) + return GLFW_FALSE; + if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwInitOSMesa()) + return GLFW_FALSE; + if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + } + + if (window->monitor) + { + _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); + if (!acquireMonitor(window)) + return GLFW_FALSE; + + if (wndconfig->centerCursor) + centerCursor(window); + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (window->monitor) + releaseMonitor(window); + + if (window->context.destroy) + window->context.destroy(window); + + if (_glfw.win32.disabledCursorWindow == window) + _glfw.win32.disabledCursorWindow = NULL; + + if (window->win32.handle) + { + RemovePropW(window->win32.handle, L"GLFW"); + DestroyWindow(window->win32.handle); + window->win32.handle = NULL; + } + + if (window->win32.bigIcon) + DestroyIcon(window->win32.bigIcon); + + if (window->win32.smallIcon) + DestroyIcon(window->win32.smallIcon); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ + WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title); + if (!wideTitle) + return; + + SetWindowTextW(window->win32.handle, wideTitle); + free(wideTitle); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + HICON bigIcon = NULL, smallIcon = NULL; + + if (count) + { + const GLFWimage* bigImage = chooseImage(count, images, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON)); + const GLFWimage* smallImage = chooseImage(count, images, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON)); + + bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE); + smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE); + } + else + { + bigIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICON); + smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM); + } + + SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); + SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); + + if (window->win32.bigIcon) + DestroyIcon(window->win32.bigIcon); + + if (window->win32.smallIcon) + DestroyIcon(window->win32.smallIcon); + + if (count) + { + window->win32.bigIcon = bigIcon; + window->win32.smallIcon = smallIcon; + } +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + POINT pos = { 0, 0 }; + ClientToScreen(window->win32.handle, &pos); + + if (xpos) + *xpos = pos.x; + if (ypos) + *ypos = pos.y; +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + RECT rect = { xpos, ypos, xpos, ypos }; + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + RECT area; + GetClientRect(window->win32.handle, &area); + + if (width) + *width = area.right; + if (height) + *height = area.bottom; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + if (window->monitor) + { + if (window->monitor->window == window) + acquireMonitor(window); + } + else + { + RECT rect = { 0, 0, width, height }; + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, HWND_TOP, + 0, 0, rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); + } +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + RECT area; + + if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) && + (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)) + { + return; + } + + GetWindowRect(window->win32.handle, &area); + MoveWindow(window->win32.handle, + area.left, area.top, + area.right - area.left, + area.bottom - area.top, TRUE); +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +{ + RECT area; + + if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) + return; + + GetWindowRect(window->win32.handle, &area); + applyAspectRatio(window, WMSZ_BOTTOMRIGHT, &area); + MoveWindow(window->win32.handle, + area.left, area.top, + area.right - area.left, + area.bottom - area.top, TRUE); +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + _glfwPlatformGetWindowSize(window, width, height); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + RECT rect; + int width, height; + + _glfwPlatformGetWindowSize(window, &width, &height); + SetRect(&rect, 0, 0, width, height); + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + + if (left) + *left = -rect.left; + if (top) + *top = -rect.top; + if (right) + *right = rect.right - width; + if (bottom) + *bottom = rect.bottom - height; +} + +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + const HANDLE handle = MonitorFromWindow(window->win32.handle, + MONITOR_DEFAULTTONEAREST); + _glfwGetMonitorContentScaleWin32(handle, xscale, yscale); +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_MINIMIZE); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_RESTORE); +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_MAXIMIZE); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_SHOW); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_HIDE); +} + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + FlashWindow(window->win32.handle, TRUE); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + BringWindowToTop(window->win32.handle); + SetForegroundWindow(window->win32.handle); + SetFocus(window->win32.handle); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + RECT rect = { xpos, ypos, xpos + width, ypos + height }; + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, HWND_TOP, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER); + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitor(window, monitor); + + if (monitor) + { + GLFWvidmode mode; + DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; + + if (window->decorated) + { + style &= ~WS_OVERLAPPEDWINDOW; + style |= getWindowStyle(window); + SetWindowLongW(window->win32.handle, GWL_STYLE, style); + + flags |= SWP_FRAMECHANGED; + } + + _glfwPlatformGetVideoMode(monitor, &mode); + _glfwPlatformGetMonitorPos(monitor, &xpos, &ypos); + + SetWindowPos(window->win32.handle, HWND_TOPMOST, + xpos, ypos, mode.width, mode.height, + flags); + + acquireMonitor(window); + } + else + { + HWND after; + RECT rect = { xpos, ypos, xpos + width, ypos + height }; + DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS; + + if (window->decorated) + { + style &= ~WS_POPUP; + style |= getWindowStyle(window); + SetWindowLongW(window->win32.handle, GWL_STYLE, style); + + flags |= SWP_FRAMECHANGED; + } + + if (window->floating) + after = HWND_TOPMOST; + else + after = HWND_NOTOPMOST; + + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, after, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + flags); + } +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + return window->win32.handle == GetActiveWindow(); +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + return IsIconic(window->win32.handle); +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + return IsWindowVisible(window->win32.handle); +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + return IsZoomed(window->win32.handle); +} + +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + return window->win32.transparent && _glfwIsCompositionEnabledWin32(); +} + +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) +{ + updateWindowStyles(window); +} + +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) +{ + updateWindowStyles(window); +} + +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) +{ + const HWND after = enabled ? HWND_TOPMOST : HWND_NOTOPMOST; + SetWindowPos(window->win32.handle, after, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +} + +void _glfwPlatformPollEvents(void) +{ + MSG msg; + HWND handle; + _GLFWwindow* window; + + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + // NOTE: While GLFW does not itself post WM_QUIT, other processes + // may post it to this one, for example Task Manager + // HACK: Treat WM_QUIT as a close on all windows + + window = _glfw.windowListHead; + while (window) + { + _glfwInputWindowCloseRequest(window); + window = window->next; + } + } + else + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + handle = GetActiveWindow(); + if (handle) + { + // NOTE: Shift keys on Windows tend to "stick" when both are pressed as + // no key up message is generated by the first key release + // The other half of this is in the handling of WM_KEYUP + // HACK: Query actual key state and synthesize release events as needed + window = GetPropW(handle, L"GLFW"); + if (window) + { + const GLFWbool lshift = (GetAsyncKeyState(VK_LSHIFT) >> 15) & 1; + const GLFWbool rshift = (GetAsyncKeyState(VK_RSHIFT) >> 15) & 1; + + if (!lshift && window->keys[GLFW_KEY_LEFT_SHIFT] == GLFW_PRESS) + { + const int mods = getAsyncKeyMods(); + const int scancode = _glfw.win32.scancodes[GLFW_KEY_LEFT_SHIFT]; + _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, GLFW_RELEASE, mods); + } + else if (!rshift && window->keys[GLFW_KEY_RIGHT_SHIFT] == GLFW_PRESS) + { + const int mods = getAsyncKeyMods(); + const int scancode = _glfw.win32.scancodes[GLFW_KEY_RIGHT_SHIFT]; + _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, GLFW_RELEASE, mods); + } + } + } + + window = _glfw.win32.disabledCursorWindow; + if (window) + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + + // NOTE: Re-center the cursor only if it has moved since the last call, + // to avoid breaking glfwWaitEvents with WM_MOUSEMOVE + if (window->win32.lastCursorPosX != width / 2 || + window->win32.lastCursorPosY != height / 2) + { + _glfwPlatformSetCursorPos(window, width / 2, height / 2); + } + } +} + +void _glfwPlatformWaitEvents(void) +{ + WaitMessage(); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformPostEmptyEvent(void) +{ + PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + POINT pos; + + if (GetCursorPos(&pos)) + { + ScreenToClient(window->win32.handle, &pos); + + if (xpos) + *xpos = pos.x; + if (ypos) + *ypos = pos.y; + } +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) +{ + POINT pos = { (int) xpos, (int) ypos }; + + // Store the new position so it can be recognized later + window->win32.lastCursorPosX = pos.x; + window->win32.lastCursorPosY = pos.y; + + ClientToScreen(window->win32.handle, &pos); + SetCursorPos(pos.x, pos.y); +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + if (mode == GLFW_CURSOR_DISABLED) + { + const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle }; + + _glfw.win32.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.win32.restoreCursorPosX, + &_glfw.win32.restoreCursorPosY); + centerCursor(window); + updateClipRect(window); + + if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to register raw input device"); + } + } + else if (_glfw.win32.disabledCursorWindow == window) + { + const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL }; + + _glfw.win32.disabledCursorWindow = NULL; + updateClipRect(NULL); + _glfwPlatformSetCursorPos(window, + _glfw.win32.restoreCursorPosX, + _glfw.win32.restoreCursorPosY); + + if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to remove raw input device"); + } + } + + if (cursorInClientArea(window)) + updateCursorImage(window); +} + +const char* _glfwPlatformGetScancodeName(int scancode) +{ + return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]]; +} + +int _glfwPlatformGetKeyScancode(int key) +{ + return _glfw.win32.scancodes[key]; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE); + if (!cursor->win32.handle) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + cursor->win32.handle = + CopyCursor(LoadCursorW(NULL, translateCursorShape(shape))); + if (!cursor->win32.handle) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create standard cursor"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + if (cursor->win32.handle) + DestroyIcon((HICON) cursor->win32.handle); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + if (cursorInClientArea(window)) + updateCursorImage(window); +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + int characterCount; + HANDLE object; + WCHAR* buffer; + + characterCount = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0); + if (!characterCount) + return; + + object = GlobalAlloc(GMEM_MOVEABLE, characterCount * sizeof(WCHAR)); + if (!object) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to allocate global handle for clipboard"); + return; + } + + buffer = GlobalLock(object); + if (!buffer) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to lock global handle"); + GlobalFree(object); + return; + } + + MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount); + GlobalUnlock(object); + + if (!OpenClipboard(_glfw.win32.helperWindowHandle)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to open clipboard"); + GlobalFree(object); + return; + } + + EmptyClipboard(); + SetClipboardData(CF_UNICODETEXT, object); + CloseClipboard(); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + HANDLE object; + WCHAR* buffer; + + if (!OpenClipboard(_glfw.win32.helperWindowHandle)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to open clipboard"); + return NULL; + } + + object = GetClipboardData(CF_UNICODETEXT); + if (!object) + { + _glfwInputErrorWin32(GLFW_FORMAT_UNAVAILABLE, + "Win32: Failed to convert clipboard to string"); + CloseClipboard(); + return NULL; + } + + buffer = GlobalLock(object); + if (!buffer) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to lock global handle"); + CloseClipboard(); + return NULL; + } + + free(_glfw.win32.clipboardString); + _glfw.win32.clipboardString = _glfwCreateUTF8FromWideStringWin32(buffer); + + GlobalUnlock(object); + CloseClipboard(); + + return _glfw.win32.clipboardString; +} + +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) +{ + if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_win32_surface) + return; + + extensions[0] = "VK_KHR_surface"; + extensions[1] = "VK_KHR_win32_surface"; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR + vkGetPhysicalDeviceWin32PresentationSupportKHR = + (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); + if (!vkGetPhysicalDeviceWin32PresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Win32: Vulkan instance missing VK_KHR_win32_surface extension"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily); +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + VkResult err; + VkWin32SurfaceCreateInfoKHR sci; + PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; + + vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"); + if (!vkCreateWin32SurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Win32: Vulkan instance missing VK_KHR_win32_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + sci.hinstance = GetModuleHandle(NULL); + sci.hwnd = window->win32.handle; + + err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create Vulkan surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->win32.handle; +} + diff --git a/src/external/glfw/src/window.c b/src/external/glfw/src/window.c new file mode 100644 index 00000000..30321733 --- /dev/null +++ b/src/external/glfw/src/window.c @@ -0,0 +1,1021 @@ +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2012 Torsten Walluhn +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) +{ + if (window->callbacks.focus) + window->callbacks.focus((GLFWwindow*) window, focused); + + if (!focused) + { + int key, button; + + for (key = 0; key <= GLFW_KEY_LAST; key++) + { + if (window->keys[key] == GLFW_PRESS) + { + const int scancode = _glfwPlatformGetKeyScancode(key); + _glfwInputKey(window, key, scancode, GLFW_RELEASE, 0); + } + } + + for (button = 0; button <= GLFW_MOUSE_BUTTON_LAST; button++) + { + if (window->mouseButtons[button] == GLFW_PRESS) + _glfwInputMouseClick(window, button, GLFW_RELEASE, 0); + } + } +} + +void _glfwInputWindowPos(_GLFWwindow* window, int x, int y) +{ + if (window->callbacks.pos) + window->callbacks.pos((GLFWwindow*) window, x, y); +} + +void _glfwInputWindowSize(_GLFWwindow* window, int width, int height) +{ + if (window->callbacks.size) + window->callbacks.size((GLFWwindow*) window, width, height); +} + +void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified) +{ + if (window->callbacks.iconify) + window->callbacks.iconify((GLFWwindow*) window, iconified); +} + +void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized) +{ + if (window->callbacks.maximize) + window->callbacks.maximize((GLFWwindow*) window, maximized); +} + +void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height) +{ + if (window->callbacks.fbsize) + window->callbacks.fbsize((GLFWwindow*) window, width, height); +} + +void _glfwInputWindowDamage(_GLFWwindow* window) +{ + if (window->callbacks.refresh) + window->callbacks.refresh((GLFWwindow*) window); +} + +void _glfwInputWindowCloseRequest(_GLFWwindow* window) +{ + window->shouldClose = GLFW_TRUE; + + if (window->callbacks.close) + window->callbacks.close((GLFWwindow*) window); +} + +void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor) +{ + window->monitor = monitor; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, + const char* title, + GLFWmonitor* monitor, + GLFWwindow* share) +{ + _GLFWfbconfig fbconfig; + _GLFWctxconfig ctxconfig; + _GLFWwndconfig wndconfig; + _GLFWwindow* window; + _GLFWwindow* previous; + + assert(title != NULL); + assert(width >= 0); + assert(height >= 0); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (width <= 0 || height <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window size %ix%i", + width, height); + + return NULL; + } + + fbconfig = _glfw.hints.framebuffer; + ctxconfig = _glfw.hints.context; + wndconfig = _glfw.hints.window; + + wndconfig.width = width; + wndconfig.height = height; + wndconfig.title = title; + ctxconfig.share = (_GLFWwindow*) share; + + if (ctxconfig.share) + { + if (ctxconfig.client == GLFW_NO_API || + ctxconfig.share->context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); + return NULL; + } + } + + if (!_glfwIsValidContextConfig(&ctxconfig)) + return NULL; + + window = calloc(1, sizeof(_GLFWwindow)); + window->next = _glfw.windowListHead; + _glfw.windowListHead = window; + + window->videoMode.width = width; + window->videoMode.height = height; + window->videoMode.redBits = fbconfig.redBits; + window->videoMode.greenBits = fbconfig.greenBits; + window->videoMode.blueBits = fbconfig.blueBits; + window->videoMode.refreshRate = _glfw.hints.refreshRate; + + window->monitor = (_GLFWmonitor*) monitor; + window->resizable = wndconfig.resizable; + window->decorated = wndconfig.decorated; + window->autoIconify = wndconfig.autoIconify; + window->floating = wndconfig.floating; + window->cursorMode = GLFW_CURSOR_NORMAL; + + window->minwidth = GLFW_DONT_CARE; + window->minheight = GLFW_DONT_CARE; + window->maxwidth = GLFW_DONT_CARE; + window->maxheight = GLFW_DONT_CARE; + window->numer = GLFW_DONT_CARE; + window->denom = GLFW_DONT_CARE; + + // Save the currently current context so it can be restored later + previous = _glfwPlatformGetTls(&_glfw.contextSlot); + if (ctxconfig.client != GLFW_NO_API) + glfwMakeContextCurrent(NULL); + + // Open the actual window and create its context + if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) + { + glfwMakeContextCurrent((GLFWwindow*) previous); + glfwDestroyWindow((GLFWwindow*) window); + return NULL; + } + + if (ctxconfig.client != GLFW_NO_API) + { + window->context.makeCurrent(window); + + // Retrieve the actual (as opposed to requested) context attributes + if (!_glfwRefreshContextAttribs(&ctxconfig)) + { + glfwMakeContextCurrent((GLFWwindow*) previous); + glfwDestroyWindow((GLFWwindow*) window); + return NULL; + } + + // Restore the previously current context (or NULL) + glfwMakeContextCurrent((GLFWwindow*) previous); + } + + if (!window->monitor) + { + if (wndconfig.visible) + { + _glfwPlatformShowWindow(window); + if (wndconfig.focused) + _glfwPlatformFocusWindow(window); + } + } + + return (GLFWwindow*) window; +} + +void glfwDefaultWindowHints(void) +{ + _GLFW_REQUIRE_INIT(); + + // The default is OpenGL with minimum version 1.0 + memset(&_glfw.hints.context, 0, sizeof(_glfw.hints.context)); + _glfw.hints.context.client = GLFW_OPENGL_API; + _glfw.hints.context.source = GLFW_NATIVE_CONTEXT_API; + _glfw.hints.context.major = 1; + _glfw.hints.context.minor = 0; + + // The default is a focused, visible, resizable window with decorations + memset(&_glfw.hints.window, 0, sizeof(_glfw.hints.window)); + _glfw.hints.window.resizable = GLFW_TRUE; + _glfw.hints.window.visible = GLFW_TRUE; + _glfw.hints.window.decorated = GLFW_TRUE; + _glfw.hints.window.focused = GLFW_TRUE; + _glfw.hints.window.autoIconify = GLFW_TRUE; + _glfw.hints.window.centerCursor = GLFW_TRUE; + + // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil, + // double buffered + memset(&_glfw.hints.framebuffer, 0, sizeof(_glfw.hints.framebuffer)); + _glfw.hints.framebuffer.redBits = 8; + _glfw.hints.framebuffer.greenBits = 8; + _glfw.hints.framebuffer.blueBits = 8; + _glfw.hints.framebuffer.alphaBits = 8; + _glfw.hints.framebuffer.depthBits = 24; + _glfw.hints.framebuffer.stencilBits = 8; + _glfw.hints.framebuffer.doublebuffer = GLFW_TRUE; + + // The default is to select the highest available refresh rate + _glfw.hints.refreshRate = GLFW_DONT_CARE; + + // The default is to use full Retina resolution framebuffers + _glfw.hints.window.ns.retina = GLFW_TRUE; +} + +GLFWAPI void glfwWindowHint(int hint, int value) +{ + _GLFW_REQUIRE_INIT(); + + switch (hint) + { + case GLFW_RED_BITS: + _glfw.hints.framebuffer.redBits = value; + return; + case GLFW_GREEN_BITS: + _glfw.hints.framebuffer.greenBits = value; + return; + case GLFW_BLUE_BITS: + _glfw.hints.framebuffer.blueBits = value; + return; + case GLFW_ALPHA_BITS: + _glfw.hints.framebuffer.alphaBits = value; + return; + case GLFW_DEPTH_BITS: + _glfw.hints.framebuffer.depthBits = value; + return; + case GLFW_STENCIL_BITS: + _glfw.hints.framebuffer.stencilBits = value; + return; + case GLFW_ACCUM_RED_BITS: + _glfw.hints.framebuffer.accumRedBits = value; + return; + case GLFW_ACCUM_GREEN_BITS: + _glfw.hints.framebuffer.accumGreenBits = value; + return; + case GLFW_ACCUM_BLUE_BITS: + _glfw.hints.framebuffer.accumBlueBits = value; + return; + case GLFW_ACCUM_ALPHA_BITS: + _glfw.hints.framebuffer.accumAlphaBits = value; + return; + case GLFW_AUX_BUFFERS: + _glfw.hints.framebuffer.auxBuffers = value; + return; + case GLFW_STEREO: + _glfw.hints.framebuffer.stereo = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_DOUBLEBUFFER: + _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_TRANSPARENT: + _glfw.hints.framebuffer.transparent = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_SAMPLES: + _glfw.hints.framebuffer.samples = value; + return; + case GLFW_SRGB_CAPABLE: + _glfw.hints.framebuffer.sRGB = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_RESIZABLE: + _glfw.hints.window.resizable = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_DECORATED: + _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_FOCUSED: + _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_AUTO_ICONIFY: + _glfw.hints.window.autoIconify = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_FLOATING: + _glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_MAXIMIZED: + _glfw.hints.window.maximized = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_VISIBLE: + _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_COCOA_RETINA_FRAMEBUFFER: + _glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_COCOA_FRAME_AUTOSAVE: + _glfw.hints.window.ns.frame = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_COCOA_GRAPHICS_SWITCHING: + _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_CENTER_CURSOR: + _glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_CLIENT_API: + _glfw.hints.context.client = value; + return; + case GLFW_CONTEXT_CREATION_API: + _glfw.hints.context.source = value; + return; + case GLFW_CONTEXT_VERSION_MAJOR: + _glfw.hints.context.major = value; + return; + case GLFW_CONTEXT_VERSION_MINOR: + _glfw.hints.context.minor = value; + return; + case GLFW_CONTEXT_ROBUSTNESS: + _glfw.hints.context.robustness = value; + return; + case GLFW_OPENGL_FORWARD_COMPAT: + _glfw.hints.context.forward = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_OPENGL_DEBUG_CONTEXT: + _glfw.hints.context.debug = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_CONTEXT_NO_ERROR: + _glfw.hints.context.noerror = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_OPENGL_PROFILE: + _glfw.hints.context.profile = value; + return; + case GLFW_CONTEXT_RELEASE_BEHAVIOR: + _glfw.hints.context.release = value; + return; + case GLFW_REFRESH_RATE: + _glfw.hints.refreshRate = value; + return; + } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint); +} + +GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + // Allow closing of NULL (to match the behavior of free) + if (window == NULL) + return; + + // Clear all callbacks to avoid exposing a half torn-down window object + memset(&window->callbacks, 0, sizeof(window->callbacks)); + + // The window's context must not be current on another thread when the + // window is destroyed + if (window == _glfwPlatformGetTls(&_glfw.contextSlot)) + glfwMakeContextCurrent(NULL); + + _glfwPlatformDestroyWindow(window); + + // Unlink window from global linked list + { + _GLFWwindow** prev = &_glfw.windowListHead; + + while (*prev != window) + prev = &((*prev)->next); + + *prev = window->next; + } + + free(window); +} + +GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return window->shouldClose; +} + +GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + window->shouldClose = value; +} + +GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(title != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetWindowTitle(window, title); +} + +GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle, + int count, const GLFWimage* images) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(count >= 0); + assert(count == 0 || images != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetWindowIcon(window, count, images); +} + +GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowPos(window, xpos, ypos); +} + +GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (window->monitor) + return; + + _glfwPlatformSetWindowPos(window, xpos, ypos); +} + +GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (width) + *width = 0; + if (height) + *height = 0; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowSize(window, width, height); +} + +GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(width >= 0); + assert(height >= 0); + + _GLFW_REQUIRE_INIT(); + + window->videoMode.width = width; + window->videoMode.height = height; + + _glfwPlatformSetWindowSize(window, width, height); +} + +GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (minwidth != GLFW_DONT_CARE && minheight != GLFW_DONT_CARE) + { + if (minwidth < 0 || minheight < 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window minimum size %ix%i", + minwidth, minheight); + return; + } + } + + if (maxwidth != GLFW_DONT_CARE && maxheight != GLFW_DONT_CARE) + { + if (maxwidth < 0 || maxheight < 0 || + maxwidth < minwidth || maxheight < minheight) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window maximum size %ix%i", + maxwidth, maxheight); + return; + } + } + + window->minwidth = minwidth; + window->minheight = minheight; + window->maxwidth = maxwidth; + window->maxheight = maxheight; + + if (window->monitor || !window->resizable) + return; + + _glfwPlatformSetWindowSizeLimits(window, + minwidth, minheight, + maxwidth, maxheight); +} + +GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(numer != 0); + assert(denom != 0); + + _GLFW_REQUIRE_INIT(); + + if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE) + { + if (numer <= 0 || denom <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window aspect ratio %i:%i", + numer, denom); + return; + } + } + + window->numer = numer; + window->denom = denom; + + if (window->monitor || !window->resizable) + return; + + _glfwPlatformSetWindowAspectRatio(window, numer, denom); +} + +GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (width) + *width = 0; + if (height) + *height = 0; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetFramebufferSize(window, width, height); +} + +GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, + int* left, int* top, + int* right, int* bottom) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (left) + *left = 0; + if (top) + *top = 0; + if (right) + *right = 0; + if (bottom) + *bottom = 0; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowFrameSize(window, left, top, right, bottom); +} + +GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, + float* xscale, float* yscale) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + if (xscale) + *xscale = 0.f; + if (yscale) + *yscale = 0.f; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowContentScale(window, xscale, yscale); +} + +GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformIconifyWindow(window); +} + +GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformRestoreWindow(window); +} + +GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (window->monitor) + return; + + _glfwPlatformMaximizeWindow(window); +} + +GLFWAPI void glfwShowWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (window->monitor) + return; + + _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); +} + +GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformRequestWindowAttention(window); +} + +GLFWAPI void glfwHideWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (window->monitor) + return; + + _glfwPlatformHideWindow(window); +} + +GLFWAPI void glfwFocusWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformFocusWindow(window); +} + +GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(0); + + switch (attrib) + { + case GLFW_FOCUSED: + return _glfwPlatformWindowFocused(window); + case GLFW_ICONIFIED: + return _glfwPlatformWindowIconified(window); + case GLFW_VISIBLE: + return _glfwPlatformWindowVisible(window); + case GLFW_MAXIMIZED: + return _glfwPlatformWindowMaximized(window); + case GLFW_TRANSPARENT: + return _glfwPlatformFramebufferTransparent(window); + case GLFW_RESIZABLE: + return window->resizable; + case GLFW_DECORATED: + return window->decorated; + case GLFW_FLOATING: + return window->floating; + case GLFW_AUTO_ICONIFY: + return window->autoIconify; + case GLFW_CLIENT_API: + return window->context.client; + case GLFW_CONTEXT_CREATION_API: + return window->context.source; + case GLFW_CONTEXT_VERSION_MAJOR: + return window->context.major; + case GLFW_CONTEXT_VERSION_MINOR: + return window->context.minor; + case GLFW_CONTEXT_REVISION: + return window->context.revision; + case GLFW_CONTEXT_ROBUSTNESS: + return window->context.robustness; + case GLFW_OPENGL_FORWARD_COMPAT: + return window->context.forward; + case GLFW_OPENGL_DEBUG_CONTEXT: + return window->context.debug; + case GLFW_OPENGL_PROFILE: + return window->context.profile; + case GLFW_CONTEXT_RELEASE_BEHAVIOR: + return window->context.release; + case GLFW_CONTEXT_NO_ERROR: + return window->context.noerror; + } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); + return 0; +} + +GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + value = value ? GLFW_TRUE : GLFW_FALSE; + + if (attrib == GLFW_AUTO_ICONIFY) + window->autoIconify = value; + else if (attrib == GLFW_RESIZABLE) + { + if (window->resizable == value) + return; + + window->resizable = value; + if (!window->monitor) + _glfwPlatformSetWindowResizable(window, value); + } + else if (attrib == GLFW_DECORATED) + { + if (window->decorated == value) + return; + + window->decorated = value; + if (!window->monitor) + _glfwPlatformSetWindowDecorated(window, value); + } + else if (attrib == GLFW_FLOATING) + { + if (window->floating == value) + return; + + window->floating = value; + if (!window->monitor) + _glfwPlatformSetWindowFloating(window, value); + } + else + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); +} + +GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return (GLFWmonitor*) window->monitor; +} + +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh, + GLFWmonitor* mh, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + _GLFWwindow* window = (_GLFWwindow*) wh; + _GLFWmonitor* monitor = (_GLFWmonitor*) mh; + assert(window != NULL); + assert(width >= 0); + assert(height >= 0); + + _GLFW_REQUIRE_INIT(); + + if (width <= 0 || height <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window size %ix%i", + width, height); + return; + } + + if (refreshRate < 0 && refreshRate != GLFW_DONT_CARE) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid refresh rate %i", + refreshRate); + return; + } + + window->videoMode.width = width; + window->videoMode.height = height; + window->videoMode.refreshRate = refreshRate; + + _glfwPlatformSetWindowMonitor(window, monitor, + xpos, ypos, width, height, + refreshRate); +} + +GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + window->userPointer = pointer; +} + +GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->userPointer; +} + +GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle, + GLFWwindowposfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.pos, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle, + GLFWwindowsizefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.size, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle, + GLFWwindowclosefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.close, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle, + GLFWwindowrefreshfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.refresh, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle, + GLFWwindowfocusfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.focus, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle, + GLFWwindowiconifyfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.iconify, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* handle, + GLFWwindowmaximizefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.maximize, cbfun); + return cbfun; +} + +GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle, + GLFWframebuffersizefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.fbsize, cbfun); + return cbfun; +} + +GLFWAPI void glfwPollEvents(void) +{ + _GLFW_REQUIRE_INIT(); + _glfwPlatformPollEvents(); +} + +GLFWAPI void glfwWaitEvents(void) +{ + _GLFW_REQUIRE_INIT(); + + if (!_glfw.windowListHead) + return; + + _glfwPlatformWaitEvents(); +} + +GLFWAPI void glfwWaitEventsTimeout(double timeout) +{ + _GLFW_REQUIRE_INIT(); + assert(timeout == timeout); + assert(timeout >= 0.0); + assert(timeout <= DBL_MAX); + + if (timeout != timeout || timeout < 0.0 || timeout > DBL_MAX) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", timeout); + return; + } + + _glfwPlatformWaitEventsTimeout(timeout); +} + +GLFWAPI void glfwPostEmptyEvent(void) +{ + _GLFW_REQUIRE_INIT(); + + if (!_glfw.windowListHead) + return; + + _glfwPlatformPostEmptyEvent(); +} + diff --git a/src/external/glfw/src/wl_init.c b/src/external/glfw/src/wl_init.c new file mode 100644 index 00000000..3841636f --- /dev/null +++ b/src/external/glfw/src/wl_init.c @@ -0,0 +1,792 @@ +//======================================================================== +// GLFW 3.3 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +static inline int min(int n1, int n2) +{ + return n1 < n2 ? n1 : n2; +} + +static void pointerHandleEnter(void* data, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface, + wl_fixed_t sx, + wl_fixed_t sy) +{ + _GLFWwindow* window = wl_surface_get_user_data(surface); + + _glfw.wl.pointerSerial = serial; + _glfw.wl.pointerFocus = window; + + _glfwPlatformSetCursor(window, window->wl.currentCursor); + _glfwInputCursorEnter(window, GLFW_TRUE); +} + +static void pointerHandleLeave(void* data, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + + if (!window) + return; + + _glfw.wl.pointerSerial = serial; + _glfw.wl.pointerFocus = NULL; + _glfwInputCursorEnter(window, GLFW_FALSE); +} + +static void pointerHandleMotion(void* data, + struct wl_pointer* pointer, + uint32_t time, + wl_fixed_t sx, + wl_fixed_t sy) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + + if (!window) + return; + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + return; + else + { + window->wl.cursorPosX = wl_fixed_to_double(sx); + window->wl.cursorPosY = wl_fixed_to_double(sy); + } + + _glfwInputCursorPos(window, + wl_fixed_to_double(sx), + wl_fixed_to_double(sy)); +} + +static void pointerHandleButton(void* data, + struct wl_pointer* wl_pointer, + uint32_t serial, + uint32_t time, + uint32_t button, + uint32_t state) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + int glfwButton; + + if (!window) + return; + + _glfw.wl.pointerSerial = serial; + + /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev + * codes. */ + glfwButton = button - BTN_LEFT; + + _glfwInputMouseClick(window, + glfwButton, + state == WL_POINTER_BUTTON_STATE_PRESSED + ? GLFW_PRESS + : GLFW_RELEASE, + _glfw.wl.xkb.modifiers); +} + +static void pointerHandleAxis(void* data, + struct wl_pointer* wl_pointer, + uint32_t time, + uint32_t axis, + wl_fixed_t value) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + double scrollFactor; + double x, y; + + if (!window) + return; + + /* Wayland scroll events are in pointer motion coordinate space (think + * two finger scroll). The factor 10 is commonly used to convert to + * "scroll step means 1.0. */ + scrollFactor = 1.0/10.0; + + switch (axis) + { + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + x = wl_fixed_to_double(value) * scrollFactor; + y = 0.0; + break; + case WL_POINTER_AXIS_VERTICAL_SCROLL: + x = 0.0; + y = wl_fixed_to_double(value) * scrollFactor; + break; + default: + break; + } + + _glfwInputScroll(window, x, y); +} + +static const struct wl_pointer_listener pointerListener = { + pointerHandleEnter, + pointerHandleLeave, + pointerHandleMotion, + pointerHandleButton, + pointerHandleAxis, +}; + +static void keyboardHandleKeymap(void* data, + struct wl_keyboard* keyboard, + uint32_t format, + int fd, + uint32_t size) +{ + struct xkb_keymap* keymap; + struct xkb_state* state; + struct xkb_compose_table* composeTable; + struct xkb_compose_state* composeState; + char* mapStr; + const char* locale; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) + { + close(fd); + return; + } + + mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (mapStr == MAP_FAILED) { + close(fd); + return; + } + + keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context, + mapStr, + XKB_KEYMAP_FORMAT_TEXT_V1, + 0); + munmap(mapStr, size); + close(fd); + + if (!keymap) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to compile keymap"); + return; + } + + state = xkb_state_new(keymap); + if (!state) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create XKB state"); + xkb_keymap_unref(keymap); + return; + } + + // Look up the preferred locale, falling back to "C" as default. + locale = getenv("LC_ALL"); + if (!locale) + locale = getenv("LC_CTYPE"); + if (!locale) + locale = getenv("LANG"); + if (!locale) + locale = "C"; + + composeTable = + xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale, + XKB_COMPOSE_COMPILE_NO_FLAGS); + if (composeTable) + { + composeState = + xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS); + xkb_compose_table_unref(composeTable); + if (composeState) + _glfw.wl.xkb.composeState = composeState; + else + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create XKB compose state"); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create XKB compose table"); + } + + xkb_keymap_unref(_glfw.wl.xkb.keymap); + xkb_state_unref(_glfw.wl.xkb.state); + _glfw.wl.xkb.keymap = keymap; + _glfw.wl.xkb.state = state; + + _glfw.wl.xkb.controlMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control"); + _glfw.wl.xkb.altMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1"); + _glfw.wl.xkb.shiftMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); + _glfw.wl.xkb.superMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); +} + +static void keyboardHandleEnter(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface, + struct wl_array* keys) +{ + _GLFWwindow* window = wl_surface_get_user_data(surface); + + _glfw.wl.keyboardFocus = window; + _glfwInputWindowFocus(window, GLFW_TRUE); +} + +static void keyboardHandleLeave(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface) +{ + _GLFWwindow* window = _glfw.wl.keyboardFocus; + + if (!window) + return; + + _glfw.wl.keyboardFocus = NULL; + _glfwInputWindowFocus(window, GLFW_FALSE); +} + +static int toGLFWKeyCode(uint32_t key) +{ + if (key < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0])) + return _glfw.wl.keycodes[key]; + + return GLFW_KEY_UNKNOWN; +} + +static xkb_keysym_t composeSymbol(xkb_keysym_t sym) +{ + if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState) + return sym; + if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym) + != XKB_COMPOSE_FEED_ACCEPTED) + return sym; + switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState)) + { + case XKB_COMPOSE_COMPOSED: + return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState); + case XKB_COMPOSE_COMPOSING: + case XKB_COMPOSE_CANCELLED: + return XKB_KEY_NoSymbol; + case XKB_COMPOSE_NOTHING: + default: + return sym; + } +} + +static void inputChar(_GLFWwindow* window, uint32_t key) +{ + uint32_t code, numSyms; + long cp; + const xkb_keysym_t *syms; + xkb_keysym_t sym; + + code = key + 8; + numSyms = xkb_state_key_get_syms(_glfw.wl.xkb.state, code, &syms); + + if (numSyms == 1) + { + sym = composeSymbol(syms[0]); + cp = _glfwKeySym2Unicode(sym); + if (cp != -1) + { + const int mods = _glfw.wl.xkb.modifiers; + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + _glfwInputChar(window, cp, mods, plain); + } + } +} + +static void keyboardHandleKey(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state) +{ + int keyCode; + int action; + _GLFWwindow* window = _glfw.wl.keyboardFocus; + + if (!window) + return; + + keyCode = toGLFWKeyCode(key); + action = state == WL_KEYBOARD_KEY_STATE_PRESSED + ? GLFW_PRESS : GLFW_RELEASE; + + _glfwInputKey(window, keyCode, key, action, + _glfw.wl.xkb.modifiers); + + if (action == GLFW_PRESS) + inputChar(window, key); +} + +static void keyboardHandleModifiers(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t modsDepressed, + uint32_t modsLatched, + uint32_t modsLocked, + uint32_t group) +{ + xkb_mod_mask_t mask; + unsigned int modifiers = 0; + + if (!_glfw.wl.xkb.keymap) + return; + + xkb_state_update_mask(_glfw.wl.xkb.state, + modsDepressed, + modsLatched, + modsLocked, + 0, + 0, + group); + + mask = xkb_state_serialize_mods(_glfw.wl.xkb.state, + XKB_STATE_MODS_DEPRESSED | + XKB_STATE_LAYOUT_DEPRESSED | + XKB_STATE_MODS_LATCHED | + XKB_STATE_LAYOUT_LATCHED); + if (mask & _glfw.wl.xkb.controlMask) + modifiers |= GLFW_MOD_CONTROL; + if (mask & _glfw.wl.xkb.altMask) + modifiers |= GLFW_MOD_ALT; + if (mask & _glfw.wl.xkb.shiftMask) + modifiers |= GLFW_MOD_SHIFT; + if (mask & _glfw.wl.xkb.superMask) + modifiers |= GLFW_MOD_SUPER; + _glfw.wl.xkb.modifiers = modifiers; +} + +static const struct wl_keyboard_listener keyboardListener = { + keyboardHandleKeymap, + keyboardHandleEnter, + keyboardHandleLeave, + keyboardHandleKey, + keyboardHandleModifiers, +}; + +static void seatHandleCapabilities(void* data, + struct wl_seat* seat, + enum wl_seat_capability caps) +{ + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer) + { + _glfw.wl.pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL); + } + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer) + { + wl_pointer_destroy(_glfw.wl.pointer); + _glfw.wl.pointer = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard) + { + _glfw.wl.keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL); + } + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard) + { + wl_keyboard_destroy(_glfw.wl.keyboard); + _glfw.wl.keyboard = NULL; + } +} + +static const struct wl_seat_listener seatListener = { + seatHandleCapabilities +}; + +static void registryHandleGlobal(void* data, + struct wl_registry* registry, + uint32_t name, + const char* interface, + uint32_t version) +{ + if (strcmp(interface, "wl_compositor") == 0) + { + _glfw.wl.compositorVersion = min(3, version); + _glfw.wl.compositor = + wl_registry_bind(registry, name, &wl_compositor_interface, + _glfw.wl.compositorVersion); + } + else if (strcmp(interface, "wl_shm") == 0) + { + _glfw.wl.shm = + wl_registry_bind(registry, name, &wl_shm_interface, 1); + } + else if (strcmp(interface, "wl_shell") == 0) + { + _glfw.wl.shell = + wl_registry_bind(registry, name, &wl_shell_interface, 1); + } + else if (strcmp(interface, "wl_output") == 0) + { + _glfwAddOutputWayland(name, version); + } + else if (strcmp(interface, "wl_seat") == 0) + { + if (!_glfw.wl.seat) + { + _glfw.wl.seat = + wl_registry_bind(registry, name, &wl_seat_interface, 1); + wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL); + } + } + else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) + { + _glfw.wl.relativePointerManager = + wl_registry_bind(registry, name, + &zwp_relative_pointer_manager_v1_interface, + 1); + } + else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) + { + _glfw.wl.pointerConstraints = + wl_registry_bind(registry, name, + &zwp_pointer_constraints_v1_interface, + 1); + } +} + +static void registryHandleGlobalRemove(void *data, + struct wl_registry *registry, + uint32_t name) +{ +} + + +static const struct wl_registry_listener registryListener = { + registryHandleGlobal, + registryHandleGlobalRemove +}; + +// Create key code translation tables +// +static void createKeyTables(void) +{ + int scancode; + + memset(_glfw.wl.keycodes, -1, sizeof(_glfw.wl.keycodes)); + memset(_glfw.wl.scancodes, -1, sizeof(_glfw.wl.scancodes)); + + _glfw.wl.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT; + _glfw.wl.keycodes[KEY_1] = GLFW_KEY_1; + _glfw.wl.keycodes[KEY_2] = GLFW_KEY_2; + _glfw.wl.keycodes[KEY_3] = GLFW_KEY_3; + _glfw.wl.keycodes[KEY_4] = GLFW_KEY_4; + _glfw.wl.keycodes[KEY_5] = GLFW_KEY_5; + _glfw.wl.keycodes[KEY_6] = GLFW_KEY_6; + _glfw.wl.keycodes[KEY_7] = GLFW_KEY_7; + _glfw.wl.keycodes[KEY_8] = GLFW_KEY_8; + _glfw.wl.keycodes[KEY_9] = GLFW_KEY_9; + _glfw.wl.keycodes[KEY_0] = GLFW_KEY_0; + _glfw.wl.keycodes[KEY_SPACE] = GLFW_KEY_SPACE; + _glfw.wl.keycodes[KEY_MINUS] = GLFW_KEY_MINUS; + _glfw.wl.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL; + _glfw.wl.keycodes[KEY_Q] = GLFW_KEY_Q; + _glfw.wl.keycodes[KEY_W] = GLFW_KEY_W; + _glfw.wl.keycodes[KEY_E] = GLFW_KEY_E; + _glfw.wl.keycodes[KEY_R] = GLFW_KEY_R; + _glfw.wl.keycodes[KEY_T] = GLFW_KEY_T; + _glfw.wl.keycodes[KEY_Y] = GLFW_KEY_Y; + _glfw.wl.keycodes[KEY_U] = GLFW_KEY_U; + _glfw.wl.keycodes[KEY_I] = GLFW_KEY_I; + _glfw.wl.keycodes[KEY_O] = GLFW_KEY_O; + _glfw.wl.keycodes[KEY_P] = GLFW_KEY_P; + _glfw.wl.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET; + _glfw.wl.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET; + _glfw.wl.keycodes[KEY_A] = GLFW_KEY_A; + _glfw.wl.keycodes[KEY_S] = GLFW_KEY_S; + _glfw.wl.keycodes[KEY_D] = GLFW_KEY_D; + _glfw.wl.keycodes[KEY_F] = GLFW_KEY_F; + _glfw.wl.keycodes[KEY_G] = GLFW_KEY_G; + _glfw.wl.keycodes[KEY_H] = GLFW_KEY_H; + _glfw.wl.keycodes[KEY_J] = GLFW_KEY_J; + _glfw.wl.keycodes[KEY_K] = GLFW_KEY_K; + _glfw.wl.keycodes[KEY_L] = GLFW_KEY_L; + _glfw.wl.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON; + _glfw.wl.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE; + _glfw.wl.keycodes[KEY_Z] = GLFW_KEY_Z; + _glfw.wl.keycodes[KEY_X] = GLFW_KEY_X; + _glfw.wl.keycodes[KEY_C] = GLFW_KEY_C; + _glfw.wl.keycodes[KEY_V] = GLFW_KEY_V; + _glfw.wl.keycodes[KEY_B] = GLFW_KEY_B; + _glfw.wl.keycodes[KEY_N] = GLFW_KEY_N; + _glfw.wl.keycodes[KEY_M] = GLFW_KEY_M; + _glfw.wl.keycodes[KEY_COMMA] = GLFW_KEY_COMMA; + _glfw.wl.keycodes[KEY_DOT] = GLFW_KEY_PERIOD; + _glfw.wl.keycodes[KEY_SLASH] = GLFW_KEY_SLASH; + _glfw.wl.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH; + _glfw.wl.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE; + _glfw.wl.keycodes[KEY_TAB] = GLFW_KEY_TAB; + _glfw.wl.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT; + _glfw.wl.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT; + _glfw.wl.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL; + _glfw.wl.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL; + _glfw.wl.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT; + _glfw.wl.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT; + _glfw.wl.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER; + _glfw.wl.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER; + _glfw.wl.keycodes[KEY_MENU] = GLFW_KEY_MENU; + _glfw.wl.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK; + _glfw.wl.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK; + _glfw.wl.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN; + _glfw.wl.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK; + _glfw.wl.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE; + _glfw.wl.keycodes[KEY_DELETE] = GLFW_KEY_DELETE; + _glfw.wl.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE; + _glfw.wl.keycodes[KEY_ENTER] = GLFW_KEY_ENTER; + _glfw.wl.keycodes[KEY_HOME] = GLFW_KEY_HOME; + _glfw.wl.keycodes[KEY_END] = GLFW_KEY_END; + _glfw.wl.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP; + _glfw.wl.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN; + _glfw.wl.keycodes[KEY_INSERT] = GLFW_KEY_INSERT; + _glfw.wl.keycodes[KEY_LEFT] = GLFW_KEY_LEFT; + _glfw.wl.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT; + _glfw.wl.keycodes[KEY_DOWN] = GLFW_KEY_DOWN; + _glfw.wl.keycodes[KEY_UP] = GLFW_KEY_UP; + _glfw.wl.keycodes[KEY_F1] = GLFW_KEY_F1; + _glfw.wl.keycodes[KEY_F2] = GLFW_KEY_F2; + _glfw.wl.keycodes[KEY_F3] = GLFW_KEY_F3; + _glfw.wl.keycodes[KEY_F4] = GLFW_KEY_F4; + _glfw.wl.keycodes[KEY_F5] = GLFW_KEY_F5; + _glfw.wl.keycodes[KEY_F6] = GLFW_KEY_F6; + _glfw.wl.keycodes[KEY_F7] = GLFW_KEY_F7; + _glfw.wl.keycodes[KEY_F8] = GLFW_KEY_F8; + _glfw.wl.keycodes[KEY_F9] = GLFW_KEY_F9; + _glfw.wl.keycodes[KEY_F10] = GLFW_KEY_F10; + _glfw.wl.keycodes[KEY_F11] = GLFW_KEY_F11; + _glfw.wl.keycodes[KEY_F12] = GLFW_KEY_F12; + _glfw.wl.keycodes[KEY_F13] = GLFW_KEY_F13; + _glfw.wl.keycodes[KEY_F14] = GLFW_KEY_F14; + _glfw.wl.keycodes[KEY_F15] = GLFW_KEY_F15; + _glfw.wl.keycodes[KEY_F16] = GLFW_KEY_F16; + _glfw.wl.keycodes[KEY_F17] = GLFW_KEY_F17; + _glfw.wl.keycodes[KEY_F18] = GLFW_KEY_F18; + _glfw.wl.keycodes[KEY_F19] = GLFW_KEY_F19; + _glfw.wl.keycodes[KEY_F20] = GLFW_KEY_F20; + _glfw.wl.keycodes[KEY_F21] = GLFW_KEY_F21; + _glfw.wl.keycodes[KEY_F22] = GLFW_KEY_F22; + _glfw.wl.keycodes[KEY_F23] = GLFW_KEY_F23; + _glfw.wl.keycodes[KEY_F24] = GLFW_KEY_F24; + _glfw.wl.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE; + _glfw.wl.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY; + _glfw.wl.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT; + _glfw.wl.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD; + _glfw.wl.keycodes[KEY_KP0] = GLFW_KEY_KP_0; + _glfw.wl.keycodes[KEY_KP1] = GLFW_KEY_KP_1; + _glfw.wl.keycodes[KEY_KP2] = GLFW_KEY_KP_2; + _glfw.wl.keycodes[KEY_KP3] = GLFW_KEY_KP_3; + _glfw.wl.keycodes[KEY_KP4] = GLFW_KEY_KP_4; + _glfw.wl.keycodes[KEY_KP5] = GLFW_KEY_KP_5; + _glfw.wl.keycodes[KEY_KP6] = GLFW_KEY_KP_6; + _glfw.wl.keycodes[KEY_KP7] = GLFW_KEY_KP_7; + _glfw.wl.keycodes[KEY_KP8] = GLFW_KEY_KP_8; + _glfw.wl.keycodes[KEY_KP9] = GLFW_KEY_KP_9; + _glfw.wl.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL; + _glfw.wl.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL; + _glfw.wl.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER; + + for (scancode = 0; scancode < 256; scancode++) + { + if (_glfw.wl.keycodes[scancode] > 0) + _glfw.wl.scancodes[_glfw.wl.keycodes[scancode]] = scancode; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + _glfw.wl.xkb.handle = dlopen("libxkbcommon.so.0", RTLD_LAZY | RTLD_GLOBAL); + if (!_glfw.wl.xkb.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to open libxkbcommon."); + return GLFW_FALSE; + } + + _glfw.wl.xkb.context_new = (PFN_xkb_context_new) + dlsym(_glfw.wl.xkb.handle, "xkb_context_new"); + _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref) + dlsym(_glfw.wl.xkb.handle, "xkb_context_unref"); + _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string) + dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string"); + _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref) + dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref"); + _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index) + dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); + _glfw.wl.xkb.state_new = (PFN_xkb_state_new) + dlsym(_glfw.wl.xkb.handle, "xkb_state_new"); + _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref) + dlsym(_glfw.wl.xkb.handle, "xkb_state_unref"); + _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms) + dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms"); + _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask) + dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask"); + _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods) + dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods"); + _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale"); + _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref"); + _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new"); + _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref"); + _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed"); + _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status"); + _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym) + dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); + + _glfw.wl.display = wl_display_connect(NULL); + if (!_glfw.wl.display) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to connect to display"); + return GLFW_FALSE; + } + + _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display); + wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL); + + createKeyTables(); + + _glfw.wl.xkb.context = xkb_context_new(0); + if (!_glfw.wl.xkb.context) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to initialize xkb context"); + return GLFW_FALSE; + } + + // Sync so we got all registry objects + wl_display_roundtrip(_glfw.wl.display); + + // Sync so we got all initial output events + wl_display_roundtrip(_glfw.wl.display); + + if (!_glfwInitJoysticksLinux()) + return GLFW_FALSE; + + _glfwInitTimerPOSIX(); + + if (_glfw.wl.pointer && _glfw.wl.shm) + { + _glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm); + if (!_glfw.wl.cursorTheme) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unable to load default cursor theme\n"); + return GLFW_FALSE; + } + _glfw.wl.cursorSurface = + wl_compositor_create_surface(_glfw.wl.compositor); + } + + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + _glfwTerminateEGL(); + _glfwTerminateJoysticksLinux(); + + xkb_compose_state_unref(_glfw.wl.xkb.composeState); + xkb_keymap_unref(_glfw.wl.xkb.keymap); + xkb_state_unref(_glfw.wl.xkb.state); + xkb_context_unref(_glfw.wl.xkb.context); + + dlclose(_glfw.wl.xkb.handle); + _glfw.wl.xkb.handle = NULL; + + if (_glfw.wl.cursorTheme) + wl_cursor_theme_destroy(_glfw.wl.cursorTheme); + if (_glfw.wl.cursorSurface) + wl_surface_destroy(_glfw.wl.cursorSurface); + if (_glfw.wl.compositor) + wl_compositor_destroy(_glfw.wl.compositor); + if (_glfw.wl.shm) + wl_shm_destroy(_glfw.wl.shm); + if (_glfw.wl.shell) + wl_shell_destroy(_glfw.wl.shell); + if (_glfw.wl.pointer) + wl_pointer_destroy(_glfw.wl.pointer); + if (_glfw.wl.keyboard) + wl_keyboard_destroy(_glfw.wl.keyboard); + if (_glfw.wl.seat) + wl_seat_destroy(_glfw.wl.seat); + if (_glfw.wl.relativePointerManager) + zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager); + if (_glfw.wl.pointerConstraints) + zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints); + if (_glfw.wl.registry) + wl_registry_destroy(_glfw.wl.registry); + if (_glfw.wl.display) + { + wl_display_flush(_glfw.wl.display); + wl_display_disconnect(_glfw.wl.display); + } +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " Wayland EGL" +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#else + " gettimeofday" +#endif + " evdev" +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; +} + diff --git a/src/external/glfw/src/wl_monitor.c b/src/external/glfw/src/wl_monitor.c new file mode 100644 index 00000000..10ef0e12 --- /dev/null +++ b/src/external/glfw/src/wl_monitor.c @@ -0,0 +1,201 @@ +//======================================================================== +// GLFW 3.3 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include +#include + + +static void geometry(void* data, + struct wl_output* output, + int32_t x, + int32_t y, + int32_t physicalWidth, + int32_t physicalHeight, + int32_t subpixel, + const char* make, + const char* model, + int32_t transform) +{ + struct _GLFWmonitor *monitor = data; + char name[1024]; + + monitor->wl.x = x; + monitor->wl.y = y; + monitor->widthMM = physicalWidth; + monitor->heightMM = physicalHeight; + + snprintf(name, sizeof(name), "%s %s", make, model); + monitor->name = strdup(name); +} + +static void mode(void* data, + struct wl_output* output, + uint32_t flags, + int32_t width, + int32_t height, + int32_t refresh) +{ + struct _GLFWmonitor *monitor = data; + GLFWvidmode mode; + + mode.width = width; + mode.height = height; + mode.redBits = 8; + mode.greenBits = 8; + mode.blueBits = 8; + mode.refreshRate = refresh / 1000; + + monitor->modeCount++; + monitor->modes = + realloc(monitor->modes, monitor->modeCount * sizeof(GLFWvidmode)); + monitor->modes[monitor->modeCount - 1] = mode; + + if (flags & WL_OUTPUT_MODE_CURRENT) + monitor->wl.currentMode = monitor->modeCount - 1; +} + +static void done(void* data, struct wl_output* output) +{ + struct _GLFWmonitor *monitor = data; + + _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); +} + +static void scale(void* data, + struct wl_output* output, + int32_t factor) +{ + struct _GLFWmonitor *monitor = data; + + monitor->wl.scale = factor; +} + +static const struct wl_output_listener outputListener = { + geometry, + mode, + done, + scale, +}; + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwAddOutputWayland(uint32_t name, uint32_t version) +{ + _GLFWmonitor *monitor; + struct wl_output *output; + + if (version < 2) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unsupported output interface version"); + return; + } + + // The actual name of this output will be set in the geometry handler. + monitor = _glfwAllocMonitor(NULL, 0, 0); + + output = wl_registry_bind(_glfw.wl.registry, + name, + &wl_output_interface, + 2); + if (!output) + { + _glfwFreeMonitor(monitor); + return; + } + + monitor->wl.scale = 1; + monitor->wl.output = output; + + wl_output_add_listener(output, &outputListener, monitor); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + if (xpos) + *xpos = monitor->wl.x; + if (ypos) + *ypos = monitor->wl.y; +} + +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = (float) monitor->wl.scale; + if (yscale) + *yscale = (float) monitor->wl.scale; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + *found = monitor->modeCount; + return monitor->modes; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + *mode = monitor->modes[monitor->wl.currentMode]; +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Gamma ramp getting not supported yet"); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Gamma ramp setting not supported yet"); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->wl.output; +} + diff --git a/src/external/glfw/src/wl_platform.h b/src/external/glfw/src/wl_platform.h new file mode 100644 index 00000000..059ea2ee --- /dev/null +++ b/src/external/glfw/src/wl_platform.h @@ -0,0 +1,223 @@ +//======================================================================== +// GLFW 3.3 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include +#include +#include +#include + +typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; + +typedef struct VkWaylandSurfaceCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display* display; + struct wl_surface* surface; +} VkWaylandSurfaceCreateInfoKHR; + +typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWaylandSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*); + +#include "posix_thread.h" +#include "posix_time.h" +#include "linux_joystick.h" +#include "xkb_unicode.h" +#include "egl_context.h" +#include "osmesa_context.h" + +#include "wayland-relative-pointer-unstable-v1-client-protocol.h" +#include "wayland-pointer-constraints-unstable-v1-client-protocol.h" + +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) + +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->wl.native) +#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.wl.display) + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWayland wl +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWayland wl + +#define _GLFW_PLATFORM_CONTEXT_STATE +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE + +typedef struct xkb_context* (* PFN_xkb_context_new)(enum xkb_context_flags); +typedef void (* PFN_xkb_context_unref)(struct xkb_context*); +typedef struct xkb_keymap* (* PFN_xkb_keymap_new_from_string)(struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags); +typedef void (* PFN_xkb_keymap_unref)(struct xkb_keymap*); +typedef xkb_mod_index_t (* PFN_xkb_keymap_mod_get_index)(struct xkb_keymap*, const char*); +typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*); +typedef void (* PFN_xkb_state_unref)(struct xkb_state*); +typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**); +typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t); +typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component); +typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags); +typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*); +typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags); +typedef void (* PFN_xkb_compose_state_unref)(struct xkb_compose_state*); +typedef enum xkb_compose_feed_result (* PFN_xkb_compose_state_feed)(struct xkb_compose_state*, xkb_keysym_t); +typedef enum xkb_compose_status (* PFN_xkb_compose_state_get_status)(struct xkb_compose_state*); +typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_state*); +#define xkb_context_new _glfw.wl.xkb.context_new +#define xkb_context_unref _glfw.wl.xkb.context_unref +#define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string +#define xkb_keymap_unref _glfw.wl.xkb.keymap_unref +#define xkb_keymap_mod_get_index _glfw.wl.xkb.keymap_mod_get_index +#define xkb_state_new _glfw.wl.xkb.state_new +#define xkb_state_unref _glfw.wl.xkb.state_unref +#define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms +#define xkb_state_update_mask _glfw.wl.xkb.state_update_mask +#define xkb_state_serialize_mods _glfw.wl.xkb.state_serialize_mods +#define xkb_compose_table_new_from_locale _glfw.wl.xkb.compose_table_new_from_locale +#define xkb_compose_table_unref _glfw.wl.xkb.compose_table_unref +#define xkb_compose_state_new _glfw.wl.xkb.compose_state_new +#define xkb_compose_state_unref _glfw.wl.xkb.compose_state_unref +#define xkb_compose_state_feed _glfw.wl.xkb.compose_state_feed +#define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status +#define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym + + +// Wayland-specific per-window data +// +typedef struct _GLFWwindowWayland +{ + int width, height; + GLFWbool visible; + GLFWbool maximized; + GLFWbool transparent; + struct wl_surface* surface; + struct wl_egl_window* native; + struct wl_shell_surface* shellSurface; + struct wl_callback* callback; + + _GLFWcursor* currentCursor; + double cursorPosX, cursorPosY; + + char* title; + + // We need to track the monitors the window spans on to calculate the + // optimal scaling factor. + int scale; + _GLFWmonitor** monitors; + int monitorsCount; + int monitorsSize; + + struct { + struct zwp_relative_pointer_v1* relativePointer; + struct zwp_locked_pointer_v1* lockedPointer; + } pointerLock; +} _GLFWwindowWayland; + +// Wayland-specific global data +// +typedef struct _GLFWlibraryWayland +{ + struct wl_display* display; + struct wl_registry* registry; + struct wl_compositor* compositor; + struct wl_shell* shell; + struct wl_shm* shm; + struct wl_seat* seat; + struct wl_pointer* pointer; + struct wl_keyboard* keyboard; + struct zwp_relative_pointer_manager_v1* relativePointerManager; + struct zwp_pointer_constraints_v1* pointerConstraints; + + int compositorVersion; + + struct wl_cursor_theme* cursorTheme; + struct wl_surface* cursorSurface; + uint32_t pointerSerial; + + short int keycodes[256]; + short int scancodes[GLFW_KEY_LAST + 1]; + + struct { + void* handle; + struct xkb_context* context; + struct xkb_keymap* keymap; + struct xkb_state* state; + struct xkb_compose_state* composeState; + xkb_mod_mask_t controlMask; + xkb_mod_mask_t altMask; + xkb_mod_mask_t shiftMask; + xkb_mod_mask_t superMask; + unsigned int modifiers; + + PFN_xkb_context_new context_new; + PFN_xkb_context_unref context_unref; + PFN_xkb_keymap_new_from_string keymap_new_from_string; + PFN_xkb_keymap_unref keymap_unref; + PFN_xkb_keymap_mod_get_index keymap_mod_get_index; + PFN_xkb_state_new state_new; + PFN_xkb_state_unref state_unref; + PFN_xkb_state_key_get_syms state_key_get_syms; + PFN_xkb_state_update_mask state_update_mask; + PFN_xkb_state_serialize_mods state_serialize_mods; + PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale; + PFN_xkb_compose_table_unref compose_table_unref; + PFN_xkb_compose_state_new compose_state_new; + PFN_xkb_compose_state_unref compose_state_unref; + PFN_xkb_compose_state_feed compose_state_feed; + PFN_xkb_compose_state_get_status compose_state_get_status; + PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym; + } xkb; + + _GLFWwindow* pointerFocus; + _GLFWwindow* keyboardFocus; + +} _GLFWlibraryWayland; + +// Wayland-specific per-monitor data +// +typedef struct _GLFWmonitorWayland +{ + struct wl_output* output; + int currentMode; + + int x; + int y; + int scale; + +} _GLFWmonitorWayland; + +// Wayland-specific per-cursor data +// +typedef struct _GLFWcursorWayland +{ + struct wl_cursor_image* image; + struct wl_buffer* buffer; + int width, height; + int xhot, yhot; +} _GLFWcursorWayland; + + +void _glfwAddOutputWayland(uint32_t name, uint32_t version); + diff --git a/src/external/glfw/src/wl_window.c b/src/external/glfw/src/wl_window.c new file mode 100644 index 00000000..f0f2637e --- /dev/null +++ b/src/external/glfw/src/wl_window.c @@ -0,0 +1,1106 @@ +//======================================================================== +// GLFW 3.3 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define _GNU_SOURCE + +#include "internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +static void handlePing(void* data, + struct wl_shell_surface* shellSurface, + uint32_t serial) +{ + wl_shell_surface_pong(shellSurface, serial); +} + +static void handleConfigure(void* data, + struct wl_shell_surface* shellSurface, + uint32_t edges, + int32_t width, + int32_t height) +{ + _GLFWwindow* window = data; + float aspectRatio; + float targetRatio; + + if (!window->monitor) + { + if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) + { + aspectRatio = (float)width / (float)height; + targetRatio = (float)window->numer / (float)window->denom; + if (aspectRatio < targetRatio) + height = width / targetRatio; + else if (aspectRatio > targetRatio) + width = height * targetRatio; + } + + if (window->minwidth != GLFW_DONT_CARE && width < window->minwidth) + width = window->minwidth; + else if (window->maxwidth != GLFW_DONT_CARE && width > window->maxwidth) + width = window->maxwidth; + + if (window->minheight != GLFW_DONT_CARE && height < window->minheight) + height = window->minheight; + else if (window->maxheight != GLFW_DONT_CARE && height > window->maxheight) + height = window->maxheight; + } + + _glfwInputWindowSize(window, width, height); + _glfwPlatformSetWindowSize(window, width, height); + _glfwInputWindowDamage(window); +} + +static void handlePopupDone(void* data, + struct wl_shell_surface* shellSurface) +{ +} + +static const struct wl_shell_surface_listener shellSurfaceListener = { + handlePing, + handleConfigure, + handlePopupDone +}; + +static void checkScaleChange(_GLFWwindow* window) +{ + int scaledWidth, scaledHeight; + int scale = 1; + int i; + int monitorScale; + + // Check if we will be able to set the buffer scale or not. + if (_glfw.wl.compositorVersion < 3) + return; + + // Get the scale factor from the highest scale monitor. + for (i = 0; i < window->wl.monitorsCount; ++i) + { + monitorScale = window->wl.monitors[i]->wl.scale; + if (scale < monitorScale) + scale = monitorScale; + } + + // Only change the framebuffer size if the scale changed. + if (scale != window->wl.scale) + { + window->wl.scale = scale; + scaledWidth = window->wl.width * scale; + scaledHeight = window->wl.height * scale; + wl_surface_set_buffer_scale(window->wl.surface, scale); + wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); + _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); + } +} + +static void handleEnter(void *data, + struct wl_surface *surface, + struct wl_output *output) +{ + _GLFWwindow* window = data; + _GLFWmonitor* monitor = wl_output_get_user_data(output); + + if (window->wl.monitorsCount + 1 > window->wl.monitorsSize) + { + ++window->wl.monitorsSize; + window->wl.monitors = + realloc(window->wl.monitors, + window->wl.monitorsSize * sizeof(_GLFWmonitor*)); + } + + window->wl.monitors[window->wl.monitorsCount++] = monitor; + + checkScaleChange(window); +} + +static void handleLeave(void *data, + struct wl_surface *surface, + struct wl_output *output) +{ + _GLFWwindow* window = data; + _GLFWmonitor* monitor = wl_output_get_user_data(output); + GLFWbool found; + int i; + + for (i = 0, found = GLFW_FALSE; i < window->wl.monitorsCount - 1; ++i) + { + if (monitor == window->wl.monitors[i]) + found = GLFW_TRUE; + if (found) + window->wl.monitors[i] = window->wl.monitors[i + 1]; + } + window->wl.monitors[--window->wl.monitorsCount] = NULL; + + checkScaleChange(window); +} + +static const struct wl_surface_listener surfaceListener = { + handleEnter, + handleLeave +}; + +// Makes the surface considered as XRGB instead of ARGB. +static void setOpaqueRegion(_GLFWwindow* window) +{ + struct wl_region* region; + + region = wl_compositor_create_region(_glfw.wl.compositor); + if (!region) + return; + + wl_region_add(region, 0, 0, window->wl.width, window->wl.height); + wl_surface_set_opaque_region(window->wl.surface, region); + wl_surface_commit(window->wl.surface); + wl_region_destroy(region); +} + +static GLFWbool createSurface(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig) +{ + window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor); + if (!window->wl.surface) + return GLFW_FALSE; + + wl_surface_add_listener(window->wl.surface, + &surfaceListener, + window); + + wl_surface_set_user_data(window->wl.surface, window); + + window->wl.native = wl_egl_window_create(window->wl.surface, + wndconfig->width, + wndconfig->height); + if (!window->wl.native) + return GLFW_FALSE; + + window->wl.width = wndconfig->width; + window->wl.height = wndconfig->height; + window->wl.scale = 1; + + if (!window->wl.transparent) + setOpaqueRegion(window); + + return GLFW_TRUE; +} + +static GLFWbool createShellSurface(_GLFWwindow* window) +{ + window->wl.shellSurface = wl_shell_get_shell_surface(_glfw.wl.shell, + window->wl.surface); + if (!window->wl.shellSurface) + return GLFW_FALSE; + + wl_shell_surface_add_listener(window->wl.shellSurface, + &shellSurfaceListener, + window); + + if (window->wl.title) + wl_shell_surface_set_title(window->wl.shellSurface, window->wl.title); + + if (window->monitor) + { + wl_shell_surface_set_fullscreen( + window->wl.shellSurface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + 0, + window->monitor->wl.output); + } + else if (window->wl.maximized) + { + wl_shell_surface_set_maximized(window->wl.shellSurface, NULL); + } + else + { + wl_shell_surface_set_toplevel(window->wl.shellSurface); + } + + wl_surface_commit(window->wl.surface); + + return GLFW_TRUE; +} + +static int +createTmpfileCloexec(char* tmpname) +{ + int fd; + + fd = mkostemp(tmpname, O_CLOEXEC); + if (fd >= 0) + unlink(tmpname); + + return fd; +} + +static void +handleEvents(int timeout) +{ + struct wl_display* display = _glfw.wl.display; + struct pollfd fds[] = { + { wl_display_get_fd(display), POLLIN }, + }; + + while (wl_display_prepare_read(display) != 0) + wl_display_dispatch_pending(display); + + // If an error different from EAGAIN happens, we have likely been + // disconnected from the Wayland session, try to handle that the best we + // can. + if (wl_display_flush(display) < 0 && errno != EAGAIN) + { + _GLFWwindow* window = _glfw.windowListHead; + while (window) + { + _glfwInputWindowCloseRequest(window); + window = window->next; + } + wl_display_cancel_read(display); + return; + } + + if (poll(fds, 1, timeout) > 0) + { + wl_display_read_events(display); + wl_display_dispatch_pending(display); + } + else + { + wl_display_cancel_read(display); + } +} + +/* + * Create a new, unique, anonymous file of the given size, and + * return the file descriptor for it. The file descriptor is set + * CLOEXEC. The file is immediately suitable for mmap()'ing + * the given size at offset zero. + * + * The file should not have a permanent backing store like a disk, + * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. + * + * The file name is deleted from the file system. + * + * The file is suitable for buffer sharing between processes by + * transmitting the file descriptor over Unix sockets using the + * SCM_RIGHTS methods. + * + * posix_fallocate() is used to guarantee that disk space is available + * for the file at the given size. If disk space is insufficent, errno + * is set to ENOSPC. If posix_fallocate() is not supported, program may + * receive SIGBUS on accessing mmap()'ed file contents instead. + */ +int +createAnonymousFile(off_t size) +{ + static const char template[] = "/glfw-shared-XXXXXX"; + const char* path; + char* name; + int fd; + int ret; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) + { + errno = ENOENT; + return -1; + } + + name = calloc(strlen(path) + sizeof(template), 1); + strcpy(name, path); + strcat(name, template); + + fd = createTmpfileCloexec(name); + + free(name); + + if (fd < 0) + return -1; + ret = posix_fallocate(fd, 0, size); + if (ret != 0) + { + close(fd); + errno = ret; + return -1; + } + return fd; +} + +// Translates a GLFW standard cursor to a theme cursor name +// +static char *translateCursorShape(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return "left_ptr"; + case GLFW_IBEAM_CURSOR: + return "xterm"; + case GLFW_CROSSHAIR_CURSOR: + return "crosshair"; + case GLFW_HAND_CURSOR: + return "grabbing"; + case GLFW_HRESIZE_CURSOR: + return "sb_h_double_arrow"; + case GLFW_VRESIZE_CURSOR: + return "sb_v_double_arrow"; + } + return NULL; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + window->wl.transparent = fbconfig->transparent; + + if (!createSurface(window, wndconfig)) + return GLFW_FALSE; + + if (ctxconfig->client != GLFW_NO_API) + { + if (ctxconfig->source == GLFW_EGL_CONTEXT_API || + ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwInitOSMesa()) + return GLFW_FALSE; + if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + } + + if (wndconfig->title) + window->wl.title = strdup(wndconfig->title); + + if (wndconfig->visible) + { + if (!createShellSurface(window)) + return GLFW_FALSE; + + window->wl.visible = GLFW_TRUE; + } + else + { + window->wl.shellSurface = NULL; + window->wl.visible = GLFW_FALSE; + } + + window->wl.currentCursor = NULL; + + window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*)); + window->wl.monitorsCount = 0; + window->wl.monitorsSize = 1; + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (window == _glfw.wl.pointerFocus) + { + _glfw.wl.pointerFocus = NULL; + _glfwInputCursorEnter(window, GLFW_FALSE); + } + if (window == _glfw.wl.keyboardFocus) + { + _glfw.wl.keyboardFocus = NULL; + _glfwInputWindowFocus(window, GLFW_FALSE); + } + + if (window->context.destroy) + window->context.destroy(window); + + if (window->wl.native) + wl_egl_window_destroy(window->wl.native); + + if (window->wl.shellSurface) + wl_shell_surface_destroy(window->wl.shellSurface); + + if (window->wl.surface) + wl_surface_destroy(window->wl.surface); + + free(window->wl.title); + free(window->wl.monitors); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ + if (window->wl.title) + free(window->wl.title); + window->wl.title = strdup(title); + if (window->wl.shellSurface) + wl_shell_surface_set_title(window->wl.shellSurface, title); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Setting window icon not supported"); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + // A Wayland client is not aware of its position, so just warn and leave it + // as (0, 0) + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window position retrieval not supported"); +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + // A Wayland client can not set its position, so just warn + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window position setting not supported"); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->wl.width; + if (height) + *height = window->wl.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + int scaledWidth = width * window->wl.scale; + int scaledHeight = height * window->wl.scale; + window->wl.width = width; + window->wl.height = height; + wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); + if (!window->wl.transparent) + setOpaqueRegion(window); + _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + // TODO: find out how to trigger a resize. + // The actual limits are checked in the wl_shell_surface::configure handler. +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +{ + // TODO: find out how to trigger a resize. + // The actual limits are checked in the wl_shell_surface::configure handler. +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + _glfwPlatformGetWindowSize(window, width, height); + *width *= window->wl.scale; + *height *= window->wl.scale; +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + // TODO: will need a proper implementation once decorations are + // implemented, but for now just leave everything as 0. +} + +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = (float) window->wl.scale; + if (yscale) + *yscale = (float) window->wl.scale; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + // TODO: move to xdg_shell instead of wl_shell. + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Iconify window not supported"); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + // TODO: also do the same for iconified. + if (window->monitor || window->wl.maximized) + { + if (window->wl.shellSurface) + wl_shell_surface_set_toplevel(window->wl.shellSurface); + + window->wl.maximized = GLFW_FALSE; + } +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + if (!window->monitor && !window->wl.maximized) + { + if (window->wl.shellSurface) + { + // Let the compositor select the best output. + wl_shell_surface_set_maximized(window->wl.shellSurface, NULL); + } + window->wl.maximized = GLFW_TRUE; + } +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + if (!window->monitor) + { + if (!window->wl.shellSurface) + createShellSurface(window); + window->wl.visible = GLFW_TRUE; + } +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + if (!window->monitor) + { + if (window->wl.shellSurface) + wl_shell_surface_destroy(window->wl.shellSurface); + window->wl.visible = GLFW_FALSE; + } +} + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window attention request not implemented yet"); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Focusing a window requires user interaction"); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (monitor) + { + wl_shell_surface_set_fullscreen( + window->wl.shellSurface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + refreshRate * 1000, // Convert Hz to mHz. + monitor->wl.output); + } + else + { + wl_shell_surface_set_toplevel(window->wl.shellSurface); + } + _glfwInputWindowMonitor(window, monitor); +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + return _glfw.wl.keyboardFocus == window; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + // TODO: move to xdg_shell, wl_shell doesn't have any iconified concept. + return GLFW_FALSE; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + return window->wl.visible; +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + return window->wl.maximized; +} + +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + return window->wl.transparent; +} + +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window attribute setting not implemented yet"); +} + +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window attribute setting not implemented yet"); +} + +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window attribute setting not implemented yet"); +} + +void _glfwPlatformPollEvents(void) +{ + handleEvents(0); +} + +void _glfwPlatformWaitEvents(void) +{ + handleEvents(-1); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + handleEvents((int) (timeout * 1e3)); +} + +void _glfwPlatformPostEmptyEvent(void) +{ + wl_display_sync(_glfw.wl.display); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + if (xpos) + *xpos = window->wl.cursorPosX; + if (ypos) + *ypos = window->wl.cursorPosY; +} + +static GLFWbool isPointerLocked(_GLFWwindow* window); + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +{ + if (isPointerLocked(window)) + { + zwp_locked_pointer_v1_set_cursor_position_hint( + window->wl.pointerLock.lockedPointer, + wl_fixed_from_double(x), wl_fixed_from_double(y)); + wl_surface_commit(window->wl.surface); + } +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + _glfwPlatformSetCursor(window, window->wl.currentCursor); +} + +const char* _glfwPlatformGetScancodeName(int scancode) +{ + // TODO + return NULL; +} + +int _glfwPlatformGetKeyScancode(int key) +{ + return _glfw.wl.scancodes[key]; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + struct wl_shm_pool* pool; + int stride = image->width * 4; + int length = image->width * image->height * 4; + void* data; + int fd, i; + + fd = createAnonymousFile(length); + if (fd < 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Creating a buffer file for %d B failed: %m", + length); + return GLFW_FALSE; + } + + data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Cursor mmap failed: %m"); + close(fd); + return GLFW_FALSE; + } + + pool = wl_shm_create_pool(_glfw.wl.shm, fd, length); + + close(fd); + unsigned char* source = (unsigned char*) image->pixels; + unsigned char* target = data; + for (i = 0; i < image->width * image->height; i++, source += 4) + { + unsigned int alpha = source[3]; + + *target++ = (unsigned char) ((source[2] * alpha) / 255); + *target++ = (unsigned char) ((source[1] * alpha) / 255); + *target++ = (unsigned char) ((source[0] * alpha) / 255); + *target++ = (unsigned char) alpha; + } + + cursor->wl.buffer = + wl_shm_pool_create_buffer(pool, 0, + image->width, + image->height, + stride, WL_SHM_FORMAT_ARGB8888); + munmap(data, length); + wl_shm_pool_destroy(pool); + + cursor->wl.width = image->width; + cursor->wl.height = image->height; + cursor->wl.xhot = xhot; + cursor->wl.yhot = yhot; + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + struct wl_cursor* standardCursor; + + standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, + translateCursorShape(shape)); + if (!standardCursor) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Standard cursor \"%s\" not found", + translateCursorShape(shape)); + return GLFW_FALSE; + } + + cursor->wl.image = standardCursor->images[0]; + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + // If it's a standard cursor we don't need to do anything here + if (cursor->wl.image) + return; + + if (cursor->wl.buffer) + wl_buffer_destroy(cursor->wl.buffer); +} + +static void handleRelativeMotion(void* data, + struct zwp_relative_pointer_v1* pointer, + uint32_t timeHi, + uint32_t timeLo, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t dxUnaccel, + wl_fixed_t dyUnaccel) +{ + _GLFWwindow* window = data; + + if (window->cursorMode != GLFW_CURSOR_DISABLED) + return; + + _glfwInputCursorPos(window, + window->virtualCursorPosX + wl_fixed_to_double(dxUnaccel), + window->virtualCursorPosY + wl_fixed_to_double(dyUnaccel)); +} + +static const struct zwp_relative_pointer_v1_listener relativePointerListener = { + handleRelativeMotion +}; + +static void handleLocked(void* data, + struct zwp_locked_pointer_v1* lockedPointer) +{ +} + +static void unlockPointer(_GLFWwindow* window) +{ + struct zwp_relative_pointer_v1* relativePointer = + window->wl.pointerLock.relativePointer; + struct zwp_locked_pointer_v1* lockedPointer = + window->wl.pointerLock.lockedPointer; + + zwp_relative_pointer_v1_destroy(relativePointer); + zwp_locked_pointer_v1_destroy(lockedPointer); + + window->wl.pointerLock.relativePointer = NULL; + window->wl.pointerLock.lockedPointer = NULL; +} + +static void lockPointer(_GLFWwindow* window); + +static void handleUnlocked(void* data, + struct zwp_locked_pointer_v1* lockedPointer) +{ +} + +static const struct zwp_locked_pointer_v1_listener lockedPointerListener = { + handleLocked, + handleUnlocked +}; + +static void lockPointer(_GLFWwindow* window) +{ + struct zwp_relative_pointer_v1* relativePointer; + struct zwp_locked_pointer_v1* lockedPointer; + + if (!_glfw.wl.relativePointerManager) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: no relative pointer manager"); + return; + } + + relativePointer = + zwp_relative_pointer_manager_v1_get_relative_pointer( + _glfw.wl.relativePointerManager, + _glfw.wl.pointer); + zwp_relative_pointer_v1_add_listener(relativePointer, + &relativePointerListener, + window); + + lockedPointer = + zwp_pointer_constraints_v1_lock_pointer( + _glfw.wl.pointerConstraints, + window->wl.surface, + _glfw.wl.pointer, + NULL, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + zwp_locked_pointer_v1_add_listener(lockedPointer, + &lockedPointerListener, + window); + + window->wl.pointerLock.relativePointer = relativePointer; + window->wl.pointerLock.lockedPointer = lockedPointer; + + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + NULL, 0, 0); +} + +static GLFWbool isPointerLocked(_GLFWwindow* window) +{ + return window->wl.pointerLock.lockedPointer != NULL; +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + struct wl_buffer* buffer; + struct wl_cursor* defaultCursor; + struct wl_cursor_image* image; + struct wl_surface* surface = _glfw.wl.cursorSurface; + + if (!_glfw.wl.pointer) + return; + + window->wl.currentCursor = cursor; + + // If we're not in the correct window just save the cursor + // the next time the pointer enters the window the cursor will change + if (window != _glfw.wl.pointerFocus) + return; + + // Unlock possible pointer lock if no longer disabled. + if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window)) + unlockPointer(window); + + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + if (cursor) + image = cursor->wl.image; + else + { + defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, + "left_ptr"); + if (!defaultCursor) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Standard cursor not found"); + return; + } + image = defaultCursor->images[0]; + } + + if (image) + { + buffer = wl_cursor_image_get_buffer(image); + if (!buffer) + return; + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + surface, + image->hotspot_x, + image->hotspot_y); + wl_surface_attach(surface, buffer, 0, 0); + wl_surface_damage(surface, 0, 0, + image->width, image->height); + wl_surface_commit(surface); + } + else + { + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + surface, + cursor->wl.xhot, + cursor->wl.yhot); + wl_surface_attach(surface, cursor->wl.buffer, 0, 0); + wl_surface_damage(surface, 0, 0, + cursor->wl.width, cursor->wl.height); + wl_surface_commit(surface); + } + } + else if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (!isPointerLocked(window)) + lockPointer(window); + } + else if (window->cursorMode == GLFW_CURSOR_HIDDEN) + { + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + NULL, 0, 0); + } +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Clipboard setting not implemented yet"); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Clipboard getting not implemented yet"); + return NULL; +} + +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) +{ + if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_wayland_surface) + return; + + extensions[0] = "VK_KHR_surface"; + extensions[1] = "VK_KHR_wayland_surface"; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR + vkGetPhysicalDeviceWaylandPresentationSupportKHR = + (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); + if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension"); + return VK_NULL_HANDLE; + } + + return vkGetPhysicalDeviceWaylandPresentationSupportKHR(device, + queuefamily, + _glfw.wl.display); +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + VkResult err; + VkWaylandSurfaceCreateInfoKHR sci; + PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; + + vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR"); + if (!vkCreateWaylandSurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + sci.display = _glfw.wl.display; + sci.surface = window->wl.surface; + + err = vkCreateWaylandSurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create Vulkan surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI struct wl_display* glfwGetWaylandDisplay(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfw.wl.display; +} + +GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->wl.surface; +} + diff --git a/src/external/glfw/src/x11_init.c b/src/external/glfw/src/x11_init.c new file mode 100644 index 00000000..b603a15f --- /dev/null +++ b/src/external/glfw/src/x11_init.c @@ -0,0 +1,1045 @@ +//======================================================================== +// GLFW 3.3 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + +#include +#include +#include +#include +#include + + +// Translate an X11 key code to a GLFW key code. +// +static int translateKeyCode(int scancode) +{ + int keySym; + + // Valid key code range is [8,255], according to the Xlib manual + if (scancode < 8 || scancode > 255) + return GLFW_KEY_UNKNOWN; + + if (_glfw.x11.xkb.available) + { + // Try secondary keysym, for numeric keypad keys + // Note: This way we always force "NumLock = ON", which is intentional + // since the returned key code should correspond to a physical + // location. + keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 1); + switch (keySym) + { + case XK_KP_0: return GLFW_KEY_KP_0; + case XK_KP_1: return GLFW_KEY_KP_1; + case XK_KP_2: return GLFW_KEY_KP_2; + case XK_KP_3: return GLFW_KEY_KP_3; + case XK_KP_4: return GLFW_KEY_KP_4; + case XK_KP_5: return GLFW_KEY_KP_5; + case XK_KP_6: return GLFW_KEY_KP_6; + case XK_KP_7: return GLFW_KEY_KP_7; + case XK_KP_8: return GLFW_KEY_KP_8; + case XK_KP_9: return GLFW_KEY_KP_9; + case XK_KP_Separator: + case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + default: break; + } + + // Now try primary keysym for function keys (non-printable keys) + // These should not depend on the current keyboard layout + keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); + } + else + { + int dummy; + KeySym* keySyms; + + keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy); + keySym = keySyms[0]; + XFree(keySyms); + } + + switch (keySym) + { + case XK_Escape: return GLFW_KEY_ESCAPE; + case XK_Tab: return GLFW_KEY_TAB; + case XK_Shift_L: return GLFW_KEY_LEFT_SHIFT; + case XK_Shift_R: return GLFW_KEY_RIGHT_SHIFT; + case XK_Control_L: return GLFW_KEY_LEFT_CONTROL; + case XK_Control_R: return GLFW_KEY_RIGHT_CONTROL; + case XK_Meta_L: + case XK_Alt_L: return GLFW_KEY_LEFT_ALT; + case XK_Mode_switch: // Mapped to Alt_R on many keyboards + case XK_ISO_Level3_Shift: // AltGr on at least some machines + case XK_Meta_R: + case XK_Alt_R: return GLFW_KEY_RIGHT_ALT; + case XK_Super_L: return GLFW_KEY_LEFT_SUPER; + case XK_Super_R: return GLFW_KEY_RIGHT_SUPER; + case XK_Menu: return GLFW_KEY_MENU; + case XK_Num_Lock: return GLFW_KEY_NUM_LOCK; + case XK_Caps_Lock: return GLFW_KEY_CAPS_LOCK; + case XK_Print: return GLFW_KEY_PRINT_SCREEN; + case XK_Scroll_Lock: return GLFW_KEY_SCROLL_LOCK; + case XK_Pause: return GLFW_KEY_PAUSE; + case XK_Delete: return GLFW_KEY_DELETE; + case XK_BackSpace: return GLFW_KEY_BACKSPACE; + case XK_Return: return GLFW_KEY_ENTER; + case XK_Home: return GLFW_KEY_HOME; + case XK_End: return GLFW_KEY_END; + case XK_Page_Up: return GLFW_KEY_PAGE_UP; + case XK_Page_Down: return GLFW_KEY_PAGE_DOWN; + case XK_Insert: return GLFW_KEY_INSERT; + case XK_Left: return GLFW_KEY_LEFT; + case XK_Right: return GLFW_KEY_RIGHT; + case XK_Down: return GLFW_KEY_DOWN; + case XK_Up: return GLFW_KEY_UP; + case XK_F1: return GLFW_KEY_F1; + case XK_F2: return GLFW_KEY_F2; + case XK_F3: return GLFW_KEY_F3; + case XK_F4: return GLFW_KEY_F4; + case XK_F5: return GLFW_KEY_F5; + case XK_F6: return GLFW_KEY_F6; + case XK_F7: return GLFW_KEY_F7; + case XK_F8: return GLFW_KEY_F8; + case XK_F9: return GLFW_KEY_F9; + case XK_F10: return GLFW_KEY_F10; + case XK_F11: return GLFW_KEY_F11; + case XK_F12: return GLFW_KEY_F12; + case XK_F13: return GLFW_KEY_F13; + case XK_F14: return GLFW_KEY_F14; + case XK_F15: return GLFW_KEY_F15; + case XK_F16: return GLFW_KEY_F16; + case XK_F17: return GLFW_KEY_F17; + case XK_F18: return GLFW_KEY_F18; + case XK_F19: return GLFW_KEY_F19; + case XK_F20: return GLFW_KEY_F20; + case XK_F21: return GLFW_KEY_F21; + case XK_F22: return GLFW_KEY_F22; + case XK_F23: return GLFW_KEY_F23; + case XK_F24: return GLFW_KEY_F24; + case XK_F25: return GLFW_KEY_F25; + + // Numeric keypad + case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; + case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; + case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; + case XK_KP_Add: return GLFW_KEY_KP_ADD; + + // These should have been detected in secondary keysym test above! + case XK_KP_Insert: return GLFW_KEY_KP_0; + case XK_KP_End: return GLFW_KEY_KP_1; + case XK_KP_Down: return GLFW_KEY_KP_2; + case XK_KP_Page_Down: return GLFW_KEY_KP_3; + case XK_KP_Left: return GLFW_KEY_KP_4; + case XK_KP_Right: return GLFW_KEY_KP_6; + case XK_KP_Home: return GLFW_KEY_KP_7; + case XK_KP_Up: return GLFW_KEY_KP_8; + case XK_KP_Page_Up: return GLFW_KEY_KP_9; + case XK_KP_Delete: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + + // Last resort: Check for printable keys (should not happen if the XKB + // extension is available). This will give a layout dependent mapping + // (which is wrong, and we may miss some keys, especially on non-US + // keyboards), but it's better than nothing... + case XK_a: return GLFW_KEY_A; + case XK_b: return GLFW_KEY_B; + case XK_c: return GLFW_KEY_C; + case XK_d: return GLFW_KEY_D; + case XK_e: return GLFW_KEY_E; + case XK_f: return GLFW_KEY_F; + case XK_g: return GLFW_KEY_G; + case XK_h: return GLFW_KEY_H; + case XK_i: return GLFW_KEY_I; + case XK_j: return GLFW_KEY_J; + case XK_k: return GLFW_KEY_K; + case XK_l: return GLFW_KEY_L; + case XK_m: return GLFW_KEY_M; + case XK_n: return GLFW_KEY_N; + case XK_o: return GLFW_KEY_O; + case XK_p: return GLFW_KEY_P; + case XK_q: return GLFW_KEY_Q; + case XK_r: return GLFW_KEY_R; + case XK_s: return GLFW_KEY_S; + case XK_t: return GLFW_KEY_T; + case XK_u: return GLFW_KEY_U; + case XK_v: return GLFW_KEY_V; + case XK_w: return GLFW_KEY_W; + case XK_x: return GLFW_KEY_X; + case XK_y: return GLFW_KEY_Y; + case XK_z: return GLFW_KEY_Z; + case XK_1: return GLFW_KEY_1; + case XK_2: return GLFW_KEY_2; + case XK_3: return GLFW_KEY_3; + case XK_4: return GLFW_KEY_4; + case XK_5: return GLFW_KEY_5; + case XK_6: return GLFW_KEY_6; + case XK_7: return GLFW_KEY_7; + case XK_8: return GLFW_KEY_8; + case XK_9: return GLFW_KEY_9; + case XK_0: return GLFW_KEY_0; + case XK_space: return GLFW_KEY_SPACE; + case XK_minus: return GLFW_KEY_MINUS; + case XK_equal: return GLFW_KEY_EQUAL; + case XK_bracketleft: return GLFW_KEY_LEFT_BRACKET; + case XK_bracketright: return GLFW_KEY_RIGHT_BRACKET; + case XK_backslash: return GLFW_KEY_BACKSLASH; + case XK_semicolon: return GLFW_KEY_SEMICOLON; + case XK_apostrophe: return GLFW_KEY_APOSTROPHE; + case XK_grave: return GLFW_KEY_GRAVE_ACCENT; + case XK_comma: return GLFW_KEY_COMMA; + case XK_period: return GLFW_KEY_PERIOD; + case XK_slash: return GLFW_KEY_SLASH; + case XK_less: return GLFW_KEY_WORLD_1; // At least in some layouts... + default: break; + } + + // No matching translation was found + return GLFW_KEY_UNKNOWN; +} + +// Create key code translation tables +// +static void createKeyTables(void) +{ + int scancode, key; + + memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes)); + memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes)); + + if (_glfw.x11.xkb.available) + { + // Use XKB to determine physical key locations independently of the + // current keyboard layout + + char name[XkbKeyNameLength + 1]; + XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd); + XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc); + + // Find the X11 key code -> GLFW key code mapping + for (scancode = desc->min_key_code; scancode <= desc->max_key_code; scancode++) + { + memcpy(name, desc->names->keys[scancode].name, XkbKeyNameLength); + name[XkbKeyNameLength] = '\0'; + + // Map the key name to a GLFW key code. Note: We only map printable + // keys here, and we use the US keyboard layout. The rest of the + // keys (function keys) are mapped using traditional KeySym + // translations. + if (strcmp(name, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT; + else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1; + else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2; + else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3; + else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4; + else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5; + else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6; + else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7; + else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8; + else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9; + else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0; + else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS; + else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL; + else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q; + else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W; + else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E; + else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R; + else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T; + else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y; + else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U; + else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I; + else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O; + else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P; + else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET; + else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET; + else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A; + else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S; + else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D; + else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F; + else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G; + else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H; + else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J; + else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K; + else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L; + else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON; + else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE; + else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z; + else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X; + else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C; + else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V; + else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B; + else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N; + else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M; + else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA; + else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD; + else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH; + else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH; + else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1; + else key = GLFW_KEY_UNKNOWN; + + if ((scancode >= 0) && (scancode < 256)) + _glfw.x11.keycodes[scancode] = key; + } + + XkbFreeNames(desc, XkbKeyNamesMask, True); + XkbFreeKeyboard(desc, 0, True); + } + + for (scancode = 0; scancode < 256; scancode++) + { + // Translate the un-translated key codes using traditional X11 KeySym + // lookups + if (_glfw.x11.keycodes[scancode] < 0) + _glfw.x11.keycodes[scancode] = translateKeyCode(scancode); + + // Store the reverse translation for faster key name lookup + if (_glfw.x11.keycodes[scancode] > 0) + _glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode; + } +} + +// Check whether the IM has a usable style +// +static GLFWbool hasUsableInputMethodStyle(void) +{ + unsigned int i; + GLFWbool found = GLFW_FALSE; + XIMStyles* styles = NULL; + + if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL) + return GLFW_FALSE; + + for (i = 0; i < styles->count_styles; i++) + { + if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) + { + found = GLFW_TRUE; + break; + } + } + + XFree(styles); + return found; +} + +// Check whether the specified atom is supported +// +static Atom getSupportedAtom(Atom* supportedAtoms, + unsigned long atomCount, + const char* atomName) +{ + unsigned long i; + const Atom atom = XInternAtom(_glfw.x11.display, atomName, False); + + for (i = 0; i < atomCount; i++) + { + if (supportedAtoms[i] == atom) + return atom; + } + + return None; +} + +// Check whether the running window manager is EWMH-compliant +// +static void detectEWMH(void) +{ + Window* windowFromRoot = NULL; + Window* windowFromChild = NULL; + + // First we need a couple of atoms + const Atom supportingWmCheck = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False); + const Atom wmSupported = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False); + + // Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window + if (!_glfwGetWindowPropertyX11(_glfw.x11.root, + supportingWmCheck, + XA_WINDOW, + (unsigned char**) &windowFromRoot)) + { + return; + } + + _glfwGrabErrorHandlerX11(); + + // It should be the ID of a child window (of the root) + // Then we look for the same property on the child window + if (!_glfwGetWindowPropertyX11(*windowFromRoot, + supportingWmCheck, + XA_WINDOW, + (unsigned char**) &windowFromChild)) + { + XFree(windowFromRoot); + return; + } + + _glfwReleaseErrorHandlerX11(); + + // It should be the ID of that same child window + if (*windowFromRoot != *windowFromChild) + { + XFree(windowFromRoot); + XFree(windowFromChild); + return; + } + + XFree(windowFromRoot); + XFree(windowFromChild); + + // We are now fairly sure that an EWMH-compliant window manager is running + + Atom* supportedAtoms; + unsigned long atomCount; + + // Now we need to check the _NET_SUPPORTED property of the root window + // It should be a list of supported WM protocol and state atoms + atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root, + wmSupported, + XA_ATOM, + (unsigned char**) &supportedAtoms); + + // See which of the atoms we support that are supported by the WM + _glfw.x11.NET_WM_STATE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE"); + _glfw.x11.NET_WM_STATE_ABOVE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); + _glfw.x11.NET_WM_STATE_FULLSCREEN = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); + _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); + _glfw.x11.NET_WM_FULLSCREEN_MONITORS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); + _glfw.x11.NET_WM_WINDOW_TYPE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); + _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); + _glfw.x11.NET_ACTIVE_WINDOW = + getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); + _glfw.x11.NET_FRAME_EXTENTS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); + _glfw.x11.NET_REQUEST_FRAME_EXTENTS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); + + if (supportedAtoms) + XFree(supportedAtoms); +} + +// Look for and initialize supported X11 extensions +// +static GLFWbool initExtensions(void) +{ + _glfw.x11.vidmode.handle = dlopen("libXxf86vm.so.1", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.vidmode.handle) + { + _glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension) + dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension"); + _glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp) + dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp"); + _glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp) + dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp"); + _glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize) + dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize"); + + _glfw.x11.vidmode.available = + XF86VidModeQueryExtension(_glfw.x11.display, + &_glfw.x11.vidmode.eventBase, + &_glfw.x11.vidmode.errorBase); + } + + _glfw.x11.xi.handle = dlopen("libXi.so.6", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.xi.handle) + { + _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion) + dlsym(_glfw.x11.xi.handle, "XIQueryVersion"); + _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents) + dlsym(_glfw.x11.xi.handle, "XISelectEvents"); + + if (XQueryExtension(_glfw.x11.display, + "XInputExtension", + &_glfw.x11.xi.majorOpcode, + &_glfw.x11.xi.eventBase, + &_glfw.x11.xi.errorBase)) + { + _glfw.x11.xi.major = 2; + _glfw.x11.xi.minor = 0; + + if (XIQueryVersion(_glfw.x11.display, + &_glfw.x11.xi.major, + &_glfw.x11.xi.minor) == Success) + { + _glfw.x11.xi.available = GLFW_TRUE; + } + } + } + + _glfw.x11.randr.handle = dlopen("libXrandr.so.2", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.randr.handle) + { + _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma) + dlsym(_glfw.x11.randr.handle, "XRRAllocGamma"); + _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) + dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo) + dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); + _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) + dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo) + dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); + _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources) + dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources"); + _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma) + dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); + _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize) + dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); + _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo) + dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); + _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo) + dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo"); + _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary) + dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); + _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent) + dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); + _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension) + dlsym(_glfw.x11.randr.handle, "XRRQueryExtension"); + _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion) + dlsym(_glfw.x11.randr.handle, "XRRQueryVersion"); + _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput) + dlsym(_glfw.x11.randr.handle, "XRRSelectInput"); + _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig) + dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); + _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma) + dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); + _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration) + dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); + + if (XRRQueryExtension(_glfw.x11.display, + &_glfw.x11.randr.eventBase, + &_glfw.x11.randr.errorBase)) + { + if (XRRQueryVersion(_glfw.x11.display, + &_glfw.x11.randr.major, + &_glfw.x11.randr.minor)) + { + // The GLFW RandR path requires at least version 1.3 + if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3) + _glfw.x11.randr.available = GLFW_TRUE; + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to query RandR version"); + } + } + } + + if (_glfw.x11.randr.available) + { + XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, + _glfw.x11.root); + + if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0])) + { + // This is likely an older Nvidia driver with broken gamma support + // Flag it as useless and fall back to xf86vm gamma, if available + _glfw.x11.randr.gammaBroken = GLFW_TRUE; + } + + if (!sr->ncrtc) + { + // A system without CRTCs is likely a system with broken RandR + // Disable the RandR monitor path and fall back to core functions + _glfw.x11.randr.monitorBroken = GLFW_TRUE; + } + + XRRFreeScreenResources(sr); + } + + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRSelectInput(_glfw.x11.display, _glfw.x11.root, + RROutputChangeNotifyMask); + } + + _glfw.x11.xcursor.handle = dlopen("libXcursor.so.1", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.xcursor.handle) + { + _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate) + dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate"); + _glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy) + dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); + _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor) + dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); + } + + _glfw.x11.xinerama.handle = dlopen("libXinerama.so.1", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.xinerama.handle) + { + _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive) + dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive"); + _glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension) + dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension"); + _glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens) + dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens"); + + if (XineramaQueryExtension(_glfw.x11.display, + &_glfw.x11.xinerama.major, + &_glfw.x11.xinerama.minor)) + { + if (XineramaIsActive(_glfw.x11.display)) + _glfw.x11.xinerama.available = GLFW_TRUE; + } + } + + _glfw.x11.xkb.major = 1; + _glfw.x11.xkb.minor = 0; + _glfw.x11.xkb.available = + XkbQueryExtension(_glfw.x11.display, + &_glfw.x11.xkb.majorOpcode, + &_glfw.x11.xkb.eventBase, + &_glfw.x11.xkb.errorBase, + &_glfw.x11.xkb.major, + &_glfw.x11.xkb.minor); + + if (_glfw.x11.xkb.available) + { + Bool supported; + + if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) + { + if (supported) + _glfw.x11.xkb.detectable = GLFW_TRUE; + } + } + + _glfw.x11.x11xcb.handle = dlopen("libX11-xcb.so.1", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.x11xcb.handle) + { + _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection) + dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); + } + + _glfw.x11.xrender.handle = dlopen("libXrender.so.1", RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.x11.xrender.handle) + { + _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension) + dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension"); + _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion) + dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion"); + _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat) + dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat"); + + if (XRenderQueryExtension(_glfw.x11.display, + &_glfw.x11.xrender.errorBase, + &_glfw.x11.xrender.eventBase)) + { + if (XRenderQueryVersion(_glfw.x11.display, + &_glfw.x11.xrender.major, + &_glfw.x11.xrender.minor)) + { + _glfw.x11.xrender.available = GLFW_TRUE; + } + } + } + + // Update the key code LUT + // FIXME: We should listen to XkbMapNotify events to track changes to + // the keyboard mapping. + createKeyTables(); + + // Detect whether an EWMH-conformant window manager is running + detectEWMH(); + + // String format atoms + _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False); + _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False); + _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False); + + // Custom selection property atom + _glfw.x11.GLFW_SELECTION = + XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False); + + // ICCCM standard clipboard atoms + _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False); + _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False); + _glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False); + _glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False); + _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False); + + // Clipboard manager atoms + _glfw.x11.CLIPBOARD_MANAGER = + XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False); + _glfw.x11.SAVE_TARGETS = + XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); + + // Xdnd (drag and drop) atoms + _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False); + _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False); + _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False); + _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False); + _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False); + _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False); + _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False); + _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False); + _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False); + _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False); + + // ICCCM, EWMH and Motif window property atoms + // These can be set safely even without WM support + // The EWMH atoms that require WM support are handled in detectEWMH + _glfw.x11.WM_PROTOCOLS = + XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False); + _glfw.x11.WM_STATE = + XInternAtom(_glfw.x11.display, "WM_STATE", False); + _glfw.x11.WM_DELETE_WINDOW = + XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False); + _glfw.x11.NET_WM_ICON = + XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False); + _glfw.x11.NET_WM_PING = + XInternAtom(_glfw.x11.display, "_NET_WM_PING", False); + _glfw.x11.NET_WM_PID = + XInternAtom(_glfw.x11.display, "_NET_WM_PID", False); + _glfw.x11.NET_WM_NAME = + XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False); + _glfw.x11.NET_WM_ICON_NAME = + XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False); + _glfw.x11.NET_WM_BYPASS_COMPOSITOR = + XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False); + _glfw.x11.MOTIF_WM_HINTS = + XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); + + return GLFW_TRUE; +} + +// Retrieve system content scale via folklore heuristics +// +static void getSystemContentScale(float* xscale, float* yscale) +{ + // NOTE: Default to the display-wide DPI as we don't currently have a policy + // for which monitor a window is considered to be on + float xdpi = DisplayWidth(_glfw.x11.display, _glfw.x11.screen) * + 25.4f / DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); + float ydpi = DisplayHeight(_glfw.x11.display, _glfw.x11.screen) * + 25.4f / DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); + + // NOTE: Basing the scale on Xft.dpi where available should provide the most + // consistent user experience (matches Qt, Gtk, etc), although not + // always the most accurate one + char* rms = XResourceManagerString(_glfw.x11.display); + if (rms) + { + XrmDatabase db = XrmGetStringDatabase(rms); + if (db) + { + XrmValue value; + char* type = NULL; + + if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) + { + if (type && strcmp(type, "String") == 0) + xdpi = ydpi = atof(value.addr); + } + + XrmDestroyDatabase(db); + } + } + + *xscale = xdpi / 96.f; + *yscale = ydpi / 96.f; +} + +// Create a blank cursor for hidden and disabled cursor modes +// +static Cursor createHiddenCursor(void) +{ + unsigned char pixels[16 * 16 * 4] = { 0 }; + GLFWimage image = { 16, 16, pixels }; + return _glfwCreateCursorX11(&image, 0, 0); +} + +// Create a helper window for IPC +// +static Window createHelperWindow(void) +{ + XSetWindowAttributes wa; + wa.event_mask = PropertyChangeMask; + + return XCreateWindow(_glfw.x11.display, _glfw.x11.root, + 0, 0, 1, 1, 0, 0, + InputOnly, + DefaultVisual(_glfw.x11.display, _glfw.x11.screen), + CWEventMask, &wa); +} + +// X error handler +// +static int errorHandler(Display *display, XErrorEvent* event) +{ + _glfw.x11.errorCode = event->error_code; + return 0; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Sets the X error handler callback +// +void _glfwGrabErrorHandlerX11(void) +{ + _glfw.x11.errorCode = Success; + XSetErrorHandler(errorHandler); +} + +// Clears the X error handler callback +// +void _glfwReleaseErrorHandlerX11(void) +{ + // Synchronize to make sure all commands are processed + XSync(_glfw.x11.display, False); + XSetErrorHandler(NULL); +} + +// Reports the specified error, appending information about the last X error +// +void _glfwInputErrorX11(int error, const char* message) +{ + char buffer[_GLFW_MESSAGE_SIZE]; + XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode, + buffer, sizeof(buffer)); + + _glfwInputError(error, "%s: %s", message, buffer); +} + +// Creates a native cursor object from the specified image and hotspot +// +Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) +{ + int i; + Cursor cursor; + + if (!_glfw.x11.xcursor.handle) + return None; + + XcursorImage* native = XcursorImageCreate(image->width, image->height); + if (native == NULL) + return None; + + native->xhot = xhot; + native->yhot = yhot; + + unsigned char* source = (unsigned char*) image->pixels; + XcursorPixel* target = native->pixels; + + for (i = 0; i < image->width * image->height; i++, target++, source += 4) + { + unsigned int alpha = source[3]; + + *target = (alpha << 24) | + ((unsigned char) ((source[0] * alpha) / 255) << 16) | + ((unsigned char) ((source[1] * alpha) / 255) << 8) | + ((unsigned char) ((source[2] * alpha) / 255) << 0); + } + + cursor = XcursorImageLoadCursor(_glfw.x11.display, native); + XcursorImageDestroy(native); + + return cursor; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ +#if !defined(X_HAVE_UTF8_STRING) + // HACK: If the current locale is "C" and the Xlib UTF-8 functions are + // unavailable, apply the environment's locale in the hope that it's + // both available and not "C" + // This is done because the "C" locale breaks wide character input, + // which is what we fall back on when UTF-8 support is missing + if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0) + setlocale(LC_CTYPE, ""); +#endif + + XInitThreads(); + XrmInitialize(); + + _glfw.x11.display = XOpenDisplay(NULL); + if (!_glfw.x11.display) + { + const char* display = getenv("DISPLAY"); + if (display) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to open display %s", display); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: The DISPLAY environment variable is missing"); + } + + return GLFW_FALSE; + } + + _glfw.x11.screen = DefaultScreen(_glfw.x11.display); + _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); + _glfw.x11.context = XUniqueContext(); + + getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY); + + if (!initExtensions()) + return GLFW_FALSE; + + _glfw.x11.helperWindowHandle = createHelperWindow(); + _glfw.x11.hiddenCursorHandle = createHiddenCursor(); + + if (XSupportsLocale()) + { + XSetLocaleModifiers(""); + + _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL); + if (_glfw.x11.im) + { + if (!hasUsableInputMethodStyle()) + { + XCloseIM(_glfw.x11.im); + _glfw.x11.im = NULL; + } + } + } + +#if defined(__linux__) + if (!_glfwInitJoysticksLinux()) + return GLFW_FALSE; +#endif + + _glfwInitTimerPOSIX(); + + _glfwPollMonitorsX11(); + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + if (_glfw.x11.helperWindowHandle) + { + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) == + _glfw.x11.helperWindowHandle) + { + _glfwPushSelectionToManagerX11(); + } + + XDestroyWindow(_glfw.x11.display, _glfw.x11.helperWindowHandle); + _glfw.x11.helperWindowHandle = None; + } + + if (_glfw.x11.hiddenCursorHandle) + { + XFreeCursor(_glfw.x11.display, _glfw.x11.hiddenCursorHandle); + _glfw.x11.hiddenCursorHandle = (Cursor) 0; + } + + free(_glfw.x11.primarySelectionString); + free(_glfw.x11.clipboardString); + + if (_glfw.x11.im) + { + XCloseIM(_glfw.x11.im); + _glfw.x11.im = NULL; + } + + _glfwTerminateEGL(); + + if (_glfw.x11.display) + { + XCloseDisplay(_glfw.x11.display); + _glfw.x11.display = NULL; + } + + if (_glfw.x11.x11xcb.handle) + { + dlclose(_glfw.x11.x11xcb.handle); + _glfw.x11.x11xcb.handle = NULL; + } + + if (_glfw.x11.xcursor.handle) + { + dlclose(_glfw.x11.xcursor.handle); + _glfw.x11.xcursor.handle = NULL; + } + + if (_glfw.x11.randr.handle) + { + dlclose(_glfw.x11.randr.handle); + _glfw.x11.randr.handle = NULL; + } + + if (_glfw.x11.xinerama.handle) + { + dlclose(_glfw.x11.xinerama.handle); + _glfw.x11.xinerama.handle = NULL; + } + + // NOTE: This needs to be done after XCloseDisplay, as libGL registers + // cleanup callbacks that get called by it + _glfwTerminateGLX(); + +#if defined(__linux__) + _glfwTerminateJoysticksLinux(); +#endif +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER " X11 GLX EGL" +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#else + " gettimeofday" +#endif +#if defined(__linux__) + " evdev" +#endif +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; +} + diff --git a/src/external/glfw/src/x11_monitor.c b/src/external/glfw/src/x11_monitor.c new file mode 100644 index 00000000..d68c5888 --- /dev/null +++ b/src/external/glfw/src/x11_monitor.c @@ -0,0 +1,510 @@ +//======================================================================== +// GLFW 3.3 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include +#include + + +// Check whether the display mode should be included in enumeration +// +static GLFWbool modeIsGood(const XRRModeInfo* mi) +{ + return (mi->modeFlags & RR_Interlace) == 0; +} + +// Calculates the refresh rate, in Hz, from the specified RandR mode info +// +static int calculateRefreshRate(const XRRModeInfo* mi) +{ + if (mi->hTotal && mi->vTotal) + return (int) ((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal)); + else + return 0; +} + +// Returns the mode info for a RandR mode XID +// +static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) +{ + int i; + + for (i = 0; i < sr->nmode; i++) + { + if (sr->modes[i].id == id) + return sr->modes + i; + } + + return NULL; +} + +// Convert RandR mode info to GLFW video mode +// +static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi, + const XRRCrtcInfo* ci) +{ + GLFWvidmode mode; + + if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) + { + mode.width = mi->height; + mode.height = mi->width; + } + else + { + mode.width = mi->width; + mode.height = mi->height; + } + + mode.refreshRate = calculateRefreshRate(mi); + + _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), + &mode.redBits, &mode.greenBits, &mode.blueBits); + + return mode; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Poll for changes in the set of connected monitors +// +void _glfwPollMonitorsX11(void) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + int i, j, disconnectedCount, screenCount = 0; + _GLFWmonitor** disconnected = NULL; + XineramaScreenInfo* screens = NULL; + XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, + _glfw.x11.root); + RROutput primary = XRRGetOutputPrimary(_glfw.x11.display, + _glfw.x11.root); + + if (_glfw.x11.xinerama.available) + screens = XineramaQueryScreens(_glfw.x11.display, &screenCount); + + disconnectedCount = _glfw.monitorCount; + if (disconnectedCount) + { + disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); + memcpy(disconnected, + _glfw.monitors, + _glfw.monitorCount * sizeof(_GLFWmonitor*)); + } + + for (i = 0; i < sr->noutput; i++) + { + int type, widthMM, heightMM; + XRROutputInfo* oi; + XRRCrtcInfo* ci; + _GLFWmonitor* monitor; + + oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]); + if (oi->connection != RR_Connected || oi->crtc == None) + { + XRRFreeOutputInfo(oi); + continue; + } + + for (j = 0; j < disconnectedCount; j++) + { + if (disconnected[j] && + disconnected[j]->x11.output == sr->outputs[i]) + { + disconnected[j] = NULL; + break; + } + } + + if (j < disconnectedCount) + { + XRRFreeOutputInfo(oi); + continue; + } + + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc); + if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) + { + widthMM = oi->mm_height; + heightMM = oi->mm_width; + } + else + { + widthMM = oi->mm_width; + heightMM = oi->mm_height; + } + + monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM); + monitor->x11.output = sr->outputs[i]; + monitor->x11.crtc = oi->crtc; + + for (j = 0; j < screenCount; j++) + { + if (screens[j].x_org == ci->x && + screens[j].y_org == ci->y && + screens[j].width == ci->width && + screens[j].height == ci->height) + { + monitor->x11.index = j; + break; + } + } + + if (monitor->x11.output == primary) + type = _GLFW_INSERT_FIRST; + else + type = _GLFW_INSERT_LAST; + + _glfwInputMonitor(monitor, GLFW_CONNECTED, type); + + XRRFreeOutputInfo(oi); + XRRFreeCrtcInfo(ci); + } + + XRRFreeScreenResources(sr); + + if (screens) + XFree(screens); + + for (i = 0; i < disconnectedCount; i++) + { + if (disconnected[i]) + _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); + } + + free(disconnected); + } + + if (!_glfw.monitorCount) + { + const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); + const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); + + _glfwInputMonitor(_glfwAllocMonitor("Display", widthMM, heightMM), + GLFW_CONNECTED, + _GLFW_INSERT_FIRST); + } +} + +// Set the current video mode for the specified monitor +// +GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr; + XRRCrtcInfo* ci; + XRROutputInfo* oi; + GLFWvidmode current; + const GLFWvidmode* best; + RRMode native = None; + int i; + + best = _glfwChooseVideoMode(monitor, desired); + _glfwPlatformGetVideoMode(monitor, ¤t); + if (_glfwCompareVideoModes(¤t, best) == 0) + return GLFW_TRUE; + + sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); + + for (i = 0; i < oi->nmode; i++) + { + const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); + if (!modeIsGood(mi)) + continue; + + const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); + if (_glfwCompareVideoModes(best, &mode) == 0) + { + native = mi->id; + break; + } + } + + if (native) + { + if (monitor->x11.oldMode == None) + monitor->x11.oldMode = ci->mode; + + XRRSetCrtcConfig(_glfw.x11.display, + sr, monitor->x11.crtc, + CurrentTime, + ci->x, ci->y, + native, + ci->rotation, + ci->outputs, + ci->noutput); + } + + XRRFreeOutputInfo(oi); + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + + if (!native) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Monitor mode list changed"); + return GLFW_FALSE; + } + } + + return GLFW_TRUE; +} + +// Restore the saved (original) video mode for the specified monitor +// +void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr; + XRRCrtcInfo* ci; + + if (monitor->x11.oldMode == None) + return; + + sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + + XRRSetCrtcConfig(_glfw.x11.display, + sr, monitor->x11.crtc, + CurrentTime, + ci->x, ci->y, + monitor->x11.oldMode, + ci->rotation, + ci->outputs, + ci->noutput); + + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + + monitor->x11.oldMode = None; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr; + XRRCrtcInfo* ci; + + sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + + if (xpos) + *xpos = ci->x; + if (ypos) + *ypos = ci->y; + + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + } +} + +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = _glfw.x11.contentScaleX; + if (yscale) + *yscale = _glfw.x11.contentScaleY; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) +{ + GLFWvidmode* result; + + *count = 0; + + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + int i, j; + XRRScreenResources* sr; + XRRCrtcInfo* ci; + XRROutputInfo* oi; + + sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); + + result = calloc(oi->nmode, sizeof(GLFWvidmode)); + + for (i = 0; i < oi->nmode; i++) + { + const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); + if (!modeIsGood(mi)) + continue; + + const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); + + for (j = 0; j < *count; j++) + { + if (_glfwCompareVideoModes(result + j, &mode) == 0) + break; + } + + // Skip duplicate modes + if (j < *count) + continue; + + (*count)++; + result[*count - 1] = mode; + } + + XRRFreeOutputInfo(oi); + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + } + else + { + *count = 1; + result = calloc(1, sizeof(GLFWvidmode)); + _glfwPlatformGetVideoMode(monitor, result); + } + + return result; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr; + XRRCrtcInfo* ci; + + sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + + *mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci); + + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + } + else + { + mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); + mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); + mode->refreshRate = 0; + + _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), + &mode->redBits, &mode->greenBits, &mode->blueBits); + } +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) + { + const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display, + monitor->x11.crtc); + XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display, + monitor->x11.crtc); + + _glfwAllocGammaArrays(ramp, size); + + memcpy(ramp->red, gamma->red, size * sizeof(unsigned short)); + memcpy(ramp->green, gamma->green, size * sizeof(unsigned short)); + memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); + + XRRFreeGamma(gamma); + } + else if (_glfw.x11.vidmode.available) + { + int size; + XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size); + + _glfwAllocGammaArrays(ramp, size); + + XF86VidModeGetGammaRamp(_glfw.x11.display, + _glfw.x11.screen, + ramp->size, ramp->red, ramp->green, ramp->blue); + } +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) + { + if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != ramp->size) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Gamma ramp size must match current ramp size"); + return; + } + + XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size); + + memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); + memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short)); + memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short)); + + XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma); + XRRFreeGamma(gamma); + } + else if (_glfw.x11.vidmode.available) + { + XF86VidModeSetGammaRamp(_glfw.x11.display, + _glfw.x11.screen, + ramp->size, + (unsigned short*) ramp->red, + (unsigned short*) ramp->green, + (unsigned short*) ramp->blue); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + return monitor->x11.crtc; +} + +GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + return monitor->x11.output; +} + diff --git a/src/external/glfw/src/x11_platform.h b/src/external/glfw/src/x11_platform.h new file mode 100644 index 00000000..7eba441d --- /dev/null +++ b/src/external/glfw/src/x11_platform.h @@ -0,0 +1,442 @@ +//======================================================================== +// GLFW 3.3 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include +#include +#include +#include + +#include +#include +#include +#include + +// The XRandR extension provides mode setting and gamma control +#include + +// The Xkb extension provides improved keyboard support +#include + +// The Xinerama extension provides legacy monitor indices +#include + +// The XInput extension provides raw mouse motion input +#include + +typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int); +typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*); +typedef void (* PFN_XRRFreeGamma)(XRRCrtcGamma*); +typedef void (* PFN_XRRFreeOutputInfo)(XRROutputInfo*); +typedef void (* PFN_XRRFreeScreenResources)(XRRScreenResources*); +typedef XRRCrtcGamma* (* PFN_XRRGetCrtcGamma)(Display*,RRCrtc); +typedef int (* PFN_XRRGetCrtcGammaSize)(Display*,RRCrtc); +typedef XRRCrtcInfo* (* PFN_XRRGetCrtcInfo) (Display*,XRRScreenResources*,RRCrtc); +typedef XRROutputInfo* (* PFN_XRRGetOutputInfo)(Display*,XRRScreenResources*,RROutput); +typedef RROutput (* PFN_XRRGetOutputPrimary)(Display*,Window); +typedef XRRScreenResources* (* PFN_XRRGetScreenResourcesCurrent)(Display*,Window); +typedef Bool (* PFN_XRRQueryExtension)(Display*,int*,int*); +typedef Status (* PFN_XRRQueryVersion)(Display*,int*,int*); +typedef void (* PFN_XRRSelectInput)(Display*,Window,int); +typedef Status (* PFN_XRRSetCrtcConfig)(Display*,XRRScreenResources*,RRCrtc,Time,int,int,RRMode,Rotation,RROutput*,int); +typedef void (* PFN_XRRSetCrtcGamma)(Display*,RRCrtc,XRRCrtcGamma*); +typedef int (* PFN_XRRUpdateConfiguration)(XEvent*); +#define XRRAllocGamma _glfw.x11.randr.AllocGamma +#define XRRFreeCrtcInfo _glfw.x11.randr.FreeCrtcInfo +#define XRRFreeGamma _glfw.x11.randr.FreeGamma +#define XRRFreeOutputInfo _glfw.x11.randr.FreeOutputInfo +#define XRRFreeScreenResources _glfw.x11.randr.FreeScreenResources +#define XRRGetCrtcGamma _glfw.x11.randr.GetCrtcGamma +#define XRRGetCrtcGammaSize _glfw.x11.randr.GetCrtcGammaSize +#define XRRGetCrtcInfo _glfw.x11.randr.GetCrtcInfo +#define XRRGetOutputInfo _glfw.x11.randr.GetOutputInfo +#define XRRGetOutputPrimary _glfw.x11.randr.GetOutputPrimary +#define XRRGetScreenResourcesCurrent _glfw.x11.randr.GetScreenResourcesCurrent +#define XRRQueryExtension _glfw.x11.randr.QueryExtension +#define XRRQueryVersion _glfw.x11.randr.QueryVersion +#define XRRSelectInput _glfw.x11.randr.SelectInput +#define XRRSetCrtcConfig _glfw.x11.randr.SetCrtcConfig +#define XRRSetCrtcGamma _glfw.x11.randr.SetCrtcGamma +#define XRRUpdateConfiguration _glfw.x11.randr.UpdateConfiguration + +typedef XcursorImage* (* PFN_XcursorImageCreate)(int,int); +typedef void (* PFN_XcursorImageDestroy)(XcursorImage*); +typedef Cursor (* PFN_XcursorImageLoadCursor)(Display*,const XcursorImage*); +#define XcursorImageCreate _glfw.x11.xcursor.ImageCreate +#define XcursorImageDestroy _glfw.x11.xcursor.ImageDestroy +#define XcursorImageLoadCursor _glfw.x11.xcursor.ImageLoadCursor + +typedef Bool (* PFN_XineramaIsActive)(Display*); +typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*); +typedef XineramaScreenInfo* (* PFN_XineramaQueryScreens)(Display*,int*); +#define XineramaIsActive _glfw.x11.xinerama.IsActive +#define XineramaQueryExtension _glfw.x11.xinerama.QueryExtension +#define XineramaQueryScreens _glfw.x11.xinerama.QueryScreens + +typedef XID xcb_window_t; +typedef XID xcb_visualid_t; +typedef struct xcb_connection_t xcb_connection_t; +typedef xcb_connection_t* (* PFN_XGetXCBConnection)(Display*); +#define XGetXCBConnection _glfw.x11.x11xcb.GetXCBConnection + +typedef Bool (* PFN_XF86VidModeQueryExtension)(Display*,int*,int*); +typedef Bool (* PFN_XF86VidModeGetGammaRamp)(Display*,int,int,unsigned short*,unsigned short*,unsigned short*); +typedef Bool (* PFN_XF86VidModeSetGammaRamp)(Display*,int,int,unsigned short*,unsigned short*,unsigned short*); +typedef Bool (* PFN_XF86VidModeGetGammaRampSize)(Display*,int,int*); +#define XF86VidModeQueryExtension _glfw.x11.vidmode.QueryExtension +#define XF86VidModeGetGammaRamp _glfw.x11.vidmode.GetGammaRamp +#define XF86VidModeSetGammaRamp _glfw.x11.vidmode.SetGammaRamp +#define XF86VidModeGetGammaRampSize _glfw.x11.vidmode.GetGammaRampSize + +typedef Status (* PFN_XIQueryVersion)(Display*,int*,int*); +typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); +#define XIQueryVersion _glfw.x11.xi.QueryVersion +#define XISelectEvents _glfw.x11.xi.SelectEvents + +typedef Bool (* PFN_XRenderQueryExtension)(Display*,int*,int*); +typedef Status (* PFN_XRenderQueryVersion)(Display*dpy,int*,int*); +typedef XRenderPictFormat* (* PFN_XRenderFindVisualFormat)(Display*,Visual const*); +#define XRenderQueryExtension _glfw.x11.xrender.QueryExtension +#define XRenderQueryVersion _glfw.x11.xrender.QueryVersion +#define XRenderFindVisualFormat _glfw.x11.xrender.FindVisualFormat + +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; + +typedef struct VkXlibSurfaceCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + +typedef struct VkXcbSurfaceCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + +typedef VkResult (APIENTRY *PFN_vkCreateXlibSurfaceKHR)(VkInstance,const VkXlibSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice,uint32_t,Display*,VisualID); +typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t); + +#include "posix_thread.h" +#include "posix_time.h" +#include "xkb_unicode.h" +#include "glx_context.h" +#include "egl_context.h" +#include "osmesa_context.h" +#if defined(__linux__) +#include "linux_joystick.h" +#else +#include "null_joystick.h" +#endif + +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) + +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle) +#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display) + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11 +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11 +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11 + + +// X11-specific per-window data +// +typedef struct _GLFWwindowX11 +{ + Colormap colormap; + Window handle; + XIC ic; + + GLFWbool overrideRedirect; + GLFWbool iconified; + GLFWbool maximized; + + // Whether the visual supports framebuffer transparency + GLFWbool transparent; + + // Cached position and size used to filter out duplicate events + int width, height; + int xpos, ypos; + + // The last received cursor position, regardless of source + int lastCursorPosX, lastCursorPosY; + // The last position the cursor was warped to by GLFW + int warpCursorPosX, warpCursorPosY; + + // The time of the last KeyPress event + Time lastKeyTime; + +} _GLFWwindowX11; + +// X11-specific global data +// +typedef struct _GLFWlibraryX11 +{ + Display* display; + int screen; + Window root; + + // System content scale + float contentScaleX, contentScaleY; + // Helper window for IPC + Window helperWindowHandle; + // Invisible cursor for hidden cursor mode + Cursor hiddenCursorHandle; + // Context for mapping window XIDs to _GLFWwindow pointers + XContext context; + // XIM input method + XIM im; + // Most recent error code received by X error handler + int errorCode; + // Primary selection string (while the primary selection is owned) + char* primarySelectionString; + // Clipboard string (while the selection is owned) + char* clipboardString; + // Key name string + char keyName[5]; + // X11 keycode to GLFW key LUT + short int keycodes[256]; + // GLFW key to X11 keycode LUT + short int scancodes[GLFW_KEY_LAST + 1]; + // Where to place the cursor when re-enabled + double restoreCursorPosX, restoreCursorPosY; + // The window whose disabled cursor mode is active + _GLFWwindow* disabledCursorWindow; + + // Window manager atoms + Atom WM_PROTOCOLS; + Atom WM_STATE; + Atom WM_DELETE_WINDOW; + Atom NET_WM_NAME; + Atom NET_WM_ICON_NAME; + Atom NET_WM_ICON; + Atom NET_WM_PID; + Atom NET_WM_PING; + Atom NET_WM_WINDOW_TYPE; + Atom NET_WM_WINDOW_TYPE_NORMAL; + Atom NET_WM_STATE; + Atom NET_WM_STATE_ABOVE; + Atom NET_WM_STATE_FULLSCREEN; + Atom NET_WM_STATE_MAXIMIZED_VERT; + Atom NET_WM_STATE_MAXIMIZED_HORZ; + Atom NET_WM_STATE_DEMANDS_ATTENTION; + Atom NET_WM_BYPASS_COMPOSITOR; + Atom NET_WM_FULLSCREEN_MONITORS; + Atom NET_ACTIVE_WINDOW; + Atom NET_FRAME_EXTENTS; + Atom NET_REQUEST_FRAME_EXTENTS; + Atom MOTIF_WM_HINTS; + + // Xdnd (drag and drop) atoms + Atom XdndAware; + Atom XdndEnter; + Atom XdndPosition; + Atom XdndStatus; + Atom XdndActionCopy; + Atom XdndDrop; + Atom XdndFinished; + Atom XdndSelection; + Atom XdndTypeList; + Atom text_uri_list; + + // Selection (clipboard) atoms + Atom TARGETS; + Atom MULTIPLE; + Atom INCR; + Atom CLIPBOARD; + Atom PRIMARY; + Atom CLIPBOARD_MANAGER; + Atom SAVE_TARGETS; + Atom NULL_; + Atom UTF8_STRING; + Atom COMPOUND_STRING; + Atom ATOM_PAIR; + Atom GLFW_SELECTION; + + struct { + GLFWbool available; + void* handle; + int eventBase; + int errorBase; + int major; + int minor; + GLFWbool gammaBroken; + GLFWbool monitorBroken; + PFN_XRRAllocGamma AllocGamma; + PFN_XRRFreeCrtcInfo FreeCrtcInfo; + PFN_XRRFreeGamma FreeGamma; + PFN_XRRFreeOutputInfo FreeOutputInfo; + PFN_XRRFreeScreenResources FreeScreenResources; + PFN_XRRGetCrtcGamma GetCrtcGamma; + PFN_XRRGetCrtcGammaSize GetCrtcGammaSize; + PFN_XRRGetCrtcInfo GetCrtcInfo; + PFN_XRRGetOutputInfo GetOutputInfo; + PFN_XRRGetOutputPrimary GetOutputPrimary; + PFN_XRRGetScreenResourcesCurrent GetScreenResourcesCurrent; + PFN_XRRQueryExtension QueryExtension; + PFN_XRRQueryVersion QueryVersion; + PFN_XRRSelectInput SelectInput; + PFN_XRRSetCrtcConfig SetCrtcConfig; + PFN_XRRSetCrtcGamma SetCrtcGamma; + PFN_XRRUpdateConfiguration UpdateConfiguration; + } randr; + + struct { + GLFWbool available; + GLFWbool detectable; + int majorOpcode; + int eventBase; + int errorBase; + int major; + int minor; + } xkb; + + struct { + int count; + int timeout; + int interval; + int blanking; + int exposure; + } saver; + + struct { + int version; + Window source; + Atom format; + } xdnd; + + struct { + void* handle; + PFN_XcursorImageCreate ImageCreate; + PFN_XcursorImageDestroy ImageDestroy; + PFN_XcursorImageLoadCursor ImageLoadCursor; + } xcursor; + + struct { + GLFWbool available; + void* handle; + int major; + int minor; + PFN_XineramaIsActive IsActive; + PFN_XineramaQueryExtension QueryExtension; + PFN_XineramaQueryScreens QueryScreens; + } xinerama; + + struct { + void* handle; + PFN_XGetXCBConnection GetXCBConnection; + } x11xcb; + + struct { + GLFWbool available; + void* handle; + int eventBase; + int errorBase; + PFN_XF86VidModeQueryExtension QueryExtension; + PFN_XF86VidModeGetGammaRamp GetGammaRamp; + PFN_XF86VidModeSetGammaRamp SetGammaRamp; + PFN_XF86VidModeGetGammaRampSize GetGammaRampSize; + } vidmode; + + struct { + GLFWbool available; + void* handle; + int majorOpcode; + int eventBase; + int errorBase; + int major; + int minor; + PFN_XIQueryVersion QueryVersion; + PFN_XISelectEvents SelectEvents; + } xi; + + struct { + GLFWbool available; + void* handle; + int major; + int minor; + int eventBase; + int errorBase; + PFN_XRenderQueryExtension QueryExtension; + PFN_XRenderQueryVersion QueryVersion; + PFN_XRenderFindVisualFormat FindVisualFormat; + } xrender; + +} _GLFWlibraryX11; + +// X11-specific per-monitor data +// +typedef struct _GLFWmonitorX11 +{ + RROutput output; + RRCrtc crtc; + RRMode oldMode; + + // Index of corresponding Xinerama screen, + // for EWMH full screen window placement + int index; + +} _GLFWmonitorX11; + +// X11-specific per-cursor data +// +typedef struct _GLFWcursorX11 +{ + Cursor handle; + +} _GLFWcursorX11; + + +void _glfwPollMonitorsX11(void); +GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired); +void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor); + +Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot); + +unsigned long _glfwGetWindowPropertyX11(Window window, + Atom property, + Atom type, + unsigned char** value); +GLFWbool _glfwIsVisualTransparentX11(Visual* visual); + +void _glfwGrabErrorHandlerX11(void); +void _glfwReleaseErrorHandlerX11(void); +void _glfwInputErrorX11(int error, const char* message); + +void _glfwPushSelectionToManagerX11(void); + diff --git a/src/external/glfw/src/x11_window.c b/src/external/glfw/src/x11_window.c new file mode 100644 index 00000000..c89d2ec5 --- /dev/null +++ b/src/external/glfw/src/x11_window.c @@ -0,0 +1,2991 @@ +//======================================================================== +// GLFW 3.3 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +// Action for EWMH client messages +#define _NET_WM_STATE_REMOVE 0 +#define _NET_WM_STATE_ADD 1 +#define _NET_WM_STATE_TOGGLE 2 + +// Additional mouse button names for XButtonEvent +#define Button6 6 +#define Button7 7 + +#define _GLFW_XDND_VERSION 5 + + +// Wait for data to arrive using select +// This avoids blocking other threads via the per-display Xlib lock that also +// covers GLX functions +// +static GLFWbool waitForEvent(double* timeout) +{ + fd_set fds; + const int fd = ConnectionNumber(_glfw.x11.display); + int count = fd + 1; + +#if defined(__linux__) + if (_glfw.linjs.inotify > fd) + count = _glfw.linjs.inotify + 1; +#endif + for (;;) + { + FD_ZERO(&fds); + FD_SET(fd, &fds); +#if defined(__linux__) + if (_glfw.linjs.inotify > 0) + FD_SET(_glfw.linjs.inotify, &fds); +#endif + + if (timeout) + { + const long seconds = (long) *timeout; + const long microseconds = (long) ((*timeout - seconds) * 1e6); + struct timeval tv = { seconds, microseconds }; + const uint64_t base = _glfwPlatformGetTimerValue(); + + const int result = select(count, &fds, NULL, NULL, &tv); + const int error = errno; + + *timeout -= (_glfwPlatformGetTimerValue() - base) / + (double) _glfwPlatformGetTimerFrequency(); + + if (result > 0) + return GLFW_TRUE; + if ((result == -1 && error == EINTR) || *timeout <= 0.0) + return GLFW_FALSE; + } + else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR) + return GLFW_TRUE; + } +} + +// Waits until a VisibilityNotify event arrives for the specified window or the +// timeout period elapses (ICCCM section 4.2.2) +// +static GLFWbool waitForVisibilityNotify(_GLFWwindow* window) +{ + XEvent dummy; + double timeout = 0.1; + + while (!XCheckTypedWindowEvent(_glfw.x11.display, + window->x11.handle, + VisibilityNotify, + &dummy)) + { + if (!waitForEvent(&timeout)) + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Returns whether the window is iconified +// +static int getWindowState(_GLFWwindow* window) +{ + int result = WithdrawnState; + struct { + CARD32 state; + Window icon; + } *state = NULL; + + if (_glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.WM_STATE, + _glfw.x11.WM_STATE, + (unsigned char**) &state) >= 2) + { + result = state->state; + } + + if (state) + XFree(state); + + return result; +} + +// Returns whether the event is a selection event +// +static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer) +{ + if (event->xany.window != _glfw.x11.helperWindowHandle) + return False; + + return event->type == SelectionRequest || + event->type == SelectionNotify || + event->type == SelectionClear; +} + +// Returns whether it is a _NET_FRAME_EXTENTS event for the specified window +// +static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer) +{ + _GLFWwindow* window = (_GLFWwindow*) pointer; + return event->type == PropertyNotify && + event->xproperty.state == PropertyNewValue && + event->xproperty.window == window->x11.handle && + event->xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS; +} + +// Returns whether it is a property event for the specified selection transfer +// +static Bool isSelPropNewValueNotify(Display* display, XEvent* event, XPointer pointer) +{ + XEvent* notification = (XEvent*) pointer; + return event->type == PropertyNotify && + event->xproperty.state == PropertyNewValue && + event->xproperty.window == notification->xselection.requestor && + event->xproperty.atom == notification->xselection.property; +} + +// Translates a GLFW standard cursor to a font cursor shape +// +static int translateCursorShape(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return XC_left_ptr; + case GLFW_IBEAM_CURSOR: + return XC_xterm; + case GLFW_CROSSHAIR_CURSOR: + return XC_crosshair; + case GLFW_HAND_CURSOR: + return XC_hand1; + case GLFW_HRESIZE_CURSOR: + return XC_sb_h_double_arrow; + case GLFW_VRESIZE_CURSOR: + return XC_sb_v_double_arrow; + } + + return 0; +} + +// Translates an X event modifier state mask +// +static int translateState(int state) +{ + int mods = 0; + + if (state & ShiftMask) + mods |= GLFW_MOD_SHIFT; + if (state & ControlMask) + mods |= GLFW_MOD_CONTROL; + if (state & Mod1Mask) + mods |= GLFW_MOD_ALT; + if (state & Mod4Mask) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Translates an X11 key code to a GLFW key token +// +static int translateKey(int scancode) +{ + // Use the pre-filled LUT (see createKeyTables() in x11_init.c) + if (scancode < 0 || scancode > 255) + return GLFW_KEY_UNKNOWN; + + return _glfw.x11.keycodes[scancode]; +} + +// Return the GLFW window corresponding to the specified X11 window +// +static _GLFWwindow* findWindowByHandle(Window handle) +{ + _GLFWwindow* window; + + if (XFindContext(_glfw.x11.display, + handle, + _glfw.x11.context, + (XPointer*) &window) != 0) + { + return NULL; + } + + return window; +} + +// Sends an EWMH or ICCCM event to the window manager +// +static void sendEventToWM(_GLFWwindow* window, Atom type, + long a, long b, long c, long d, long e) +{ + XEvent event; + memset(&event, 0, sizeof(event)); + + event.type = ClientMessage; + event.xclient.window = window->x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = type; + event.xclient.data.l[0] = a; + event.xclient.data.l[1] = b; + event.xclient.data.l[2] = c; + event.xclient.data.l[3] = d; + event.xclient.data.l[4] = e; + + XSendEvent(_glfw.x11.display, _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); +} + +// Updates the normal hints according to the window settings +// +static void updateNormalHints(_GLFWwindow* window, int width, int height) +{ + XSizeHints* hints = XAllocSizeHints(); + + if (!window->monitor) + { + if (window->resizable) + { + if (window->minwidth != GLFW_DONT_CARE && + window->minheight != GLFW_DONT_CARE) + { + hints->flags |= PMinSize; + hints->min_width = window->minwidth; + hints->min_height = window->minheight; + } + + if (window->maxwidth != GLFW_DONT_CARE && + window->maxheight != GLFW_DONT_CARE) + { + hints->flags |= PMaxSize; + hints->max_width = window->maxwidth; + hints->max_height = window->maxheight; + } + + if (window->numer != GLFW_DONT_CARE && + window->denom != GLFW_DONT_CARE) + { + hints->flags |= PAspect; + hints->min_aspect.x = hints->max_aspect.x = window->numer; + hints->min_aspect.y = hints->max_aspect.y = window->denom; + } + } + else + { + hints->flags |= (PMinSize | PMaxSize); + hints->min_width = hints->max_width = width; + hints->min_height = hints->max_height = height; + } + } + + hints->flags |= PWinGravity; + hints->win_gravity = StaticGravity; + + XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); + XFree(hints); +} + +// Updates the full screen status of the window +// +static void updateWindowMode(_GLFWwindow* window) +{ + if (window->monitor) + { + if (_glfw.x11.xinerama.available && + _glfw.x11.NET_WM_FULLSCREEN_MONITORS) + { + sendEventToWM(window, + _glfw.x11.NET_WM_FULLSCREEN_MONITORS, + window->monitor->x11.index, + window->monitor->x11.index, + window->monitor->x11.index, + window->monitor->x11.index, + 0); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + _glfw.x11.NET_WM_STATE_FULLSCREEN, + 0, 1, 0); + } + else + { + // This is the butcher's way of removing window decorations + // Setting the override-redirect attribute on a window makes the + // window manager ignore the window completely (ICCCM, section 4) + // The good thing is that this makes undecorated full screen windows + // easy to do; the bad thing is that we have to do everything + // manually and some things (like iconify/restore) won't work at + // all, as those are tasks usually performed by the window manager + + XSetWindowAttributes attributes; + attributes.override_redirect = True; + XChangeWindowAttributes(_glfw.x11.display, + window->x11.handle, + CWOverrideRedirect, + &attributes); + + window->x11.overrideRedirect = GLFW_TRUE; + } + + // Enable compositor bypass + if (!window->x11.transparent) + { + const unsigned long value = 1; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*) &value, 1); + } + } + else + { + if (_glfw.x11.xinerama.available && + _glfw.x11.NET_WM_FULLSCREEN_MONITORS) + { + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_FULLSCREEN_MONITORS); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_REMOVE, + _glfw.x11.NET_WM_STATE_FULLSCREEN, + 0, 1, 0); + } + else + { + XSetWindowAttributes attributes; + attributes.override_redirect = False; + XChangeWindowAttributes(_glfw.x11.display, + window->x11.handle, + CWOverrideRedirect, + &attributes); + + window->x11.overrideRedirect = GLFW_FALSE; + } + + // Disable compositor bypass + if (!window->x11.transparent) + { + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR); + } + } +} + +// Splits and translates a text/uri-list into separate file paths +// NOTE: This function destroys the provided string +// +static char** parseUriList(char* text, int* count) +{ + const char* prefix = "file://"; + char** paths = NULL; + char* line; + + *count = 0; + + while ((line = strtok(text, "\r\n"))) + { + text = NULL; + + if (line[0] == '#') + continue; + + if (strncmp(line, prefix, strlen(prefix)) == 0) + { + line += strlen(prefix); + // TODO: Validate hostname + while (*line != '/') + line++; + } + + (*count)++; + + char* path = calloc(strlen(line) + 1, 1); + paths = realloc(paths, *count * sizeof(char*)); + paths[*count - 1] = path; + + while (*line) + { + if (line[0] == '%' && line[1] && line[2]) + { + const char digits[3] = { line[1], line[2], '\0' }; + *path = strtol(digits, NULL, 16); + line += 2; + } + else + *path = *line; + + path++; + line++; + } + } + + return paths; +} + +// Encode a Unicode code point to a UTF-8 stream +// Based on cutef8 by Jeff Bezanson (Public Domain) +// +static size_t encodeUTF8(char* s, unsigned int ch) +{ + size_t count = 0; + + if (ch < 0x80) + s[count++] = (char) ch; + else if (ch < 0x800) + { + s[count++] = (ch >> 6) | 0xc0; + s[count++] = (ch & 0x3f) | 0x80; + } + else if (ch < 0x10000) + { + s[count++] = (ch >> 12) | 0xe0; + s[count++] = ((ch >> 6) & 0x3f) | 0x80; + s[count++] = (ch & 0x3f) | 0x80; + } + else if (ch < 0x110000) + { + s[count++] = (ch >> 18) | 0xf0; + s[count++] = ((ch >> 12) & 0x3f) | 0x80; + s[count++] = ((ch >> 6) & 0x3f) | 0x80; + s[count++] = (ch & 0x3f) | 0x80; + } + + return count; +} + +// Decode a Unicode code point from a UTF-8 stream +// Based on cutef8 by Jeff Bezanson (Public Domain) +// +#if defined(X_HAVE_UTF8_STRING) +static unsigned int decodeUTF8(const char** s) +{ + unsigned int ch = 0, count = 0; + static const unsigned int offsets[] = + { + 0x00000000u, 0x00003080u, 0x000e2080u, + 0x03c82080u, 0xfa082080u, 0x82082080u + }; + + do + { + ch = (ch << 6) + (unsigned char) **s; + (*s)++; + count++; + } while ((**s & 0xc0) == 0x80); + + assert(count <= 6); + return ch - offsets[count - 1]; +} +#endif /*X_HAVE_UTF8_STRING*/ + +// Convert the specified Latin-1 string to UTF-8 +// +static char* convertLatin1toUTF8(const char* source) +{ + size_t size = 1; + const char* sp; + + for (sp = source; *sp; sp++) + size += (*sp & 0x80) ? 2 : 1; + + char* target = calloc(size, 1); + char* tp = target; + + for (sp = source; *sp; sp++) + tp += encodeUTF8(tp, *sp); + + return target; +} + +// Centers the cursor over the window client area +// +static void centerCursor(_GLFWwindow* window) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); +} + +// Updates the cursor image according to its cursor mode +// +static void updateCursorImage(_GLFWwindow* window) +{ + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + if (window->cursor) + { + XDefineCursor(_glfw.x11.display, window->x11.handle, + window->cursor->x11.handle); + } + else + XUndefineCursor(_glfw.x11.display, window->x11.handle); + } + else + { + XDefineCursor(_glfw.x11.display, window->x11.handle, + _glfw.x11.hiddenCursorHandle); + } +} + +// Create the X11 window (and its colormap) +// +static GLFWbool createNativeWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + Visual* visual, int depth) +{ + // Create a colormap based on the visual used by the current context + window->x11.colormap = XCreateColormap(_glfw.x11.display, + _glfw.x11.root, + visual, + AllocNone); + + window->x11.transparent = _glfwIsVisualTransparentX11(visual); + + // Create the actual window + { + XSetWindowAttributes wa; + const unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask; + + wa.colormap = window->x11.colormap; + wa.border_pixel = 0; + wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | + ExposureMask | FocusChangeMask | VisibilityChangeMask | + EnterWindowMask | LeaveWindowMask | PropertyChangeMask; + + _glfwGrabErrorHandlerX11(); + + window->x11.handle = XCreateWindow(_glfw.x11.display, + _glfw.x11.root, + 0, 0, + wndconfig->width, wndconfig->height, + 0, // Border width + depth, // Color depth + InputOutput, + visual, + wamask, + &wa); + + _glfwReleaseErrorHandlerX11(); + + if (!window->x11.handle) + { + _glfwInputErrorX11(GLFW_PLATFORM_ERROR, + "X11: Failed to create window"); + return GLFW_FALSE; + } + + XSaveContext(_glfw.x11.display, + window->x11.handle, + _glfw.x11.context, + (XPointer) window); + } + + if (!wndconfig->decorated) + _glfwPlatformSetWindowDecorated(window, GLFW_FALSE); + + if (_glfw.x11.NET_WM_STATE && !window->monitor) + { + Atom states[3]; + int count = 0; + + if (wndconfig->floating) + { + if (_glfw.x11.NET_WM_STATE_ABOVE) + states[count++] = _glfw.x11.NET_WM_STATE_ABOVE; + } + + if (wndconfig->maximized) + { + if (_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT; + states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ; + window->x11.maximized = GLFW_TRUE; + } + } + + if (count) + { + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &states, count); + } + } + + // Declare the WM protocols supported by GLFW + { + Atom protocols[] = + { + _glfw.x11.WM_DELETE_WINDOW, + _glfw.x11.NET_WM_PING + }; + + XSetWMProtocols(_glfw.x11.display, window->x11.handle, + protocols, sizeof(protocols) / sizeof(Atom)); + } + + // Declare our PID + { + const long pid = getpid(); + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_PID, XA_CARDINAL, 32, + PropModeReplace, + (unsigned char*) &pid, 1); + } + + if (_glfw.x11.NET_WM_WINDOW_TYPE && _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL) + { + Atom type = _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL; + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_WINDOW_TYPE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &type, 1); + } + + // Set ICCCM WM_HINTS property + { + XWMHints* hints = XAllocWMHints(); + if (!hints) + { + _glfwInputError(GLFW_OUT_OF_MEMORY, + "X11: Failed to allocate WM hints"); + return GLFW_FALSE; + } + + hints->flags = StateHint; + hints->initial_state = NormalState; + + XSetWMHints(_glfw.x11.display, window->x11.handle, hints); + XFree(hints); + } + + updateNormalHints(window, wndconfig->width, wndconfig->height); + + // Set ICCCM WM_CLASS property + { + XClassHint* hint = XAllocClassHint(); + + if (strlen(_glfw.hints.init.x11.className) && + strlen(_glfw.hints.init.x11.classClass)) + { + hint->res_name = (char*) _glfw.hints.init.x11.className; + hint->res_class = (char*) _glfw.hints.init.x11.classClass; + } + else if (strlen(wndconfig->title)) + { + hint->res_name = (char*) wndconfig->title; + hint->res_class = (char*) wndconfig->title; + } + else + { + hint->res_name = (char*) "glfw-application"; + hint->res_class = (char*) "GLFW-Application"; + } + + XSetClassHint(_glfw.x11.display, window->x11.handle, hint); + XFree(hint); + } + + // Announce support for Xdnd (drag and drop) + { + const Atom version = _GLFW_XDND_VERSION; + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.XdndAware, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &version, 1); + } + + _glfwPlatformSetWindowTitle(window, wndconfig->title); + + if (_glfw.x11.im) + { + window->x11.ic = XCreateIC(_glfw.x11.im, + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, + window->x11.handle, + XNFocusWindow, + window->x11.handle, + NULL); + } + + _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); + _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); + + return GLFW_TRUE; +} + +// Set the specified property to the selection converted to the requested target +// +static Atom writeTargetToProperty(const XSelectionRequestEvent* request) +{ + int i; + char* selectionString = NULL; + const Atom formats[] = { _glfw.x11.UTF8_STRING, XA_STRING }; + const int formatCount = sizeof(formats) / sizeof(formats[0]); + + if (request->selection == _glfw.x11.PRIMARY) + selectionString = _glfw.x11.primarySelectionString; + else + selectionString = _glfw.x11.clipboardString; + + if (request->property == None) + { + // The requester is a legacy client (ICCCM section 2.2) + // We don't support legacy clients, so fail here + return None; + } + + if (request->target == _glfw.x11.TARGETS) + { + // The list of supported targets was requested + + const Atom targets[] = { _glfw.x11.TARGETS, + _glfw.x11.MULTIPLE, + _glfw.x11.UTF8_STRING, + XA_STRING }; + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char*) targets, + sizeof(targets) / sizeof(targets[0])); + + return request->property; + } + + if (request->target == _glfw.x11.MULTIPLE) + { + // Multiple conversions were requested + + Atom* targets; + unsigned long i, count; + + count = _glfwGetWindowPropertyX11(request->requestor, + request->property, + _glfw.x11.ATOM_PAIR, + (unsigned char**) &targets); + + for (i = 0; i < count; i += 2) + { + int j; + + for (j = 0; j < formatCount; j++) + { + if (targets[i] == formats[j]) + break; + } + + if (j < formatCount) + { + XChangeProperty(_glfw.x11.display, + request->requestor, + targets[i + 1], + targets[i], + 8, + PropModeReplace, + (unsigned char *) selectionString, + strlen(selectionString)); + } + else + targets[i + 1] = None; + } + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + _glfw.x11.ATOM_PAIR, + 32, + PropModeReplace, + (unsigned char*) targets, + count); + + XFree(targets); + + return request->property; + } + + if (request->target == _glfw.x11.SAVE_TARGETS) + { + // The request is a check whether we support SAVE_TARGETS + // It should be handled as a no-op side effect target + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + _glfw.x11.NULL_, + 32, + PropModeReplace, + NULL, + 0); + + return request->property; + } + + // Conversion to a data target was requested + + for (i = 0; i < formatCount; i++) + { + if (request->target == formats[i]) + { + // The requested target is one we support + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + request->target, + 8, + PropModeReplace, + (unsigned char *) selectionString, + strlen(selectionString)); + + return request->property; + } + } + + // The requested target is not supported + + return None; +} + +static void handleSelectionClear(XEvent* event) +{ + if (event->xselectionclear.selection == _glfw.x11.PRIMARY) + { + free(_glfw.x11.primarySelectionString); + _glfw.x11.primarySelectionString = NULL; + } + else + { + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = NULL; + } +} + +static void handleSelectionRequest(XEvent* event) +{ + const XSelectionRequestEvent* request = &event->xselectionrequest; + + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.xselection.property = writeTargetToProperty(request); + reply.xselection.type = SelectionNotify; + reply.xselection.display = request->display; + reply.xselection.requestor = request->requestor; + reply.xselection.selection = request->selection; + reply.xselection.target = request->target; + reply.xselection.time = request->time; + + XSendEvent(_glfw.x11.display, request->requestor, False, 0, &reply); +} + +static const char* getSelectionString(Atom selection) +{ + size_t i; + char** selectionString = NULL; + const Atom targets[] = { _glfw.x11.UTF8_STRING, XA_STRING }; + const size_t targetCount = sizeof(targets) / sizeof(targets[0]); + + if (selection == _glfw.x11.PRIMARY) + selectionString = &_glfw.x11.primarySelectionString; + else + selectionString = &_glfw.x11.clipboardString; + + if (XGetSelectionOwner(_glfw.x11.display, selection) == + _glfw.x11.helperWindowHandle) + { + // Instead of doing a large number of X round-trips just to put this + // string into a window property and then read it back, just return it + return *selectionString; + } + + free(*selectionString); + *selectionString = NULL; + + for (i = 0; i < targetCount; i++) + { + char* data; + Atom actualType; + int actualFormat; + unsigned long itemCount, bytesAfter; + XEvent notification, dummy; + + XConvertSelection(_glfw.x11.display, + selection, + targets[i], + _glfw.x11.GLFW_SELECTION, + _glfw.x11.helperWindowHandle, + CurrentTime); + + while (!XCheckTypedWindowEvent(_glfw.x11.display, + _glfw.x11.helperWindowHandle, + SelectionNotify, + ¬ification)) + { + waitForEvent(NULL); + } + + if (notification.xselection.property == None) + continue; + + XCheckIfEvent(_glfw.x11.display, + &dummy, + isSelPropNewValueNotify, + (XPointer) ¬ification); + + XGetWindowProperty(_glfw.x11.display, + notification.xselection.requestor, + notification.xselection.property, + 0, + LONG_MAX, + True, + AnyPropertyType, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + (unsigned char**) &data); + + if (actualType == _glfw.x11.INCR) + { + size_t size = 1; + char* string = NULL; + + for (;;) + { + while (!XCheckIfEvent(_glfw.x11.display, + &dummy, + isSelPropNewValueNotify, + (XPointer) ¬ification)) + { + waitForEvent(NULL); + } + + XFree(data); + XGetWindowProperty(_glfw.x11.display, + notification.xselection.requestor, + notification.xselection.property, + 0, + LONG_MAX, + True, + AnyPropertyType, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + (unsigned char**) &data); + + if (itemCount) + { + size += itemCount; + string = realloc(string, size); + string[size - itemCount - 1] = '\0'; + strcat(string, data); + } + + if (!itemCount) + { + if (targets[i] == XA_STRING) + { + *selectionString = convertLatin1toUTF8(string); + free(string); + } + else + *selectionString = string; + + break; + } + } + } + else if (actualType == targets[i]) + { + if (targets[i] == XA_STRING) + *selectionString = convertLatin1toUTF8(data); + else + *selectionString = strdup(data); + } + + XFree(data); + + if (*selectionString) + break; + } + + if (!*selectionString) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "X11: Failed to convert selection to string"); + } + + return *selectionString; +} + +// Make the specified window and its video mode active on its monitor +// +static GLFWbool acquireMonitor(_GLFWwindow* window) +{ + GLFWbool status; + + if (_glfw.x11.saver.count == 0) + { + // Remember old screen saver settings + XGetScreenSaver(_glfw.x11.display, + &_glfw.x11.saver.timeout, + &_glfw.x11.saver.interval, + &_glfw.x11.saver.blanking, + &_glfw.x11.saver.exposure); + + // Disable screen saver + XSetScreenSaver(_glfw.x11.display, 0, 0, DontPreferBlanking, + DefaultExposures); + } + + if (!window->monitor->window) + _glfw.x11.saver.count++; + + status = _glfwSetVideoModeX11(window->monitor, &window->videoMode); + + if (window->x11.overrideRedirect) + { + int xpos, ypos; + GLFWvidmode mode; + + // Manually position the window over its monitor + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + _glfwPlatformGetVideoMode(window->monitor, &mode); + + XMoveResizeWindow(_glfw.x11.display, window->x11.handle, + xpos, ypos, mode.width, mode.height); + } + + _glfwInputMonitorWindow(window->monitor, window); + return status; +} + +// Remove the window and restore the original video mode +// +static void releaseMonitor(_GLFWwindow* window) +{ + if (window->monitor->window != window) + return; + + _glfwInputMonitorWindow(window->monitor, NULL); + _glfwRestoreVideoModeX11(window->monitor); + + _glfw.x11.saver.count--; + + if (_glfw.x11.saver.count == 0) + { + // Restore old screen saver settings + XSetScreenSaver(_glfw.x11.display, + _glfw.x11.saver.timeout, + _glfw.x11.saver.interval, + _glfw.x11.saver.blanking, + _glfw.x11.saver.exposure); + } +} + +// Process the specified X event +// +static void processEvent(XEvent *event) +{ + _GLFWwindow* window = NULL; + int keycode = 0; + Bool filtered = False; + + // HACK: Save scancode as some IMs clear the field in XFilterEvent + if (event->type == KeyPress || event->type == KeyRelease) + keycode = event->xkey.keycode; + + if (_glfw.x11.im) + filtered = XFilterEvent(event, None); + + if (_glfw.x11.randr.available) + { + if (event->type == _glfw.x11.randr.eventBase + RRNotify) + { + XRRUpdateConfiguration(event); + _glfwPollMonitorsX11(); + return; + } + } + + if (event->type == GenericEvent) + { + if (_glfw.x11.xi.available) + { + _GLFWwindow* window = _glfw.x11.disabledCursorWindow; + + if (window && + event->xcookie.extension == _glfw.x11.xi.majorOpcode && + XGetEventData(_glfw.x11.display, &event->xcookie) && + event->xcookie.evtype == XI_RawMotion) + { + XIRawEvent* re = event->xcookie.data; + if (re->valuators.mask_len) + { + const double* values = re->raw_values; + double xpos = window->virtualCursorPosX; + double ypos = window->virtualCursorPosY; + + if (XIMaskIsSet(re->valuators.mask, 0)) + { + xpos += *values; + values++; + } + + if (XIMaskIsSet(re->valuators.mask, 1)) + ypos += *values; + + _glfwInputCursorPos(window, xpos, ypos); + } + } + + XFreeEventData(_glfw.x11.display, &event->xcookie); + } + + return; + } + + if (event->type == SelectionClear) + { + handleSelectionClear(event); + return; + } + else if (event->type == SelectionRequest) + { + handleSelectionRequest(event); + return; + } + + window = findWindowByHandle(event->xany.window); + if (window == NULL) + { + // This is an event for a window that has already been destroyed + return; + } + + switch (event->type) + { + case KeyPress: + { + const int key = translateKey(keycode); + const int mods = translateState(event->xkey.state); + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + + if (window->x11.ic) + { + // HACK: Ignore duplicate key press events generated by ibus + // These have the same timestamp as the original event + // Corresponding release events are filtered out + // implicitly by the GLFW key repeat logic + if (window->x11.lastKeyTime < event->xkey.time) + { + if (keycode) + _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); + + window->x11.lastKeyTime = event->xkey.time; + } + + if (!filtered) + { + int count; + Status status; +#if defined(X_HAVE_UTF8_STRING) + char buffer[100]; + char* chars = buffer; + + count = Xutf8LookupString(window->x11.ic, + &event->xkey, + buffer, sizeof(buffer) - 1, + NULL, &status); + + if (status == XBufferOverflow) + { + chars = calloc(count + 1, 1); + count = Xutf8LookupString(window->x11.ic, + &event->xkey, + chars, count, + NULL, &status); + } + + if (status == XLookupChars || status == XLookupBoth) + { + const char* c = chars; + chars[count] = '\0'; + while (c - chars < count) + _glfwInputChar(window, decodeUTF8(&c), mods, plain); + } +#else /*X_HAVE_UTF8_STRING*/ + wchar_t buffer[16]; + wchar_t* chars = buffer; + + count = XwcLookupString(window->x11.ic, + &event->xkey, + buffer, + sizeof(buffer) / sizeof(wchar_t), + NULL, + &status); + + if (status == XBufferOverflow) + { + chars = calloc(count, sizeof(wchar_t)); + count = XwcLookupString(window->x11.ic, + &event->xkey, + chars, count, + NULL, &status); + } + + if (status == XLookupChars || status == XLookupBoth) + { + int i; + for (i = 0; i < count; i++) + _glfwInputChar(window, chars[i], mods, plain); + } +#endif /*X_HAVE_UTF8_STRING*/ + + if (chars != buffer) + free(chars); + } + } + else + { + KeySym keysym; + XLookupString(&event->xkey, NULL, 0, &keysym, NULL); + + _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); + + const long character = _glfwKeySym2Unicode(keysym); + if (character != -1) + _glfwInputChar(window, character, mods, plain); + } + + return; + } + + case KeyRelease: + { + const int key = translateKey(keycode); + const int mods = translateState(event->xkey.state); + + if (!_glfw.x11.xkb.detectable) + { + // HACK: Key repeat events will arrive as KeyRelease/KeyPress + // pairs with similar or identical time stamps + // The key repeat logic in _glfwInputKey expects only key + // presses to repeat, so detect and discard release events + if (XEventsQueued(_glfw.x11.display, QueuedAfterReading)) + { + XEvent next; + XPeekEvent(_glfw.x11.display, &next); + + if (next.type == KeyPress && + next.xkey.window == event->xkey.window && + next.xkey.keycode == keycode) + { + // HACK: The time of repeat events sometimes doesn't + // match that of the press event, so add an + // epsilon + // Toshiyuki Takahashi can press a button + // 16 times per second so it's fairly safe to + // assume that no human is pressing the key 50 + // times per second (value is ms) + if ((next.xkey.time - event->xkey.time) < 20) + { + // This is very likely a server-generated key repeat + // event, so ignore it + return; + } + } + } + } + + _glfwInputKey(window, key, keycode, GLFW_RELEASE, mods); + return; + } + + case ButtonPress: + { + const int mods = translateState(event->xbutton.state); + + if (event->xbutton.button == Button1) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); + else if (event->xbutton.button == Button2) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods); + else if (event->xbutton.button == Button3) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); + + // Modern X provides scroll events as mouse button presses + else if (event->xbutton.button == Button4) + _glfwInputScroll(window, 0.0, 1.0); + else if (event->xbutton.button == Button5) + _glfwInputScroll(window, 0.0, -1.0); + else if (event->xbutton.button == Button6) + _glfwInputScroll(window, 1.0, 0.0); + else if (event->xbutton.button == Button7) + _glfwInputScroll(window, -1.0, 0.0); + + else + { + // Additional buttons after 7 are treated as regular buttons + // We subtract 4 to fill the gap left by scroll input above + _glfwInputMouseClick(window, + event->xbutton.button - Button1 - 4, + GLFW_PRESS, + mods); + } + + return; + } + + case ButtonRelease: + { + const int mods = translateState(event->xbutton.state); + + if (event->xbutton.button == Button1) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE, + mods); + } + else if (event->xbutton.button == Button2) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_MIDDLE, + GLFW_RELEASE, + mods); + } + else if (event->xbutton.button == Button3) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_RIGHT, + GLFW_RELEASE, + mods); + } + else if (event->xbutton.button > Button7) + { + // Additional buttons after 7 are treated as regular buttons + // We subtract 4 to fill the gap left by scroll input above + _glfwInputMouseClick(window, + event->xbutton.button - Button1 - 4, + GLFW_RELEASE, + mods); + } + + return; + } + + case EnterNotify: + { + // HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise + // ignore the defined cursor for hidden cursor mode + if (window->cursorMode == GLFW_CURSOR_HIDDEN) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_HIDDEN); + + _glfwInputCursorEnter(window, GLFW_TRUE); + return; + } + + case LeaveNotify: + { + _glfwInputCursorEnter(window, GLFW_FALSE); + return; + } + + case MotionNotify: + { + const int x = event->xmotion.x; + const int y = event->xmotion.y; + + if (x != window->x11.warpCursorPosX || + y != window->x11.warpCursorPosY) + { + // The cursor was moved by something other than GLFW + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (_glfw.x11.disabledCursorWindow != window) + return; + if (_glfw.x11.xi.available) + return; + + const int dx = x - window->x11.lastCursorPosX; + const int dy = y - window->x11.lastCursorPosY; + + _glfwInputCursorPos(window, + window->virtualCursorPosX + dx, + window->virtualCursorPosY + dy); + } + else + _glfwInputCursorPos(window, x, y); + } + + window->x11.lastCursorPosX = x; + window->x11.lastCursorPosY = y; + return; + } + + case ConfigureNotify: + { + if (event->xconfigure.width != window->x11.width || + event->xconfigure.height != window->x11.height) + { + _glfwInputFramebufferSize(window, + event->xconfigure.width, + event->xconfigure.height); + + _glfwInputWindowSize(window, + event->xconfigure.width, + event->xconfigure.height); + + window->x11.width = event->xconfigure.width; + window->x11.height = event->xconfigure.height; + } + + if (event->xconfigure.x != window->x11.xpos || + event->xconfigure.y != window->x11.ypos) + { + if (window->x11.overrideRedirect || event->xany.send_event) + { + _glfwInputWindowPos(window, + event->xconfigure.x, + event->xconfigure.y); + + window->x11.xpos = event->xconfigure.x; + window->x11.ypos = event->xconfigure.y; + } + } + + return; + } + + case ClientMessage: + { + // Custom client message, probably from the window manager + + if (filtered) + return; + + if (event->xclient.message_type == None) + return; + + if (event->xclient.message_type == _glfw.x11.WM_PROTOCOLS) + { + const Atom protocol = event->xclient.data.l[0]; + if (protocol == None) + return; + + if (protocol == _glfw.x11.WM_DELETE_WINDOW) + { + // The window manager was asked to close the window, for + // example by the user pressing a 'close' window decoration + // button + _glfwInputWindowCloseRequest(window); + } + else if (protocol == _glfw.x11.NET_WM_PING) + { + // The window manager is pinging the application to ensure + // it's still responding to events + + XEvent reply = *event; + reply.xclient.window = _glfw.x11.root; + + XSendEvent(_glfw.x11.display, _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &reply); + } + } + else if (event->xclient.message_type == _glfw.x11.XdndEnter) + { + // A drag operation has entered the window + unsigned long i, count; + Atom* formats = NULL; + const GLFWbool list = event->xclient.data.l[1] & 1; + + _glfw.x11.xdnd.source = event->xclient.data.l[0]; + _glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24; + _glfw.x11.xdnd.format = None; + + if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) + return; + + if (list) + { + count = _glfwGetWindowPropertyX11(_glfw.x11.xdnd.source, + _glfw.x11.XdndTypeList, + XA_ATOM, + (unsigned char**) &formats); + } + else + { + count = 3; + formats = (Atom*) event->xclient.data.l + 2; + } + + for (i = 0; i < count; i++) + { + if (formats[i] == _glfw.x11.text_uri_list) + { + _glfw.x11.xdnd.format = _glfw.x11.text_uri_list; + break; + } + } + + if (list && formats) + XFree(formats); + } + else if (event->xclient.message_type == _glfw.x11.XdndDrop) + { + // The drag operation has finished by dropping on the window + Time time = CurrentTime; + + if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) + return; + + if (_glfw.x11.xdnd.format) + { + if (_glfw.x11.xdnd.version >= 1) + time = event->xclient.data.l[2]; + + // Request the chosen format from the source window + XConvertSelection(_glfw.x11.display, + _glfw.x11.XdndSelection, + _glfw.x11.xdnd.format, + _glfw.x11.XdndSelection, + window->x11.handle, + time); + } + else if (_glfw.x11.xdnd.version >= 2) + { + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.type = ClientMessage; + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = 0; // The drag was rejected + reply.xclient.data.l[2] = None; + + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } + } + else if (event->xclient.message_type == _glfw.x11.XdndPosition) + { + // The drag operation has moved over the window + const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff; + const int yabs = (event->xclient.data.l[2]) & 0xffff; + Window dummy; + int xpos, ypos; + + if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) + return; + + XTranslateCoordinates(_glfw.x11.display, + _glfw.x11.root, + window->x11.handle, + xabs, yabs, + &xpos, &ypos, + &dummy); + + _glfwInputCursorPos(window, xpos, ypos); + + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.type = ClientMessage; + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndStatus; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[2] = 0; // Specify an empty rectangle + reply.xclient.data.l[3] = 0; + + if (_glfw.x11.xdnd.format) + { + // Reply that we are ready to copy the dragged data + reply.xclient.data.l[1] = 1; // Accept with no rectangle + if (_glfw.x11.xdnd.version >= 2) + reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy; + } + + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } + + return; + } + + case SelectionNotify: + { + if (event->xselection.property == _glfw.x11.XdndSelection) + { + // The converted data from the drag operation has arrived + char* data; + const unsigned long result = + _glfwGetWindowPropertyX11(event->xselection.requestor, + event->xselection.property, + event->xselection.target, + (unsigned char**) &data); + + if (result) + { + int i, count; + char** paths = parseUriList(data, &count); + + _glfwInputDrop(window, count, (const char**) paths); + + for (i = 0; i < count; i++) + free(paths[i]); + free(paths); + } + + if (data) + XFree(data); + + if (_glfw.x11.xdnd.version >= 2) + { + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.type = ClientMessage; + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = result; + reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; + + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } + } + + return; + } + + case FocusIn: + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + + if (event->xfocus.mode == NotifyGrab || + event->xfocus.mode == NotifyUngrab) + { + // Ignore focus events from popup indicator windows, window menu + // key chords and window dragging + return; + } + + if (window->x11.ic) + XSetICFocus(window->x11.ic); + + _glfwInputWindowFocus(window, GLFW_TRUE); + return; + } + + case FocusOut: + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + + if (event->xfocus.mode == NotifyGrab || + event->xfocus.mode == NotifyUngrab) + { + // Ignore focus events from popup indicator windows, window menu + // key chords and window dragging + return; + } + + if (window->x11.ic) + XUnsetICFocus(window->x11.ic); + + if (window->monitor && window->autoIconify) + _glfwPlatformIconifyWindow(window); + + _glfwInputWindowFocus(window, GLFW_FALSE); + return; + } + + case Expose: + { + _glfwInputWindowDamage(window); + return; + } + + case PropertyNotify: + { + if (event->xproperty.state != PropertyNewValue) + return; + + if (event->xproperty.atom == _glfw.x11.WM_STATE) + { + const int state = getWindowState(window); + if (state != IconicState && state != NormalState) + return; + + const GLFWbool iconified = (state == IconicState); + if (window->x11.iconified != iconified) + { + if (window->monitor) + { + if (iconified) + releaseMonitor(window); + else + acquireMonitor(window); + } + + window->x11.iconified = iconified; + _glfwInputWindowIconify(window, iconified); + } + } + else if (event->xproperty.atom == _glfw.x11.NET_WM_STATE) + { + const GLFWbool maximized = _glfwPlatformWindowMaximized(window); + if (window->x11.maximized != maximized) + { + window->x11.maximized = maximized; + _glfwInputWindowMaximize(window, maximized); + } + } + + return; + } + + case DestroyNotify: + return; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Retrieve a single window property of the specified type +// Inspired by fghGetWindowProperty from freeglut +// +unsigned long _glfwGetWindowPropertyX11(Window window, + Atom property, + Atom type, + unsigned char** value) +{ + Atom actualType; + int actualFormat; + unsigned long itemCount, bytesAfter; + + XGetWindowProperty(_glfw.x11.display, + window, + property, + 0, + LONG_MAX, + False, + type, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + value); + + return itemCount; +} + +GLFWbool _glfwIsVisualTransparentX11(Visual* visual) +{ + if (!_glfw.x11.xrender.available) + return GLFW_FALSE; + + XRenderPictFormat* pf = XRenderFindVisualFormat(_glfw.x11.display, visual); + return pf && pf->direct.alphaMask; +} + +// Push contents of our selection to clipboard manager +// +void _glfwPushSelectionToManagerX11(void) +{ + XConvertSelection(_glfw.x11.display, + _glfw.x11.CLIPBOARD_MANAGER, + _glfw.x11.SAVE_TARGETS, + None, + _glfw.x11.helperWindowHandle, + CurrentTime); + + for (;;) + { + XEvent event; + + while (XCheckIfEvent(_glfw.x11.display, &event, isSelectionEvent, NULL)) + { + switch (event.type) + { + case SelectionRequest: + handleSelectionRequest(&event); + break; + + case SelectionClear: + handleSelectionClear(&event); + break; + + case SelectionNotify: + { + if (event.xselection.target == _glfw.x11.SAVE_TARGETS) + { + // This means one of two things; either the selection + // was not owned, which means there is no clipboard + // manager, or the transfer to the clipboard manager has + // completed + // In either case, it means we are done here + return; + } + + break; + } + } + } + + waitForEvent(NULL); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + Visual* visual; + int depth; + + if (ctxconfig->client != GLFW_NO_API) + { + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwInitGLX()) + return GLFW_FALSE; + if (!_glfwChooseVisualGLX(wndconfig, ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; + } + else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwChooseVisualEGL(wndconfig, ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; + } + else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwInitOSMesa()) + return GLFW_FALSE; + } + } + + if (ctxconfig->client == GLFW_NO_API || + ctxconfig->source == GLFW_OSMESA_CONTEXT_API) + { + visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen); + depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen); + } + + if (!createNativeWindow(window, wndconfig, visual, depth)) + return GLFW_FALSE; + + if (ctxconfig->client != GLFW_NO_API) + { + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwCreateContextGLX(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) + { + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + } + + if (window->monitor) + { + _glfwPlatformShowWindow(window); + updateWindowMode(window); + if (!acquireMonitor(window)) + return GLFW_FALSE; + + if (wndconfig->centerCursor) + centerCursor(window); + } + + XFlush(_glfw.x11.display); + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (_glfw.x11.disabledCursorWindow == window) + _glfw.x11.disabledCursorWindow = NULL; + + if (window->monitor) + releaseMonitor(window); + + if (window->x11.ic) + { + XDestroyIC(window->x11.ic); + window->x11.ic = NULL; + } + + if (window->context.destroy) + window->context.destroy(window); + + if (window->x11.handle) + { + XDeleteContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context); + XUnmapWindow(_glfw.x11.display, window->x11.handle); + XDestroyWindow(_glfw.x11.display, window->x11.handle); + window->x11.handle = (Window) 0; + } + + if (window->x11.colormap) + { + XFreeColormap(_glfw.x11.display, window->x11.colormap); + window->x11.colormap = (Colormap) 0; + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ +#if defined(X_HAVE_UTF8_STRING) + Xutf8SetWMProperties(_glfw.x11.display, + window->x11.handle, + title, title, + NULL, 0, + NULL, NULL, NULL); +#else + // This may be a slightly better fallback than using XStoreName and + // XSetIconName, which always store their arguments using STRING + XmbSetWMProperties(_glfw.x11.display, + window->x11.handle, + title, title, + NULL, 0, + NULL, NULL, NULL); +#endif + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8, + PropModeReplace, + (unsigned char*) title, strlen(title)); + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8, + PropModeReplace, + (unsigned char*) title, strlen(title)); + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + if (count) + { + int i, j, longCount = 0; + + for (i = 0; i < count; i++) + longCount += 2 + images[i].width * images[i].height; + + long* icon = calloc(longCount, sizeof(long)); + long* target = icon; + + for (i = 0; i < count; i++) + { + *target++ = images[i].width; + *target++ = images[i].height; + + for (j = 0; j < images[i].width * images[i].height; j++) + { + *target++ = (images[i].pixels[j * 4 + 0] << 16) | + (images[i].pixels[j * 4 + 1] << 8) | + (images[i].pixels[j * 4 + 2] << 0) | + (images[i].pixels[j * 4 + 3] << 24); + } + } + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_ICON, + XA_CARDINAL, 32, + PropModeReplace, + (unsigned char*) icon, + longCount); + + free(icon); + } + else + { + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_ICON); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + Window dummy; + int x, y; + + XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root, + 0, 0, &x, &y, &dummy); + + if (xpos) + *xpos = x; + if (ypos) + *ypos = y; +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + // HACK: Explicitly setting PPosition to any value causes some WMs, notably + // Compiz and Metacity, to honor the position of unmapped windows + if (!_glfwPlatformWindowVisible(window)) + { + long supplied; + XSizeHints* hints = XAllocSizeHints(); + + if (XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied)) + { + hints->flags |= PPosition; + hints->x = hints->y = 0; + + XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); + } + + XFree(hints); + } + + XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + XWindowAttributes attribs; + XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs); + + if (width) + *width = attribs.width; + if (height) + *height = attribs.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + if (window->monitor) + { + if (window->monitor->window == window) + acquireMonitor(window); + } + else + { + if (!window->resizable) + updateNormalHints(window, width, height); + + XResizeWindow(_glfw.x11.display, window->x11.handle, width, height); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + updateNormalHints(window, width, height); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + updateNormalHints(window, width, height); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + _glfwPlatformGetWindowSize(window, width, height); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + long* extents = NULL; + + if (window->monitor || !window->decorated) + return; + + if (_glfw.x11.NET_FRAME_EXTENTS == None) + return; + + if (!_glfwPlatformWindowVisible(window) && + _glfw.x11.NET_REQUEST_FRAME_EXTENTS) + { + XEvent event; + double timeout = 0.5; + + // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to + // function before the window is mapped + sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS, + 0, 0, 0, 0, 0); + + // HACK: Use a timeout because earlier versions of some window managers + // (at least Unity, Fluxbox and Xfwm) failed to send the reply + // They have been fixed but broken versions are still in the wild + // If you are affected by this and your window manager is NOT + // listed above, PLEASE report it to their and our issue trackers + while (!XCheckIfEvent(_glfw.x11.display, + &event, + isFrameExtentsEvent, + (XPointer) window)) + { + if (!waitForEvent(&timeout)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); + return; + } + } + } + + if (_glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_FRAME_EXTENTS, + XA_CARDINAL, + (unsigned char**) &extents) == 4) + { + if (left) + *left = extents[0]; + if (top) + *top = extents[2]; + if (right) + *right = extents[1]; + if (bottom) + *bottom = extents[3]; + } + + if (extents) + XFree(extents); +} + +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, + float* xscale, float* yscale) +{ + if (xscale) + *xscale = _glfw.x11.contentScaleX; + if (yscale) + *yscale = _glfw.x11.contentScaleY; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + if (window->x11.overrideRedirect) + { + // Override-redirect windows cannot be iconified or restored, as those + // tasks are performed by the window manager + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Iconification of full screen windows requires a WM that supports EWMH full screen"); + return; + } + + XIconifyWindow(_glfw.x11.display, window->x11.handle, _glfw.x11.screen); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + if (window->x11.overrideRedirect) + { + // Override-redirect windows cannot be iconified or restored, as those + // tasks are performed by the window manager + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Iconification of full screen windows requires a WM that supports EWMH full screen"); + return; + } + + if (_glfwPlatformWindowIconified(window)) + { + XMapWindow(_glfw.x11.display, window->x11.handle); + waitForVisibilityNotify(window); + } + else if (_glfwPlatformWindowVisible(window)) + { + if (_glfw.x11.NET_WM_STATE && + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_REMOVE, + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, + 1, 0); + } + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + if (_glfw.x11.NET_WM_STATE && + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, + 1, 0); + XFlush(_glfw.x11.display); + } +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + if (_glfwPlatformWindowVisible(window)) + return; + + XMapWindow(_glfw.x11.display, window->x11.handle); + waitForVisibilityNotify(window); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + XUnmapWindow(_glfw.x11.display, window->x11.handle); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +{ + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION, + 0, 1, 0); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + if (_glfw.x11.NET_ACTIVE_WINDOW) + sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); + else + { + XRaiseWindow(_glfw.x11.display, window->x11.handle); + XSetInputFocus(_glfw.x11.display, window->x11.handle, + RevertToParent, CurrentTime); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + XMoveResizeWindow(_glfw.x11.display, window->x11.handle, + xpos, ypos, width, height); + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitor(window, monitor); + updateNormalHints(window, width, height); + updateWindowMode(window); + + if (window->monitor) + { + XMapRaised(_glfw.x11.display, window->x11.handle); + if (waitForVisibilityNotify(window)) + acquireMonitor(window); + } + else + { + XMoveResizeWindow(_glfw.x11.display, window->x11.handle, + xpos, ypos, width, height); + } + + XFlush(_glfw.x11.display); +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + Window focused; + int state; + + XGetInputFocus(_glfw.x11.display, &focused, &state); + return window->x11.handle == focused; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + return getWindowState(window) == IconicState; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + XWindowAttributes wa; + XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &wa); + return wa.map_state == IsViewable; +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + Atom* states; + unsigned long i; + GLFWbool maximized = GLFW_FALSE; + const unsigned long count = + _glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_WM_STATE, + XA_ATOM, + (unsigned char**) &states); + + for (i = 0; i < count; i++) + { + if (states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || + states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + maximized = GLFW_TRUE; + break; + } + } + + if (states) + XFree(states); + + return maximized; +} + +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +{ + if (!window->x11.transparent) + return GLFW_FALSE; + + // Check whether a compositing manager is running + char name[32]; + snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen); + const Atom selection = XInternAtom(_glfw.x11.display, name, False); + return XGetSelectionOwner(_glfw.x11.display, selection) != None; +} + +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + updateNormalHints(window, width, height); +} + +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) +{ + if (enabled) + { + XDeleteProperty(_glfw.x11.display, + window->x11.handle, + _glfw.x11.MOTIF_WM_HINTS); + } + else + { + struct + { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; + } hints; + + hints.flags = 2; // Set decorations + hints.decorations = 0; // No decorations + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.MOTIF_WM_HINTS, + _glfw.x11.MOTIF_WM_HINTS, 32, + PropModeReplace, + (unsigned char*) &hints, + sizeof(hints) / sizeof(long)); + } +} + +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) +{ + if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_ABOVE) + return; + + if (_glfwPlatformWindowVisible(window)) + { + const Atom action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + action, + _glfw.x11.NET_WM_STATE_ABOVE, + 0, 1, 0); + } + else + { + Atom* states; + unsigned long i, count; + + count = _glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_WM_STATE, + XA_ATOM, + (unsigned char**) &states); + if (!states) + return; + + if (enabled) + { + for (i = 0; i < count; i++) + { + if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) + break; + } + + if (i == count) + { + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeAppend, + (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE, + 1); + } + } + else + { + for (i = 0; i < count; i++) + { + if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) + { + states[i] = states[count - 1]; + count--; + } + } + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &states, count); + } + + XFree(states); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformPollEvents(void) +{ + _GLFWwindow* window; + +#if defined(__linux__) + _glfwDetectJoystickConnectionLinux(); +#endif + int count = XPending(_glfw.x11.display); + while (count--) + { + XEvent event; + XNextEvent(_glfw.x11.display, &event); + processEvent(&event); + } + + window = _glfw.x11.disabledCursorWindow; + if (window) + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + + // NOTE: Re-center the cursor only if it has moved since the last call, + // to avoid breaking glfwWaitEvents with MotionNotify + if (window->x11.lastCursorPosX != width / 2 || + window->x11.lastCursorPosY != height / 2) + { + _glfwPlatformSetCursorPos(window, width / 2, height / 2); + } + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformWaitEvents(void) +{ + while (!XPending(_glfw.x11.display)) + waitForEvent(NULL); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + while (!XPending(_glfw.x11.display)) + { + if (!waitForEvent(&timeout)) + break; + } + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformPostEmptyEvent(void) +{ + XEvent event; + + memset(&event, 0, sizeof(event)); + event.type = ClientMessage; + event.xclient.window = _glfw.x11.helperWindowHandle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11.NULL_; + + XSendEvent(_glfw.x11.display, _glfw.x11.helperWindowHandle, False, 0, &event); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + Window root, child; + int rootX, rootY, childX, childY; + unsigned int mask; + + XQueryPointer(_glfw.x11.display, window->x11.handle, + &root, &child, + &rootX, &rootY, &childX, &childY, + &mask); + + if (xpos) + *xpos = childX; + if (ypos) + *ypos = childY; +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +{ + // Store the new position so it can be recognized later + window->x11.warpCursorPosX = (int) x; + window->x11.warpCursorPosY = (int) y; + + XWarpPointer(_glfw.x11.display, None, window->x11.handle, + 0,0,0,0, (int) x, (int) y); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + if (mode == GLFW_CURSOR_DISABLED) + { + if (_glfw.x11.xi.available) + { + XIEventMask em; + unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; + + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + XISetMask(mask, XI_RawMotion); + + XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); + } + + _glfw.x11.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.x11.restoreCursorPosX, + &_glfw.x11.restoreCursorPosY); + centerCursor(window); + XGrabPointer(_glfw.x11.display, window->x11.handle, True, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + window->x11.handle, + _glfw.x11.hiddenCursorHandle, + CurrentTime); + } + else if (_glfw.x11.disabledCursorWindow == window) + { + if (_glfw.x11.xi.available) + { + XIEventMask em; + unsigned char mask[] = { 0 }; + + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + + XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); + } + + _glfw.x11.disabledCursorWindow = NULL; + XUngrabPointer(_glfw.x11.display, CurrentTime); + _glfwPlatformSetCursorPos(window, + _glfw.x11.restoreCursorPosX, + _glfw.x11.restoreCursorPosY); + } + + updateCursorImage(window); + XFlush(_glfw.x11.display); +} + +const char* _glfwPlatformGetScancodeName(int scancode) +{ + if (!_glfw.x11.xkb.available) + return NULL; + + const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); + if (keysym == NoSymbol) + return NULL; + + const long ch = _glfwKeySym2Unicode(keysym); + if (ch == -1) + return NULL; + + const size_t count = encodeUTF8(_glfw.x11.keyName, (unsigned int) ch); + if (count == 0) + return NULL; + + _glfw.x11.keyName[count] = '\0'; + return _glfw.x11.keyName; +} + +int _glfwPlatformGetKeyScancode(int key) +{ + return _glfw.x11.scancodes[key]; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + cursor->x11.handle = _glfwCreateCursorX11(image, xhot, yhot); + if (!cursor->x11.handle) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, + translateCursorShape(shape)); + if (!cursor->x11.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create standard cursor"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + if (cursor->x11.handle) + XFreeCursor(_glfw.x11.display, cursor->x11.handle); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + updateCursorImage(window); + XFlush(_glfw.x11.display); + } +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = strdup(string); + + XSetSelectionOwner(_glfw.x11.display, + _glfw.x11.CLIPBOARD, + _glfw.x11.helperWindowHandle, + CurrentTime); + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) != + _glfw.x11.helperWindowHandle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to become owner of clipboard selection"); + } +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + return getSelectionString(_glfw.x11.CLIPBOARD); +} + +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) +{ + if (!_glfw.vk.KHR_surface) + return; + + if (!_glfw.vk.KHR_xcb_surface || !_glfw.x11.x11xcb.handle) + { + if (!_glfw.vk.KHR_xlib_surface) + return; + } + + extensions[0] = "VK_KHR_surface"; + + // NOTE: VK_KHR_xcb_surface is preferred due to some early ICDs exposing but + // not correctly implementing VK_KHR_xlib_surface + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) + extensions[1] = "VK_KHR_xcb_surface"; + else + extensions[1] = "VK_KHR_xlib_surface"; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + VisualID visualID = XVisualIDFromVisual(DefaultVisual(_glfw.x11.display, + _glfw.x11.screen)); + + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) + { + PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR + vkGetPhysicalDeviceXcbPresentationSupportKHR = + (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); + if (!vkGetPhysicalDeviceXcbPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xcb_surface extension"); + return GLFW_FALSE; + } + + xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display); + if (!connection) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to retrieve XCB connection"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceXcbPresentationSupportKHR(device, + queuefamily, + connection, + visualID); + } + else + { + PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR + vkGetPhysicalDeviceXlibPresentationSupportKHR = + (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); + if (!vkGetPhysicalDeviceXlibPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceXlibPresentationSupportKHR(device, + queuefamily, + _glfw.x11.display, + visualID); + } +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) + { + VkResult err; + VkXcbSurfaceCreateInfoKHR sci; + PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; + + xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display); + if (!connection) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to retrieve XCB connection"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR"); + if (!vkCreateXcbSurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xcb_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + sci.connection = connection; + sci.window = window->x11.handle; + + err = vkCreateXcbSurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create Vulkan XCB surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; + } + else + { + VkResult err; + VkXlibSurfaceCreateInfoKHR sci; + PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; + + vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR"); + if (!vkCreateXlibSurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + sci.dpy = _glfw.x11.display; + sci.window = window->x11.handle; + + err = vkCreateXlibSurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create Vulkan X11 surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI Display* glfwGetX11Display(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfw.x11.display; +} + +GLFWAPI Window glfwGetX11Window(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + return window->x11.handle; +} + +GLFWAPI void glfwSetX11SelectionString(const char* string) +{ + _GLFW_REQUIRE_INIT(); + + free(_glfw.x11.primarySelectionString); + _glfw.x11.primarySelectionString = strdup(string); + + XSetSelectionOwner(_glfw.x11.display, + _glfw.x11.PRIMARY, + _glfw.x11.helperWindowHandle, + CurrentTime); + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.PRIMARY) != + _glfw.x11.helperWindowHandle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to become owner of primary selection"); + } +} + +GLFWAPI const char* glfwGetX11SelectionString(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return getSelectionString(_glfw.x11.PRIMARY); +} + diff --git a/src/external/glfw/src/xkb_unicode.c b/src/external/glfw/src/xkb_unicode.c new file mode 100644 index 00000000..ecfdc2af --- /dev/null +++ b/src/external/glfw/src/xkb_unicode.c @@ -0,0 +1,940 @@ +//======================================================================== +// GLFW 3.3 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +/* + * Marcus: This code was originally written by Markus G. Kuhn. + * I have made some slight changes (trimmed it down a bit from >60 KB to + * 20 KB), but the functionality is the same. + */ + +/* + * This module converts keysym values into the corresponding ISO 10646 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * _glfwKeySym2Unicode() maps a keysym onto a Unicode value using a binary + * search, therefore keysymtab[] must remain SORTED by keysym value. + * + * We allow to represent any UCS character in the range U-00000000 to + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U-10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x0100abcd. + * + * Original author: Markus G. Kuhn , University of + * Cambridge, April 2001 + * + * Special thanks to Richard Verhoeven for preparing + * an initial draft of the mapping table. + * + */ + + +//************************************************************************ +//**** KeySym to Unicode mapping table **** +//************************************************************************ + +static const struct codepair { + unsigned short keysym; + unsigned short ucs; +} keysymtab[] = { + { 0x01a1, 0x0104 }, + { 0x01a2, 0x02d8 }, + { 0x01a3, 0x0141 }, + { 0x01a5, 0x013d }, + { 0x01a6, 0x015a }, + { 0x01a9, 0x0160 }, + { 0x01aa, 0x015e }, + { 0x01ab, 0x0164 }, + { 0x01ac, 0x0179 }, + { 0x01ae, 0x017d }, + { 0x01af, 0x017b }, + { 0x01b1, 0x0105 }, + { 0x01b2, 0x02db }, + { 0x01b3, 0x0142 }, + { 0x01b5, 0x013e }, + { 0x01b6, 0x015b }, + { 0x01b7, 0x02c7 }, + { 0x01b9, 0x0161 }, + { 0x01ba, 0x015f }, + { 0x01bb, 0x0165 }, + { 0x01bc, 0x017a }, + { 0x01bd, 0x02dd }, + { 0x01be, 0x017e }, + { 0x01bf, 0x017c }, + { 0x01c0, 0x0154 }, + { 0x01c3, 0x0102 }, + { 0x01c5, 0x0139 }, + { 0x01c6, 0x0106 }, + { 0x01c8, 0x010c }, + { 0x01ca, 0x0118 }, + { 0x01cc, 0x011a }, + { 0x01cf, 0x010e }, + { 0x01d0, 0x0110 }, + { 0x01d1, 0x0143 }, + { 0x01d2, 0x0147 }, + { 0x01d5, 0x0150 }, + { 0x01d8, 0x0158 }, + { 0x01d9, 0x016e }, + { 0x01db, 0x0170 }, + { 0x01de, 0x0162 }, + { 0x01e0, 0x0155 }, + { 0x01e3, 0x0103 }, + { 0x01e5, 0x013a }, + { 0x01e6, 0x0107 }, + { 0x01e8, 0x010d }, + { 0x01ea, 0x0119 }, + { 0x01ec, 0x011b }, + { 0x01ef, 0x010f }, + { 0x01f0, 0x0111 }, + { 0x01f1, 0x0144 }, + { 0x01f2, 0x0148 }, + { 0x01f5, 0x0151 }, + { 0x01f8, 0x0159 }, + { 0x01f9, 0x016f }, + { 0x01fb, 0x0171 }, + { 0x01fe, 0x0163 }, + { 0x01ff, 0x02d9 }, + { 0x02a1, 0x0126 }, + { 0x02a6, 0x0124 }, + { 0x02a9, 0x0130 }, + { 0x02ab, 0x011e }, + { 0x02ac, 0x0134 }, + { 0x02b1, 0x0127 }, + { 0x02b6, 0x0125 }, + { 0x02b9, 0x0131 }, + { 0x02bb, 0x011f }, + { 0x02bc, 0x0135 }, + { 0x02c5, 0x010a }, + { 0x02c6, 0x0108 }, + { 0x02d5, 0x0120 }, + { 0x02d8, 0x011c }, + { 0x02dd, 0x016c }, + { 0x02de, 0x015c }, + { 0x02e5, 0x010b }, + { 0x02e6, 0x0109 }, + { 0x02f5, 0x0121 }, + { 0x02f8, 0x011d }, + { 0x02fd, 0x016d }, + { 0x02fe, 0x015d }, + { 0x03a2, 0x0138 }, + { 0x03a3, 0x0156 }, + { 0x03a5, 0x0128 }, + { 0x03a6, 0x013b }, + { 0x03aa, 0x0112 }, + { 0x03ab, 0x0122 }, + { 0x03ac, 0x0166 }, + { 0x03b3, 0x0157 }, + { 0x03b5, 0x0129 }, + { 0x03b6, 0x013c }, + { 0x03ba, 0x0113 }, + { 0x03bb, 0x0123 }, + { 0x03bc, 0x0167 }, + { 0x03bd, 0x014a }, + { 0x03bf, 0x014b }, + { 0x03c0, 0x0100 }, + { 0x03c7, 0x012e }, + { 0x03cc, 0x0116 }, + { 0x03cf, 0x012a }, + { 0x03d1, 0x0145 }, + { 0x03d2, 0x014c }, + { 0x03d3, 0x0136 }, + { 0x03d9, 0x0172 }, + { 0x03dd, 0x0168 }, + { 0x03de, 0x016a }, + { 0x03e0, 0x0101 }, + { 0x03e7, 0x012f }, + { 0x03ec, 0x0117 }, + { 0x03ef, 0x012b }, + { 0x03f1, 0x0146 }, + { 0x03f2, 0x014d }, + { 0x03f3, 0x0137 }, + { 0x03f9, 0x0173 }, + { 0x03fd, 0x0169 }, + { 0x03fe, 0x016b }, + { 0x047e, 0x203e }, + { 0x04a1, 0x3002 }, + { 0x04a2, 0x300c }, + { 0x04a3, 0x300d }, + { 0x04a4, 0x3001 }, + { 0x04a5, 0x30fb }, + { 0x04a6, 0x30f2 }, + { 0x04a7, 0x30a1 }, + { 0x04a8, 0x30a3 }, + { 0x04a9, 0x30a5 }, + { 0x04aa, 0x30a7 }, + { 0x04ab, 0x30a9 }, + { 0x04ac, 0x30e3 }, + { 0x04ad, 0x30e5 }, + { 0x04ae, 0x30e7 }, + { 0x04af, 0x30c3 }, + { 0x04b0, 0x30fc }, + { 0x04b1, 0x30a2 }, + { 0x04b2, 0x30a4 }, + { 0x04b3, 0x30a6 }, + { 0x04b4, 0x30a8 }, + { 0x04b5, 0x30aa }, + { 0x04b6, 0x30ab }, + { 0x04b7, 0x30ad }, + { 0x04b8, 0x30af }, + { 0x04b9, 0x30b1 }, + { 0x04ba, 0x30b3 }, + { 0x04bb, 0x30b5 }, + { 0x04bc, 0x30b7 }, + { 0x04bd, 0x30b9 }, + { 0x04be, 0x30bb }, + { 0x04bf, 0x30bd }, + { 0x04c0, 0x30bf }, + { 0x04c1, 0x30c1 }, + { 0x04c2, 0x30c4 }, + { 0x04c3, 0x30c6 }, + { 0x04c4, 0x30c8 }, + { 0x04c5, 0x30ca }, + { 0x04c6, 0x30cb }, + { 0x04c7, 0x30cc }, + { 0x04c8, 0x30cd }, + { 0x04c9, 0x30ce }, + { 0x04ca, 0x30cf }, + { 0x04cb, 0x30d2 }, + { 0x04cc, 0x30d5 }, + { 0x04cd, 0x30d8 }, + { 0x04ce, 0x30db }, + { 0x04cf, 0x30de }, + { 0x04d0, 0x30df }, + { 0x04d1, 0x30e0 }, + { 0x04d2, 0x30e1 }, + { 0x04d3, 0x30e2 }, + { 0x04d4, 0x30e4 }, + { 0x04d5, 0x30e6 }, + { 0x04d6, 0x30e8 }, + { 0x04d7, 0x30e9 }, + { 0x04d8, 0x30ea }, + { 0x04d9, 0x30eb }, + { 0x04da, 0x30ec }, + { 0x04db, 0x30ed }, + { 0x04dc, 0x30ef }, + { 0x04dd, 0x30f3 }, + { 0x04de, 0x309b }, + { 0x04df, 0x309c }, + { 0x05ac, 0x060c }, + { 0x05bb, 0x061b }, + { 0x05bf, 0x061f }, + { 0x05c1, 0x0621 }, + { 0x05c2, 0x0622 }, + { 0x05c3, 0x0623 }, + { 0x05c4, 0x0624 }, + { 0x05c5, 0x0625 }, + { 0x05c6, 0x0626 }, + { 0x05c7, 0x0627 }, + { 0x05c8, 0x0628 }, + { 0x05c9, 0x0629 }, + { 0x05ca, 0x062a }, + { 0x05cb, 0x062b }, + { 0x05cc, 0x062c }, + { 0x05cd, 0x062d }, + { 0x05ce, 0x062e }, + { 0x05cf, 0x062f }, + { 0x05d0, 0x0630 }, + { 0x05d1, 0x0631 }, + { 0x05d2, 0x0632 }, + { 0x05d3, 0x0633 }, + { 0x05d4, 0x0634 }, + { 0x05d5, 0x0635 }, + { 0x05d6, 0x0636 }, + { 0x05d7, 0x0637 }, + { 0x05d8, 0x0638 }, + { 0x05d9, 0x0639 }, + { 0x05da, 0x063a }, + { 0x05e0, 0x0640 }, + { 0x05e1, 0x0641 }, + { 0x05e2, 0x0642 }, + { 0x05e3, 0x0643 }, + { 0x05e4, 0x0644 }, + { 0x05e5, 0x0645 }, + { 0x05e6, 0x0646 }, + { 0x05e7, 0x0647 }, + { 0x05e8, 0x0648 }, + { 0x05e9, 0x0649 }, + { 0x05ea, 0x064a }, + { 0x05eb, 0x064b }, + { 0x05ec, 0x064c }, + { 0x05ed, 0x064d }, + { 0x05ee, 0x064e }, + { 0x05ef, 0x064f }, + { 0x05f0, 0x0650 }, + { 0x05f1, 0x0651 }, + { 0x05f2, 0x0652 }, + { 0x06a1, 0x0452 }, + { 0x06a2, 0x0453 }, + { 0x06a3, 0x0451 }, + { 0x06a4, 0x0454 }, + { 0x06a5, 0x0455 }, + { 0x06a6, 0x0456 }, + { 0x06a7, 0x0457 }, + { 0x06a8, 0x0458 }, + { 0x06a9, 0x0459 }, + { 0x06aa, 0x045a }, + { 0x06ab, 0x045b }, + { 0x06ac, 0x045c }, + { 0x06ae, 0x045e }, + { 0x06af, 0x045f }, + { 0x06b0, 0x2116 }, + { 0x06b1, 0x0402 }, + { 0x06b2, 0x0403 }, + { 0x06b3, 0x0401 }, + { 0x06b4, 0x0404 }, + { 0x06b5, 0x0405 }, + { 0x06b6, 0x0406 }, + { 0x06b7, 0x0407 }, + { 0x06b8, 0x0408 }, + { 0x06b9, 0x0409 }, + { 0x06ba, 0x040a }, + { 0x06bb, 0x040b }, + { 0x06bc, 0x040c }, + { 0x06be, 0x040e }, + { 0x06bf, 0x040f }, + { 0x06c0, 0x044e }, + { 0x06c1, 0x0430 }, + { 0x06c2, 0x0431 }, + { 0x06c3, 0x0446 }, + { 0x06c4, 0x0434 }, + { 0x06c5, 0x0435 }, + { 0x06c6, 0x0444 }, + { 0x06c7, 0x0433 }, + { 0x06c8, 0x0445 }, + { 0x06c9, 0x0438 }, + { 0x06ca, 0x0439 }, + { 0x06cb, 0x043a }, + { 0x06cc, 0x043b }, + { 0x06cd, 0x043c }, + { 0x06ce, 0x043d }, + { 0x06cf, 0x043e }, + { 0x06d0, 0x043f }, + { 0x06d1, 0x044f }, + { 0x06d2, 0x0440 }, + { 0x06d3, 0x0441 }, + { 0x06d4, 0x0442 }, + { 0x06d5, 0x0443 }, + { 0x06d6, 0x0436 }, + { 0x06d7, 0x0432 }, + { 0x06d8, 0x044c }, + { 0x06d9, 0x044b }, + { 0x06da, 0x0437 }, + { 0x06db, 0x0448 }, + { 0x06dc, 0x044d }, + { 0x06dd, 0x0449 }, + { 0x06de, 0x0447 }, + { 0x06df, 0x044a }, + { 0x06e0, 0x042e }, + { 0x06e1, 0x0410 }, + { 0x06e2, 0x0411 }, + { 0x06e3, 0x0426 }, + { 0x06e4, 0x0414 }, + { 0x06e5, 0x0415 }, + { 0x06e6, 0x0424 }, + { 0x06e7, 0x0413 }, + { 0x06e8, 0x0425 }, + { 0x06e9, 0x0418 }, + { 0x06ea, 0x0419 }, + { 0x06eb, 0x041a }, + { 0x06ec, 0x041b }, + { 0x06ed, 0x041c }, + { 0x06ee, 0x041d }, + { 0x06ef, 0x041e }, + { 0x06f0, 0x041f }, + { 0x06f1, 0x042f }, + { 0x06f2, 0x0420 }, + { 0x06f3, 0x0421 }, + { 0x06f4, 0x0422 }, + { 0x06f5, 0x0423 }, + { 0x06f6, 0x0416 }, + { 0x06f7, 0x0412 }, + { 0x06f8, 0x042c }, + { 0x06f9, 0x042b }, + { 0x06fa, 0x0417 }, + { 0x06fb, 0x0428 }, + { 0x06fc, 0x042d }, + { 0x06fd, 0x0429 }, + { 0x06fe, 0x0427 }, + { 0x06ff, 0x042a }, + { 0x07a1, 0x0386 }, + { 0x07a2, 0x0388 }, + { 0x07a3, 0x0389 }, + { 0x07a4, 0x038a }, + { 0x07a5, 0x03aa }, + { 0x07a7, 0x038c }, + { 0x07a8, 0x038e }, + { 0x07a9, 0x03ab }, + { 0x07ab, 0x038f }, + { 0x07ae, 0x0385 }, + { 0x07af, 0x2015 }, + { 0x07b1, 0x03ac }, + { 0x07b2, 0x03ad }, + { 0x07b3, 0x03ae }, + { 0x07b4, 0x03af }, + { 0x07b5, 0x03ca }, + { 0x07b6, 0x0390 }, + { 0x07b7, 0x03cc }, + { 0x07b8, 0x03cd }, + { 0x07b9, 0x03cb }, + { 0x07ba, 0x03b0 }, + { 0x07bb, 0x03ce }, + { 0x07c1, 0x0391 }, + { 0x07c2, 0x0392 }, + { 0x07c3, 0x0393 }, + { 0x07c4, 0x0394 }, + { 0x07c5, 0x0395 }, + { 0x07c6, 0x0396 }, + { 0x07c7, 0x0397 }, + { 0x07c8, 0x0398 }, + { 0x07c9, 0x0399 }, + { 0x07ca, 0x039a }, + { 0x07cb, 0x039b }, + { 0x07cc, 0x039c }, + { 0x07cd, 0x039d }, + { 0x07ce, 0x039e }, + { 0x07cf, 0x039f }, + { 0x07d0, 0x03a0 }, + { 0x07d1, 0x03a1 }, + { 0x07d2, 0x03a3 }, + { 0x07d4, 0x03a4 }, + { 0x07d5, 0x03a5 }, + { 0x07d6, 0x03a6 }, + { 0x07d7, 0x03a7 }, + { 0x07d8, 0x03a8 }, + { 0x07d9, 0x03a9 }, + { 0x07e1, 0x03b1 }, + { 0x07e2, 0x03b2 }, + { 0x07e3, 0x03b3 }, + { 0x07e4, 0x03b4 }, + { 0x07e5, 0x03b5 }, + { 0x07e6, 0x03b6 }, + { 0x07e7, 0x03b7 }, + { 0x07e8, 0x03b8 }, + { 0x07e9, 0x03b9 }, + { 0x07ea, 0x03ba }, + { 0x07eb, 0x03bb }, + { 0x07ec, 0x03bc }, + { 0x07ed, 0x03bd }, + { 0x07ee, 0x03be }, + { 0x07ef, 0x03bf }, + { 0x07f0, 0x03c0 }, + { 0x07f1, 0x03c1 }, + { 0x07f2, 0x03c3 }, + { 0x07f3, 0x03c2 }, + { 0x07f4, 0x03c4 }, + { 0x07f5, 0x03c5 }, + { 0x07f6, 0x03c6 }, + { 0x07f7, 0x03c7 }, + { 0x07f8, 0x03c8 }, + { 0x07f9, 0x03c9 }, + { 0x08a1, 0x23b7 }, + { 0x08a2, 0x250c }, + { 0x08a3, 0x2500 }, + { 0x08a4, 0x2320 }, + { 0x08a5, 0x2321 }, + { 0x08a6, 0x2502 }, + { 0x08a7, 0x23a1 }, + { 0x08a8, 0x23a3 }, + { 0x08a9, 0x23a4 }, + { 0x08aa, 0x23a6 }, + { 0x08ab, 0x239b }, + { 0x08ac, 0x239d }, + { 0x08ad, 0x239e }, + { 0x08ae, 0x23a0 }, + { 0x08af, 0x23a8 }, + { 0x08b0, 0x23ac }, + { 0x08bc, 0x2264 }, + { 0x08bd, 0x2260 }, + { 0x08be, 0x2265 }, + { 0x08bf, 0x222b }, + { 0x08c0, 0x2234 }, + { 0x08c1, 0x221d }, + { 0x08c2, 0x221e }, + { 0x08c5, 0x2207 }, + { 0x08c8, 0x223c }, + { 0x08c9, 0x2243 }, + { 0x08cd, 0x21d4 }, + { 0x08ce, 0x21d2 }, + { 0x08cf, 0x2261 }, + { 0x08d6, 0x221a }, + { 0x08da, 0x2282 }, + { 0x08db, 0x2283 }, + { 0x08dc, 0x2229 }, + { 0x08dd, 0x222a }, + { 0x08de, 0x2227 }, + { 0x08df, 0x2228 }, + { 0x08ef, 0x2202 }, + { 0x08f6, 0x0192 }, + { 0x08fb, 0x2190 }, + { 0x08fc, 0x2191 }, + { 0x08fd, 0x2192 }, + { 0x08fe, 0x2193 }, + { 0x09e0, 0x25c6 }, + { 0x09e1, 0x2592 }, + { 0x09e2, 0x2409 }, + { 0x09e3, 0x240c }, + { 0x09e4, 0x240d }, + { 0x09e5, 0x240a }, + { 0x09e8, 0x2424 }, + { 0x09e9, 0x240b }, + { 0x09ea, 0x2518 }, + { 0x09eb, 0x2510 }, + { 0x09ec, 0x250c }, + { 0x09ed, 0x2514 }, + { 0x09ee, 0x253c }, + { 0x09ef, 0x23ba }, + { 0x09f0, 0x23bb }, + { 0x09f1, 0x2500 }, + { 0x09f2, 0x23bc }, + { 0x09f3, 0x23bd }, + { 0x09f4, 0x251c }, + { 0x09f5, 0x2524 }, + { 0x09f6, 0x2534 }, + { 0x09f7, 0x252c }, + { 0x09f8, 0x2502 }, + { 0x0aa1, 0x2003 }, + { 0x0aa2, 0x2002 }, + { 0x0aa3, 0x2004 }, + { 0x0aa4, 0x2005 }, + { 0x0aa5, 0x2007 }, + { 0x0aa6, 0x2008 }, + { 0x0aa7, 0x2009 }, + { 0x0aa8, 0x200a }, + { 0x0aa9, 0x2014 }, + { 0x0aaa, 0x2013 }, + { 0x0aae, 0x2026 }, + { 0x0aaf, 0x2025 }, + { 0x0ab0, 0x2153 }, + { 0x0ab1, 0x2154 }, + { 0x0ab2, 0x2155 }, + { 0x0ab3, 0x2156 }, + { 0x0ab4, 0x2157 }, + { 0x0ab5, 0x2158 }, + { 0x0ab6, 0x2159 }, + { 0x0ab7, 0x215a }, + { 0x0ab8, 0x2105 }, + { 0x0abb, 0x2012 }, + { 0x0abc, 0x2329 }, + { 0x0abe, 0x232a }, + { 0x0ac3, 0x215b }, + { 0x0ac4, 0x215c }, + { 0x0ac5, 0x215d }, + { 0x0ac6, 0x215e }, + { 0x0ac9, 0x2122 }, + { 0x0aca, 0x2613 }, + { 0x0acc, 0x25c1 }, + { 0x0acd, 0x25b7 }, + { 0x0ace, 0x25cb }, + { 0x0acf, 0x25af }, + { 0x0ad0, 0x2018 }, + { 0x0ad1, 0x2019 }, + { 0x0ad2, 0x201c }, + { 0x0ad3, 0x201d }, + { 0x0ad4, 0x211e }, + { 0x0ad6, 0x2032 }, + { 0x0ad7, 0x2033 }, + { 0x0ad9, 0x271d }, + { 0x0adb, 0x25ac }, + { 0x0adc, 0x25c0 }, + { 0x0add, 0x25b6 }, + { 0x0ade, 0x25cf }, + { 0x0adf, 0x25ae }, + { 0x0ae0, 0x25e6 }, + { 0x0ae1, 0x25ab }, + { 0x0ae2, 0x25ad }, + { 0x0ae3, 0x25b3 }, + { 0x0ae4, 0x25bd }, + { 0x0ae5, 0x2606 }, + { 0x0ae6, 0x2022 }, + { 0x0ae7, 0x25aa }, + { 0x0ae8, 0x25b2 }, + { 0x0ae9, 0x25bc }, + { 0x0aea, 0x261c }, + { 0x0aeb, 0x261e }, + { 0x0aec, 0x2663 }, + { 0x0aed, 0x2666 }, + { 0x0aee, 0x2665 }, + { 0x0af0, 0x2720 }, + { 0x0af1, 0x2020 }, + { 0x0af2, 0x2021 }, + { 0x0af3, 0x2713 }, + { 0x0af4, 0x2717 }, + { 0x0af5, 0x266f }, + { 0x0af6, 0x266d }, + { 0x0af7, 0x2642 }, + { 0x0af8, 0x2640 }, + { 0x0af9, 0x260e }, + { 0x0afa, 0x2315 }, + { 0x0afb, 0x2117 }, + { 0x0afc, 0x2038 }, + { 0x0afd, 0x201a }, + { 0x0afe, 0x201e }, + { 0x0ba3, 0x003c }, + { 0x0ba6, 0x003e }, + { 0x0ba8, 0x2228 }, + { 0x0ba9, 0x2227 }, + { 0x0bc0, 0x00af }, + { 0x0bc2, 0x22a5 }, + { 0x0bc3, 0x2229 }, + { 0x0bc4, 0x230a }, + { 0x0bc6, 0x005f }, + { 0x0bca, 0x2218 }, + { 0x0bcc, 0x2395 }, + { 0x0bce, 0x22a4 }, + { 0x0bcf, 0x25cb }, + { 0x0bd3, 0x2308 }, + { 0x0bd6, 0x222a }, + { 0x0bd8, 0x2283 }, + { 0x0bda, 0x2282 }, + { 0x0bdc, 0x22a2 }, + { 0x0bfc, 0x22a3 }, + { 0x0cdf, 0x2017 }, + { 0x0ce0, 0x05d0 }, + { 0x0ce1, 0x05d1 }, + { 0x0ce2, 0x05d2 }, + { 0x0ce3, 0x05d3 }, + { 0x0ce4, 0x05d4 }, + { 0x0ce5, 0x05d5 }, + { 0x0ce6, 0x05d6 }, + { 0x0ce7, 0x05d7 }, + { 0x0ce8, 0x05d8 }, + { 0x0ce9, 0x05d9 }, + { 0x0cea, 0x05da }, + { 0x0ceb, 0x05db }, + { 0x0cec, 0x05dc }, + { 0x0ced, 0x05dd }, + { 0x0cee, 0x05de }, + { 0x0cef, 0x05df }, + { 0x0cf0, 0x05e0 }, + { 0x0cf1, 0x05e1 }, + { 0x0cf2, 0x05e2 }, + { 0x0cf3, 0x05e3 }, + { 0x0cf4, 0x05e4 }, + { 0x0cf5, 0x05e5 }, + { 0x0cf6, 0x05e6 }, + { 0x0cf7, 0x05e7 }, + { 0x0cf8, 0x05e8 }, + { 0x0cf9, 0x05e9 }, + { 0x0cfa, 0x05ea }, + { 0x0da1, 0x0e01 }, + { 0x0da2, 0x0e02 }, + { 0x0da3, 0x0e03 }, + { 0x0da4, 0x0e04 }, + { 0x0da5, 0x0e05 }, + { 0x0da6, 0x0e06 }, + { 0x0da7, 0x0e07 }, + { 0x0da8, 0x0e08 }, + { 0x0da9, 0x0e09 }, + { 0x0daa, 0x0e0a }, + { 0x0dab, 0x0e0b }, + { 0x0dac, 0x0e0c }, + { 0x0dad, 0x0e0d }, + { 0x0dae, 0x0e0e }, + { 0x0daf, 0x0e0f }, + { 0x0db0, 0x0e10 }, + { 0x0db1, 0x0e11 }, + { 0x0db2, 0x0e12 }, + { 0x0db3, 0x0e13 }, + { 0x0db4, 0x0e14 }, + { 0x0db5, 0x0e15 }, + { 0x0db6, 0x0e16 }, + { 0x0db7, 0x0e17 }, + { 0x0db8, 0x0e18 }, + { 0x0db9, 0x0e19 }, + { 0x0dba, 0x0e1a }, + { 0x0dbb, 0x0e1b }, + { 0x0dbc, 0x0e1c }, + { 0x0dbd, 0x0e1d }, + { 0x0dbe, 0x0e1e }, + { 0x0dbf, 0x0e1f }, + { 0x0dc0, 0x0e20 }, + { 0x0dc1, 0x0e21 }, + { 0x0dc2, 0x0e22 }, + { 0x0dc3, 0x0e23 }, + { 0x0dc4, 0x0e24 }, + { 0x0dc5, 0x0e25 }, + { 0x0dc6, 0x0e26 }, + { 0x0dc7, 0x0e27 }, + { 0x0dc8, 0x0e28 }, + { 0x0dc9, 0x0e29 }, + { 0x0dca, 0x0e2a }, + { 0x0dcb, 0x0e2b }, + { 0x0dcc, 0x0e2c }, + { 0x0dcd, 0x0e2d }, + { 0x0dce, 0x0e2e }, + { 0x0dcf, 0x0e2f }, + { 0x0dd0, 0x0e30 }, + { 0x0dd1, 0x0e31 }, + { 0x0dd2, 0x0e32 }, + { 0x0dd3, 0x0e33 }, + { 0x0dd4, 0x0e34 }, + { 0x0dd5, 0x0e35 }, + { 0x0dd6, 0x0e36 }, + { 0x0dd7, 0x0e37 }, + { 0x0dd8, 0x0e38 }, + { 0x0dd9, 0x0e39 }, + { 0x0dda, 0x0e3a }, + { 0x0ddf, 0x0e3f }, + { 0x0de0, 0x0e40 }, + { 0x0de1, 0x0e41 }, + { 0x0de2, 0x0e42 }, + { 0x0de3, 0x0e43 }, + { 0x0de4, 0x0e44 }, + { 0x0de5, 0x0e45 }, + { 0x0de6, 0x0e46 }, + { 0x0de7, 0x0e47 }, + { 0x0de8, 0x0e48 }, + { 0x0de9, 0x0e49 }, + { 0x0dea, 0x0e4a }, + { 0x0deb, 0x0e4b }, + { 0x0dec, 0x0e4c }, + { 0x0ded, 0x0e4d }, + { 0x0df0, 0x0e50 }, + { 0x0df1, 0x0e51 }, + { 0x0df2, 0x0e52 }, + { 0x0df3, 0x0e53 }, + { 0x0df4, 0x0e54 }, + { 0x0df5, 0x0e55 }, + { 0x0df6, 0x0e56 }, + { 0x0df7, 0x0e57 }, + { 0x0df8, 0x0e58 }, + { 0x0df9, 0x0e59 }, + { 0x0ea1, 0x3131 }, + { 0x0ea2, 0x3132 }, + { 0x0ea3, 0x3133 }, + { 0x0ea4, 0x3134 }, + { 0x0ea5, 0x3135 }, + { 0x0ea6, 0x3136 }, + { 0x0ea7, 0x3137 }, + { 0x0ea8, 0x3138 }, + { 0x0ea9, 0x3139 }, + { 0x0eaa, 0x313a }, + { 0x0eab, 0x313b }, + { 0x0eac, 0x313c }, + { 0x0ead, 0x313d }, + { 0x0eae, 0x313e }, + { 0x0eaf, 0x313f }, + { 0x0eb0, 0x3140 }, + { 0x0eb1, 0x3141 }, + { 0x0eb2, 0x3142 }, + { 0x0eb3, 0x3143 }, + { 0x0eb4, 0x3144 }, + { 0x0eb5, 0x3145 }, + { 0x0eb6, 0x3146 }, + { 0x0eb7, 0x3147 }, + { 0x0eb8, 0x3148 }, + { 0x0eb9, 0x3149 }, + { 0x0eba, 0x314a }, + { 0x0ebb, 0x314b }, + { 0x0ebc, 0x314c }, + { 0x0ebd, 0x314d }, + { 0x0ebe, 0x314e }, + { 0x0ebf, 0x314f }, + { 0x0ec0, 0x3150 }, + { 0x0ec1, 0x3151 }, + { 0x0ec2, 0x3152 }, + { 0x0ec3, 0x3153 }, + { 0x0ec4, 0x3154 }, + { 0x0ec5, 0x3155 }, + { 0x0ec6, 0x3156 }, + { 0x0ec7, 0x3157 }, + { 0x0ec8, 0x3158 }, + { 0x0ec9, 0x3159 }, + { 0x0eca, 0x315a }, + { 0x0ecb, 0x315b }, + { 0x0ecc, 0x315c }, + { 0x0ecd, 0x315d }, + { 0x0ece, 0x315e }, + { 0x0ecf, 0x315f }, + { 0x0ed0, 0x3160 }, + { 0x0ed1, 0x3161 }, + { 0x0ed2, 0x3162 }, + { 0x0ed3, 0x3163 }, + { 0x0ed4, 0x11a8 }, + { 0x0ed5, 0x11a9 }, + { 0x0ed6, 0x11aa }, + { 0x0ed7, 0x11ab }, + { 0x0ed8, 0x11ac }, + { 0x0ed9, 0x11ad }, + { 0x0eda, 0x11ae }, + { 0x0edb, 0x11af }, + { 0x0edc, 0x11b0 }, + { 0x0edd, 0x11b1 }, + { 0x0ede, 0x11b2 }, + { 0x0edf, 0x11b3 }, + { 0x0ee0, 0x11b4 }, + { 0x0ee1, 0x11b5 }, + { 0x0ee2, 0x11b6 }, + { 0x0ee3, 0x11b7 }, + { 0x0ee4, 0x11b8 }, + { 0x0ee5, 0x11b9 }, + { 0x0ee6, 0x11ba }, + { 0x0ee7, 0x11bb }, + { 0x0ee8, 0x11bc }, + { 0x0ee9, 0x11bd }, + { 0x0eea, 0x11be }, + { 0x0eeb, 0x11bf }, + { 0x0eec, 0x11c0 }, + { 0x0eed, 0x11c1 }, + { 0x0eee, 0x11c2 }, + { 0x0eef, 0x316d }, + { 0x0ef0, 0x3171 }, + { 0x0ef1, 0x3178 }, + { 0x0ef2, 0x317f }, + { 0x0ef3, 0x3181 }, + { 0x0ef4, 0x3184 }, + { 0x0ef5, 0x3186 }, + { 0x0ef6, 0x318d }, + { 0x0ef7, 0x318e }, + { 0x0ef8, 0x11eb }, + { 0x0ef9, 0x11f0 }, + { 0x0efa, 0x11f9 }, + { 0x0eff, 0x20a9 }, + { 0x13a4, 0x20ac }, + { 0x13bc, 0x0152 }, + { 0x13bd, 0x0153 }, + { 0x13be, 0x0178 }, + { 0x20ac, 0x20ac }, + { 0xfe50, '`' }, + { 0xfe51, 0x00b4 }, + { 0xfe52, '^' }, + { 0xfe53, '~' }, + { 0xfe54, 0x00af }, + { 0xfe55, 0x02d8 }, + { 0xfe56, 0x02d9 }, + { 0xfe57, 0x00a8 }, + { 0xfe58, 0x02da }, + { 0xfe59, 0x02dd }, + { 0xfe5a, 0x02c7 }, + { 0xfe5b, 0x00b8 }, + { 0xfe5c, 0x02db }, + { 0xfe5d, 0x037a }, + { 0xfe5e, 0x309b }, + { 0xfe5f, 0x309c }, + { 0xfe63, '/' }, + { 0xfe64, 0x02bc }, + { 0xfe65, 0x02bd }, + { 0xfe66, 0x02f5 }, + { 0xfe67, 0x02f3 }, + { 0xfe68, 0x02cd }, + { 0xfe69, 0xa788 }, + { 0xfe6a, 0x02f7 }, + { 0xfe6e, ',' }, + { 0xfe6f, 0x00a4 }, + { 0xfe80, 'a' }, // XK_dead_a + { 0xfe81, 'A' }, // XK_dead_A + { 0xfe82, 'e' }, // XK_dead_e + { 0xfe83, 'E' }, // XK_dead_E + { 0xfe84, 'i' }, // XK_dead_i + { 0xfe85, 'I' }, // XK_dead_I + { 0xfe86, 'o' }, // XK_dead_o + { 0xfe87, 'O' }, // XK_dead_O + { 0xfe88, 'u' }, // XK_dead_u + { 0xfe89, 'U' }, // XK_dead_U + { 0xfe8a, 0x0259 }, + { 0xfe8b, 0x018f }, + { 0xfe8c, 0x00b5 }, + { 0xfe90, '_' }, + { 0xfe91, 0x02c8 }, + { 0xfe92, 0x02cc }, + { 0xff80 /*XKB_KEY_KP_Space*/, ' ' }, + { 0xff95 /*XKB_KEY_KP_7*/, 0x0037 }, + { 0xff96 /*XKB_KEY_KP_4*/, 0x0034 }, + { 0xff97 /*XKB_KEY_KP_8*/, 0x0038 }, + { 0xff98 /*XKB_KEY_KP_6*/, 0x0036 }, + { 0xff99 /*XKB_KEY_KP_2*/, 0x0032 }, + { 0xff9a /*XKB_KEY_KP_9*/, 0x0039 }, + { 0xff9b /*XKB_KEY_KP_3*/, 0x0033 }, + { 0xff9c /*XKB_KEY_KP_1*/, 0x0031 }, + { 0xff9d /*XKB_KEY_KP_5*/, 0x0035 }, + { 0xff9e /*XKB_KEY_KP_0*/, 0x0030 }, + { 0xffaa /*XKB_KEY_KP_Multiply*/, '*' }, + { 0xffab /*XKB_KEY_KP_Add*/, '+' }, + { 0xffac /*XKB_KEY_KP_Separator*/, ',' }, + { 0xffad /*XKB_KEY_KP_Subtract*/, '-' }, + { 0xffae /*XKB_KEY_KP_Decimal*/, '.' }, + { 0xffaf /*XKB_KEY_KP_Divide*/, '/' }, + { 0xffb0 /*XKB_KEY_KP_0*/, 0x0030 }, + { 0xffb1 /*XKB_KEY_KP_1*/, 0x0031 }, + { 0xffb2 /*XKB_KEY_KP_2*/, 0x0032 }, + { 0xffb3 /*XKB_KEY_KP_3*/, 0x0033 }, + { 0xffb4 /*XKB_KEY_KP_4*/, 0x0034 }, + { 0xffb5 /*XKB_KEY_KP_5*/, 0x0035 }, + { 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 }, + { 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 }, + { 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 }, + { 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 }, + { 0xffbd /*XKB_KEY_KP_Equal*/, '=' } +}; + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Convert XKB KeySym to Unicode +// +long _glfwKeySym2Unicode(unsigned int keysym) +{ + int min = 0; + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; + int mid; + + // First check for Latin-1 characters (1:1 mapping) + if ((keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff)) + { + return keysym; + } + + // Also check for directly encoded 24-bit UCS characters + if ((keysym & 0xff000000) == 0x01000000) + return keysym & 0x00ffffff; + + // Binary search in table + while (max >= min) + { + mid = (min + max) / 2; + if (keysymtab[mid].keysym < keysym) + min = mid + 1; + else if (keysymtab[mid].keysym > keysym) + max = mid - 1; + else + return keysymtab[mid].ucs; + } + + // No matching Unicode value found + return -1; +} + diff --git a/src/external/glfw/src/xkb_unicode.h b/src/external/glfw/src/xkb_unicode.h new file mode 100644 index 00000000..f95e14f1 --- /dev/null +++ b/src/external/glfw/src/xkb_unicode.h @@ -0,0 +1,28 @@ +//======================================================================== +// GLFW 3.3 Linux - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +long _glfwKeySym2Unicode(unsigned int keysym); + diff --git a/src/rglfw.c b/src/rglfw.c new file mode 100644 index 00000000..81949a3d --- /dev/null +++ b/src/rglfw.c @@ -0,0 +1,74 @@ +/********************************************************************************************** +* +* raylib GLFW single file compilation +* +* This file includes GLFW sources to be compiled together with raylib for all supported +* platforms, this way, no external dependencies are required. +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2017 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "external/glfw/src/context.c" +#include "external/glfw/src/init.c" +#include "external/glfw/src/input.c" +#include "external/glfw/src/monitor.c" +#include "external/glfw/src/vulkan.c" +#include "external/glfw/src/window.c" + +// Required compilation defines: -D_GLFW_WIN32 +#ifdef _WIN32 +#include "external/glfw/src/win32_init.c" +#include "external/glfw/src/win32_joystick.c" +#include "external/glfw/src/win32_monitor.c" +#include "external/glfw/src/win32_time.c" +#include "external/glfw/src/win32_thread.c" +#include "external/glfw/src/win32_window.c" +#include "external/glfw/src/wgl_context.c" +#include "external/glfw/src/egl_context.c" +#include "external/glfw/src/osmesa_context.c" +#endif + +// Required compilation defines: -D_GLFW_X11 +#ifdef __linux__ +#include "external/glfw/src/x11_init.c" +#include "external/glfw/src/x11_monitor.c" +#include "external/glfw/src/x11_window.c" +#include "external/glfw/src/xkb_unicode.c" +#include "external/glfw/src/linux_joystick.c" +#include "external/glfw/src/posix_time.c" +#include "external/glfw/src/posix_thread.c" +#include "external/glfw/src/glx_context.c" +#include "external/glfw/src/egl_context.c" +#include "external/glfw/src/osmesa_context.c" +#endif + +// Required compilation defines: -D_GLFW_COCOA -D_GLFW_USE_CHDIR -D_GLFW_USE_MENUBAR -D_GLFW_USE_RETINA +#ifdef __APPLE__ +#include "external/glfw/src/cocoa_init.m" +#include "external/glfw/src/cocoa_joystick.m" +#include "external/glfw/src/cocoa_monitor.m" +#include "external/glfw/src/cocoa_window.m" +#include "external/glfw/src/cocoa_time.c" +#include "external/glfw/src/posix_thread.c" +#include "external/glfw/src/nsgl_context.m" +#include "external/glfw/src/egl_context.c" +#include "external/glfw/src/osmesa_context.c.m" +#endif From 3a96a66fdfd2b403be20e4f2b104baf3a25961a1 Mon Sep 17 00:00:00 2001 From: David Reid Date: Mon, 13 Nov 2017 21:46:29 +1000 Subject: [PATCH 010/139] Bring up to date with changes to mini_al. --- src/audio.c | 26 +-- src/external/mini_al.h | 474 ++++++++++++++++++++++++----------------- 2 files changed, 289 insertions(+), 211 deletions(-) diff --git a/src/audio.c b/src/audio.c index 70426532..d29ad1ba 100644 --- a/src/audio.c +++ b/src/audio.c @@ -257,7 +257,7 @@ static AudioStreamData* lastAudioStream; static void AppendSound(SoundData* internalSound) { - mal_mutex_lock(&context, &soundLock); + mal_mutex_lock(&soundLock); { if (firstSound == NULL) { firstSound = internalSound; @@ -268,12 +268,12 @@ static void AppendSound(SoundData* internalSound) lastSound = internalSound; } - mal_mutex_unlock(&context, &soundLock); + mal_mutex_unlock(&soundLock); } static void RemoveSound(SoundData* internalSound) { - mal_mutex_lock(&context, &soundLock); + mal_mutex_lock(&soundLock); { if (internalSound->prev == NULL) { firstSound = internalSound->next; @@ -287,12 +287,12 @@ static void RemoveSound(SoundData* internalSound) internalSound->next->prev = internalSound->prev; } } - mal_mutex_unlock(&context, &soundLock); + mal_mutex_unlock(&soundLock); } static void AppendAudioStream(AudioStreamData* internalAudioStream) { - mal_mutex_lock(&context, &soundLock); + mal_mutex_lock(&soundLock); { if (firstAudioStream == NULL) { firstAudioStream = internalAudioStream; @@ -303,12 +303,12 @@ static void AppendAudioStream(AudioStreamData* internalAudioStream) lastAudioStream = internalAudioStream; } - mal_mutex_unlock(&context, &soundLock); + mal_mutex_unlock(&soundLock); } static void RemoveAudioStream(AudioStreamData* internalAudioStream) { - mal_mutex_lock(&context, &soundLock); + mal_mutex_lock(&soundLock); { if (internalAudioStream->prev == NULL) { firstAudioStream = internalAudioStream->next; @@ -322,7 +322,7 @@ static void RemoveAudioStream(AudioStreamData* internalAudioStream) internalAudioStream->next->prev = internalAudioStream->prev; } } - mal_mutex_unlock(&context, &soundLock); + mal_mutex_unlock(&soundLock); } @@ -343,7 +343,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC // Using a mutex here for thread-safety which makes things not real-time. This is unlikely to be necessary for this project, but may // want to consider how you might want to avoid this. - mal_mutex_lock(&context, &soundLock); + mal_mutex_lock(&soundLock); { float* pFramesOutF = (float*)pFramesOut; // <-- Just for convenience. @@ -454,7 +454,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC } } } - mal_mutex_unlock(&context, &soundLock); + mal_mutex_unlock(&soundLock); return frameCount; // We always output the same number of frames that were originally requested. } @@ -493,7 +493,7 @@ void InitAudioDevice(void) // Mixing happens on a seperate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may // want to look at something a bit smarter later on to keep everything real-time, if that's necessary. - if (!mal_mutex_create(&context, &soundLock)) + if (mal_mutex_init(&context, &soundLock) != MAL_SUCCESS) { TraceLog(LOG_ERROR, "Failed to create mutex for audio mixing"); mal_device_uninit(&device); @@ -550,7 +550,7 @@ void CloseAudioDevice(void) return; } - mal_mutex_delete(&context, &soundLock); + mal_mutex_uninit(&soundLock); mal_device_uninit(&device); mal_context_uninit(&context); #else @@ -1573,7 +1573,7 @@ float GetMusicTimePlayed(Music music) } -static mal_uint32 UpdateAudioStream_OnDSPRead(mal_uint32 frameCount, void* pFramesOut, void* pUserData) +static mal_uint32 UpdateAudioStream_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) { AudioStreamData* internalData = (AudioStreamData*)pUserData; diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 49347e42..abb52295 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -292,20 +292,79 @@ typedef void* mal_handle; typedef void* mal_ptr; typedef void (* mal_proc)(); -#ifdef MAL_WIN32 - typedef mal_handle mal_thread; - typedef mal_handle mal_mutex; - typedef mal_handle mal_event; -#else - typedef pthread_t mal_thread; - typedef pthread_mutex_t mal_mutex; - typedef struct +typedef struct mal_context mal_context; +typedef struct mal_device mal_device; + +typedef struct +{ + mal_context* pContext; + + union { - pthread_mutex_t mutex; - pthread_cond_t condition; - mal_uint32 value; - } mal_event; +#ifdef MAL_WIN32 + struct + { + /*HANDLE*/ mal_handle hThread; + } win32; #endif +#ifdef MAL_POSIX + struct + { + pthread_t thread; + } posix; +#endif + + int _unused; + }; +} mal_thread; + +typedef struct +{ + mal_context* pContext; + + union + { +#ifdef MAL_WIN32 + struct + { + /*HANDLE*/ mal_handle hMutex; + } win32; +#endif +#ifdef MAL_POSIX + struct + { + pthread_mutex_t mutex; + } posix; +#endif + + int _unused; + }; +} mal_mutex; + +typedef struct +{ + mal_context* pContext; + + union + { +#ifdef MAL_WIN32 + struct + { + /*HANDLE*/ mal_handle hEvent; + } win32; +#endif +#ifdef MAL_POSIX + struct + { + pthread_mutex_t mutex; + pthread_cond_t condition; + mal_uint32 value; + } posix; +#endif + + int _unused; + }; +} mal_event; #if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) typedef mal_uint16 wchar_t; @@ -393,9 +452,6 @@ typedef int mal_result; #define MAL_WINMM_FAILED_TO_GET_DEVICE_CAPS -4096 #define MAL_WINMM_FAILED_TO_GET_SUPPORTED_FORMATS -4097 -typedef struct mal_context mal_context; -typedef struct mal_device mal_device; - typedef void (* mal_log_proc) (mal_context* pContext, mal_device* pDevice, const char* message); typedef void (* mal_recv_proc)(mal_device* pDevice, mal_uint32 frameCount, const void* pSamples); typedef mal_uint32 (* mal_send_proc)(mal_device* pDevice, mal_uint32 frameCount, void* pSamples); @@ -481,7 +537,7 @@ typedef struct typedef struct mal_src mal_src; -typedef mal_uint32 (* mal_src_read_proc)(mal_uint32 frameCount, void* pFramesOut, void* pUserData); // Returns the number of frames that were read. +typedef mal_uint32 (* mal_src_read_proc)(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, void* pUserData); // Returns the number of frames that were read. typedef enum { @@ -530,7 +586,7 @@ struct mal_src }; typedef struct mal_dsp mal_dsp; -typedef mal_uint32 (* mal_dsp_read_proc)(mal_uint32 frameCount, void* pSamplesOut, void* pUserData); +typedef mal_uint32 (* mal_dsp_read_proc)(mal_dsp* pDSP, mal_uint32 frameCount, void* pSamplesOut, void* pUserData); typedef struct { @@ -1032,7 +1088,6 @@ mal_result mal_context_uninit(mal_context* pContext); // application ensures mutal exclusion to the output buffer at their level. // // Efficiency: LOW -// This API dynamically links to backend DLLs/SOs (such as dsound.dll). mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo); // Initializes a device. @@ -1332,10 +1387,19 @@ mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 chann // /////////////////////////////////////////////////////////////////////////////// -mal_bool32 mal_mutex_create(mal_context* pContext, mal_mutex* pMutex); -void mal_mutex_delete(mal_context* pContext, mal_mutex* pMutex); -void mal_mutex_lock(mal_context* pContext, mal_mutex* pMutex); -void mal_mutex_unlock(mal_context* pContext, mal_mutex* pMutex); +// Creates a mutex. +// +// A mutex must be created from a valid context. A mutex is initially unlocked. +mal_result mal_mutex_init(mal_context* pContext, mal_mutex* pMutex); + +// Deletes a mutex. +void mal_mutex_uninit(mal_mutex* pMutex); + +// Locks a mutex with an infinite timeout. +void mal_mutex_lock(mal_mutex* pMutex); + +// Unlocks a mutex. +void mal_mutex_unlock(mal_mutex* pMutex); @@ -1913,23 +1977,21 @@ mal_proc mal_dlsym(mal_handle handle, const char* symbol) // /////////////////////////////////////////////////////////////////////////////// #ifdef MAL_WIN32 -mal_bool32 mal_thread_create__win32(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) +mal_result mal_thread_create__win32(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) { (void)pContext; - *pThread = CreateThread(NULL, 0, entryProc, pData, 0, NULL); - if (*pThread == NULL) { - return MAL_FALSE; + pThread->win32.hThread = CreateThread(NULL, 0, entryProc, pData, 0, NULL); + if (pThread->win32.hThread == NULL) { + return MAL_FAILED_TO_CREATE_THREAD; } - return MAL_TRUE; + return MAL_SUCCESS; } -void mal_thread_wait__win32(mal_context* pContext, mal_thread* pThread) +void mal_thread_wait__win32(mal_thread* pThread) { - (void)pContext; - - WaitForSingleObject(*pThread, INFINITE); + WaitForSingleObject(pThread->win32.hThread, INFINITE); } void mal_sleep__win32(mal_uint32 milliseconds) @@ -1938,71 +2000,59 @@ void mal_sleep__win32(mal_uint32 milliseconds) } -mal_bool32 mal_mutex_create__win32(mal_context* pContext, mal_mutex* pMutex) +mal_result mal_mutex_init__win32(mal_context* pContext, mal_mutex* pMutex) { (void)pContext; - *pMutex = CreateEventA(NULL, FALSE, TRUE, NULL); - if (*pMutex == NULL) { - return MAL_FALSE; + pMutex->win32.hMutex = CreateEventA(NULL, FALSE, TRUE, NULL); + if (pMutex->win32.hMutex == NULL) { + return MAL_FAILED_TO_CREATE_MUTEX; } - return MAL_TRUE; + return MAL_SUCCESS; } -void mal_mutex_delete__win32(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_uninit__win32(mal_mutex* pMutex) { - (void)pContext; - - CloseHandle(*pMutex); + CloseHandle(pMutex->win32.hMutex); } -void mal_mutex_lock__win32(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_lock__win32(mal_mutex* pMutex) { - (void)pContext; - - WaitForSingleObject(*pMutex, INFINITE); + WaitForSingleObject(pMutex->win32.hMutex, INFINITE); } -void mal_mutex_unlock__win32(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_unlock__win32(mal_mutex* pMutex) { - (void)pContext; - - SetEvent(*pMutex); + SetEvent(pMutex->win32.hMutex); } -mal_bool32 mal_event_create__win32(mal_context* pContext, mal_event* pEvent) +mal_result mal_event_init__win32(mal_context* pContext, mal_event* pEvent) { (void)pContext; - *pEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - if (*pEvent == NULL) { - return MAL_FALSE; + pEvent->win32.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if (pEvent->win32.hEvent == NULL) { + return MAL_FAILED_TO_CREATE_EVENT; } - return MAL_TRUE; + return MAL_SUCCESS; } -void mal_event_delete__win32(mal_context* pContext, mal_event* pEvent) +void mal_event_uninit__win32(mal_event* pEvent) { - (void)pContext; - - CloseHandle(*pEvent); + CloseHandle(pEvent->win32.hEvent); } -mal_bool32 mal_event_wait__win32(mal_context* pContext, mal_event* pEvent) +mal_bool32 mal_event_wait__win32(mal_event* pEvent) { - (void)pContext; - - return WaitForSingleObject(*pEvent, INFINITE) == WAIT_OBJECT_0; + return WaitForSingleObject(pEvent->win32.hEvent, INFINITE) == WAIT_OBJECT_0; } -mal_bool32 mal_event_signal__win32(mal_context* pContext, mal_event* pEvent) +mal_bool32 mal_event_signal__win32(mal_event* pEvent) { - (void)pContext; - - return SetEvent(*pEvent); + return SetEvent(pEvent->win32.hEvent); } #endif @@ -2021,12 +2071,17 @@ typedef int (* mal_pthread_cond_wait_proc)(pthread_cond_t *__restrict __cond, pt mal_bool32 mal_thread_create__posix(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) { - return ((mal_pthread_create_proc)pContext->posix.pthread_create)(pThread, NULL, entryProc, pData) == 0; + int result = ((mal_pthread_create_proc)pContext->posix.pthread_create)(&pThread->posix.thread, NULL, entryProc, pData); + if (result != 0) { + return MAL_FAILED_TO_CREATE_THREAD; + } + + return MAL_SUCCESS; } -void mal_thread_wait__posix(mal_context* pContext, mal_thread* pThread) +void mal_thread_wait__posix(mal_thread* pThread) { - ((mal_pthread_join_proc)pContext->posix.pthread_join)(*pThread, NULL); + ((mal_pthread_join_proc)pThread->pContext->posix.pthread_join)(pThread->posix.thread, NULL); } void mal_sleep__posix(mal_uint32 milliseconds) @@ -2035,78 +2090,85 @@ void mal_sleep__posix(mal_uint32 milliseconds) } -mal_bool32 mal_mutex_create__posix(mal_context* pContext, mal_mutex* pMutex) +mal_result mal_mutex_init__posix(mal_context* pContext, mal_mutex* pMutex) { - return ((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(pMutex, NULL) == 0; -} - -void mal_mutex_delete__posix(mal_context* pContext, mal_mutex* pMutex) -{ - ((mal_pthread_mutex_destroy_proc)pContext->posix.pthread_mutex_destroy)(pMutex); -} - -void mal_mutex_lock__posix(mal_context* pContext, mal_mutex* pMutex) -{ - ((mal_pthread_mutex_lock_proc)pContext->posix.pthread_mutex_lock)(pMutex); -} - -void mal_mutex_unlock__posix(mal_context* pContext, mal_mutex* pMutex) -{ - ((mal_pthread_mutex_unlock_proc)pContext->posix.pthread_mutex_unlock)(pMutex); -} - - -mal_bool32 mal_event_create__posix(mal_context* pContext, mal_event* pEvent) -{ - if (((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pEvent->mutex, NULL) != 0) { - return MAL_FALSE; + int result = ((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pMutex->posix.mutex, NULL); + if (result != 0) { + return MAL_FAILED_TO_CREATE_MUTEX; } - if (((mal_pthread_cond_init_proc)pContext->posix.pthread_cond_init)(&pEvent->condition, NULL) != 0) { - return MAL_FALSE; + return MAL_SUCCESS; +} + +void mal_mutex_uninit__posix(mal_mutex* pMutex) +{ + ((mal_pthread_mutex_destroy_proc)pMutex->pContext->posix.pthread_mutex_destroy)(&pMutex->posix.mutex); +} + +void mal_mutex_lock__posix(mal_mutex* pMutex) +{ + ((mal_pthread_mutex_lock_proc)pMutex->pContext->posix.pthread_mutex_lock)(&pMutex->posix.mutex); +} + +void mal_mutex_unlock__posix(mal_mutex* pMutex) +{ + ((mal_pthread_mutex_unlock_proc)pMutex->pContext->posix.pthread_mutex_unlock)(&pMutex->posix.mutex); +} + + +mal_result mal_event_init__posix(mal_context* pContext, mal_event* pEvent) +{ + if (((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pEvent->posix.mutex, NULL) != 0) { + return MAL_FAILED_TO_CREATE_MUTEX; } - pEvent->value = 0; - return MAL_TRUE; + if (((mal_pthread_cond_init_proc)pContext->posix.pthread_cond_init)(&pEvent->posix.condition, NULL) != 0) { + return MAL_FAILED_TO_CREATE_EVENT; + } + + pEvent->posix.value = 0; + return MAL_SUCCESS; } -void mal_event_delete__posix(mal_context* pContext, mal_event* pEvent) +void mal_event_uninit__posix(mal_event* pEvent) { - ((mal_pthread_cond_destroy_proc)pContext->posix.pthread_cond_destroy)(&pEvent->condition); - ((mal_pthread_mutex_destroy_proc)pContext->posix.pthread_mutex_destroy)(&pEvent->mutex); + ((mal_pthread_cond_destroy_proc)pEvent->pContext->posix.pthread_cond_destroy)(&pEvent->posix.condition); + ((mal_pthread_mutex_destroy_proc)pEvent->pContext->posix.pthread_mutex_destroy)(&pEvent->posix.mutex); } -mal_bool32 mal_event_wait__posix(mal_context* pContext, mal_event* pEvent) +mal_bool32 mal_event_wait__posix(mal_event* pEvent) { - ((mal_pthread_mutex_lock_proc)pContext->posix.pthread_mutex_lock)(&pEvent->mutex); + ((mal_pthread_mutex_lock_proc)pEvent->pContext->posix.pthread_mutex_lock)(&pEvent->posix.mutex); { - while (pEvent->value == 0) { - ((mal_pthread_cond_wait_proc)pContext->posix.pthread_cond_wait)(&pEvent->condition, &pEvent->mutex); + while (pEvent->posix.value == 0) { + ((mal_pthread_cond_wait_proc)pEvent->pContext->posix.pthread_cond_wait)(&pEvent->posix.condition, &pEvent->posix.mutex); } - pEvent->value = 0; // Auto-reset. + pEvent->posix.value = 0; // Auto-reset. } - ((mal_pthread_mutex_unlock_proc)pContext->posix.pthread_mutex_unlock)(&pEvent->mutex); + ((mal_pthread_mutex_unlock_proc)pEvent->pContext->posix.pthread_mutex_unlock)(&pEvent->posix.mutex); return MAL_TRUE; } -mal_bool32 mal_event_signal__posix(mal_context* pContext, mal_event* pEvent) +mal_bool32 mal_event_signal__posix(mal_event* pEvent) { - ((mal_pthread_mutex_lock_proc)pContext->posix.pthread_mutex_lock)(&pEvent->mutex); + ((mal_pthread_mutex_lock_proc)pEvent->pContext->posix.pthread_mutex_lock)(&pEvent->posix.mutex); { - pEvent->value = 1; - ((mal_pthread_cond_signal_proc)pContext->posix.pthread_cond_signal)(&pEvent->condition); + pEvent->posix.value = 1; + ((mal_pthread_cond_signal_proc)pEvent->pContext->posix.pthread_cond_signal)(&pEvent->posix.condition); } - ((mal_pthread_mutex_unlock_proc)pContext->posix.pthread_mutex_unlock)(&pEvent->mutex); + ((mal_pthread_mutex_unlock_proc)pEvent->pContext->posix.pthread_mutex_unlock)(&pEvent->posix.mutex); return MAL_TRUE; } #endif -mal_bool32 mal_thread_create(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) +mal_result mal_thread_create(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) { - if (pThread == NULL || entryProc == NULL) return MAL_FALSE; + if (pContext == NULL || pThread == NULL || entryProc == NULL) return MAL_FALSE; + + pThread->pContext = pContext; #ifdef MAL_WIN32 return mal_thread_create__win32(pContext, pThread, entryProc, pData); @@ -2116,15 +2178,15 @@ mal_bool32 mal_thread_create(mal_context* pContext, mal_thread* pThread, mal_thr #endif } -void mal_thread_wait(mal_context* pContext, mal_thread* pThread) +void mal_thread_wait(mal_thread* pThread) { if (pThread == NULL) return; #ifdef MAL_WIN32 - mal_thread_wait__win32(pContext, pThread); + mal_thread_wait__win32(pThread); #endif #ifdef MAL_POSIX - mal_thread_wait__posix(pContext, pThread); + mal_thread_wait__posix(pThread); #endif } @@ -2139,100 +2201,104 @@ void mal_sleep(mal_uint32 milliseconds) } -mal_bool32 mal_mutex_create(mal_context* pContext, mal_mutex* pMutex) +mal_result mal_mutex_init(mal_context* pContext, mal_mutex* pMutex) { - if (pMutex == NULL) return MAL_FALSE; + if (pContext == NULL || pMutex == NULL) return MAL_INVALID_ARGS; + + pMutex->pContext = pContext; #ifdef MAL_WIN32 - return mal_mutex_create__win32(pContext, pMutex); + return mal_mutex_init__win32(pContext, pMutex); #endif #ifdef MAL_POSIX - return mal_mutex_create__posix(pContext, pMutex); + return mal_mutex_init__posix(pContext, pMutex); #endif } -void mal_mutex_delete(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_uninit(mal_mutex* pMutex) { - if (pMutex == NULL) return; + if (pMutex == NULL || pMutex->pContext == NULL) return; #ifdef MAL_WIN32 - mal_mutex_delete__win32(pContext, pMutex); + mal_mutex_uninit__win32(pMutex); #endif #ifdef MAL_POSIX - mal_mutex_delete__posix(pContext, pMutex); + mal_mutex_uninit__posix(pMutex); #endif } -void mal_mutex_lock(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_lock(mal_mutex* pMutex) { - if (pMutex == NULL) return; + if (pMutex == NULL || pMutex->pContext == NULL) return; #ifdef MAL_WIN32 - mal_mutex_lock__win32(pContext, pMutex); + mal_mutex_lock__win32(pMutex); #endif #ifdef MAL_POSIX - mal_mutex_lock__posix(pContext, pMutex); + mal_mutex_lock__posix(pMutex); #endif } -void mal_mutex_unlock(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_unlock(mal_mutex* pMutex) { - if (pMutex == NULL) return; + if (pMutex == NULL || pMutex->pContext == NULL) return; #ifdef MAL_WIN32 - mal_mutex_unlock__win32(pContext, pMutex); + mal_mutex_unlock__win32(pMutex); #endif #ifdef MAL_POSIX - mal_mutex_unlock__posix(pContext, pMutex); + mal_mutex_unlock__posix(pMutex); #endif } -mal_bool32 mal_event_create(mal_context* pContext, mal_event* pEvent) +mal_result mal_event_init(mal_context* pContext, mal_event* pEvent) { - if (pEvent == NULL) return MAL_FALSE; + if (pContext == NULL || pEvent == NULL) return MAL_FALSE; + + pEvent->pContext = pContext; #ifdef MAL_WIN32 - return mal_event_create__win32(pContext, pEvent); + return mal_event_init__win32(pContext, pEvent); #endif #ifdef MAL_POSIX - return mal_event_create__posix(pContext, pEvent); + return mal_event_init__posix(pContext, pEvent); #endif } -void mal_event_delete(mal_context* pContext, mal_event* pEvent) +void mal_event_uninit(mal_event* pEvent) { - if (pEvent == NULL) return; + if (pEvent == NULL || pEvent->pContext == NULL) return; #ifdef MAL_WIN32 - mal_event_delete__win32(pContext, pEvent); + mal_event_uninit__win32(pEvent); #endif #ifdef MAL_POSIX - mal_event_delete__posix(pContext, pEvent); + mal_event_uninit__posix(pEvent); #endif } -mal_bool32 mal_event_wait(mal_context* pContext, mal_event* pEvent) +mal_bool32 mal_event_wait(mal_event* pEvent) { - if (pEvent == NULL) return MAL_FALSE; + if (pEvent == NULL || pEvent->pContext == NULL) return MAL_FALSE; #ifdef MAL_WIN32 - return mal_event_wait__win32(pContext, pEvent); + return mal_event_wait__win32(pEvent); #endif #ifdef MAL_POSIX - return mal_event_wait__posix(pContext, pEvent); + return mal_event_wait__posix(pEvent); #endif } -mal_bool32 mal_event_signal(mal_context* pContext, mal_event* pEvent) +mal_bool32 mal_event_signal(mal_event* pEvent) { - if (pEvent == NULL) return MAL_FALSE; + if (pEvent == NULL || pEvent->pContext == NULL) return MAL_FALSE; #ifdef MAL_WIN32 - return mal_event_signal__win32(pContext, pEvent); + return mal_event_signal__win32(pEvent); #endif #ifdef MAL_POSIX - return mal_event_signal__posix(pContext, pEvent); + return mal_event_signal__posix(pEvent); #endif } @@ -2340,8 +2406,10 @@ static void mal_get_default_channel_mapping(mal_backend backend, mal_uint32 chan // The callback for reading from the client -> DSP -> device. -static inline mal_uint32 mal_device__on_read_from_client(mal_uint32 frameCount, void* pFramesOut, void* pUserData) +static inline mal_uint32 mal_device__on_read_from_client(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) { + (void)pDSP; + mal_device* pDevice = (mal_device*)pUserData; mal_assert(pDevice != NULL); @@ -2354,8 +2422,10 @@ static inline mal_uint32 mal_device__on_read_from_client(mal_uint32 frameCount, } // The callback for reading from the device -> DSP -> client. -static inline mal_uint32 mal_device__on_read_from_device(mal_uint32 frameCount, void* pFramesOut, void* pUserData) +static inline mal_uint32 mal_device__on_read_from_device(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) { + (void)pDSP; + mal_device* pDevice = (mal_device*)pUserData; mal_assert(pDevice != NULL); @@ -2705,7 +2775,7 @@ static mal_result mal_device__main_loop__null(mal_device* pDevice) // The SDK that comes with old versions of MSVC (VC6, for example) does not appear to define WAVEFORMATEXTENSIBLE. We // define our own implementation in this case. -#ifndef _WAVEFORMATEXTENSIBLE_ +#if defined(_MSC_VER) && !defined(_WAVEFORMATEXTENSIBLE_) typedef struct { WAVEFORMATEX Format; @@ -7452,7 +7522,7 @@ mal_result mal_context_init__openal(mal_context* pContext) libName = "libopenal.so"; #endif #ifdef MAL_APPLE - // I don't own a Mac so a contribution here would be much appreciated! Just don't know what the library is called... + libName = "OpenAL.framework/OpenAL"; #endif if (libName == NULL) { return MAL_NO_BACKEND; // Don't know what the library name is called. @@ -8230,10 +8300,10 @@ mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData) // Let the other threads know that the device has stopped. mal_device__set_state(pDevice, MAL_STATE_STOPPED); - mal_event_signal(pDevice->pContext, &pDevice->stopEvent); + mal_event_signal(&pDevice->stopEvent); // We use an event to wait for a request to wake up. - mal_event_wait(pDevice->pContext, &pDevice->wakeupEvent); + mal_event_wait(&pDevice->wakeupEvent); // Default result code. pDevice->workResult = MAL_SUCCESS; @@ -8250,21 +8320,21 @@ mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData) pDevice->workResult = mal_device__start_backend(pDevice); if (pDevice->workResult != MAL_SUCCESS) { - mal_event_signal(pDevice->pContext, &pDevice->startEvent); + mal_event_signal(&pDevice->startEvent); continue; } // The thread that requested the device to start playing is waiting for this thread to start the // device for real, which is now. mal_device__set_state(pDevice, MAL_STATE_STARTED); - mal_event_signal(pDevice->pContext, &pDevice->startEvent); + mal_event_signal(&pDevice->startEvent); // Now we just enter the main loop. The main loop can be broken with mal_device__break_main_loop(). mal_device__main_loop(pDevice); } // Make sure we aren't continuously waiting on a stop event. - mal_event_signal(pDevice->pContext, &pDevice->stopEvent); // <-- Is this still needed? + mal_event_signal(&pDevice->stopEvent); // <-- Is this still needed? #ifdef MAL_WIN32 mal_CoUninitialize(pDevice->pContext); @@ -8334,7 +8404,8 @@ mal_result mal_context_init_backend_apis__nix(mal_context* pContext) // pthread const char* libpthreadFileNames[] = { "libpthread.so", - "libpthread.so.0" + "libpthread.so.0", + "libpthread.dylib" }; for (size_t i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) { @@ -8691,7 +8762,7 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi pDevice->internalSampleRate = pDevice->sampleRate; mal_copy_memory(pDevice->internalChannelMap, pDevice->channelMap, sizeof(pDevice->channelMap)); - if (!mal_mutex_create(pContext, &pDevice->lock)) { + if (mal_mutex_init(pContext, &pDevice->lock) != MAL_SUCCESS) { return mal_post_error(pDevice, "Failed to create mutex.", MAL_FAILED_TO_CREATE_MUTEX); } @@ -8700,19 +8771,19 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi // // Each of these semaphores is released internally by the worker thread when the work is completed. The start // semaphore is also used to wake up the worker thread. - if (!mal_event_create(pContext, &pDevice->wakeupEvent)) { - mal_mutex_delete(pContext, &pDevice->lock); + if (mal_event_init(pContext, &pDevice->wakeupEvent) != MAL_SUCCESS) { + mal_mutex_uninit(&pDevice->lock); return mal_post_error(pDevice, "Failed to create worker thread wakeup event.", MAL_FAILED_TO_CREATE_EVENT); } - if (!mal_event_create(pContext, &pDevice->startEvent)) { - mal_event_delete(pContext, &pDevice->wakeupEvent); - mal_mutex_delete(pContext, &pDevice->lock); + if (mal_event_init(pContext, &pDevice->startEvent) != MAL_SUCCESS) { + mal_event_uninit(&pDevice->wakeupEvent); + mal_mutex_uninit(&pDevice->lock); return mal_post_error(pDevice, "Failed to create worker thread start event.", MAL_FAILED_TO_CREATE_EVENT); } - if (!mal_event_create(pContext, &pDevice->stopEvent)) { - mal_event_delete(pContext, &pDevice->startEvent); - mal_event_delete(pContext, &pDevice->wakeupEvent); - mal_mutex_delete(pContext, &pDevice->lock); + if (mal_event_init(pContext, &pDevice->stopEvent) != MAL_SUCCESS) { + mal_event_uninit(&pDevice->startEvent); + mal_event_uninit(&pDevice->wakeupEvent); + mal_mutex_uninit(&pDevice->lock); return mal_post_error(pDevice, "Failed to create worker thread stop event.", MAL_FAILED_TO_CREATE_EVENT); } @@ -8809,13 +8880,13 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi // Some backends don't require the worker thread. if (pContext->backend != mal_backend_opensl) { // The worker thread. - if (!mal_thread_create(pContext, &pDevice->thread, mal_worker_thread, pDevice)) { + if (mal_thread_create(pContext, &pDevice->thread, mal_worker_thread, pDevice) != MAL_SUCCESS) { mal_device_uninit(pDevice); return mal_post_error(pDevice, "Failed to create worker thread.", MAL_FAILED_TO_CREATE_THREAD); } // Wait for the worker thread to put the device into it's stopped state for real. - mal_event_wait(pContext, &pDevice->stopEvent); + mal_event_wait(&pDevice->stopEvent); } else { mal_device__set_state(pDevice, MAL_STATE_STOPPED); } @@ -8841,14 +8912,14 @@ void mal_device_uninit(mal_device* pDevice) // Wake up the worker thread and wait for it to properly terminate. if (pDevice->pContext->backend != mal_backend_opensl) { - mal_event_signal(pDevice->pContext, &pDevice->wakeupEvent); - mal_thread_wait(pDevice->pContext, &pDevice->thread); + mal_event_signal(&pDevice->wakeupEvent); + mal_thread_wait(&pDevice->thread); } - mal_event_delete(pDevice->pContext, &pDevice->stopEvent); - mal_event_delete(pDevice->pContext, &pDevice->startEvent); - mal_event_delete(pDevice->pContext, &pDevice->wakeupEvent); - mal_mutex_delete(pDevice->pContext, &pDevice->lock); + mal_event_uninit(&pDevice->stopEvent); + mal_event_uninit(&pDevice->startEvent); + mal_event_uninit(&pDevice->wakeupEvent); + mal_mutex_uninit(&pDevice->lock); #ifdef MAL_ENABLE_WASAPI if (pDevice->pContext->backend == mal_backend_wasapi) { @@ -8918,22 +8989,22 @@ mal_result mal_device_start(mal_device* pDevice) if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) return mal_post_error(pDevice, "mal_device_start() called for an uninitialized device.", MAL_DEVICE_NOT_INITIALIZED); mal_result result = MAL_ERROR; - mal_mutex_lock(pDevice->pContext, &pDevice->lock); + mal_mutex_lock(&pDevice->lock); { // Be a bit more descriptive if the device is already started or is already in the process of starting. This is likely // a bug with the application. if (mal_device__get_state(pDevice) == MAL_STATE_STARTING) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_start() called while another thread is already starting it.", MAL_DEVICE_ALREADY_STARTING); } if (mal_device__get_state(pDevice) == MAL_STATE_STARTED) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_start() called for a device that's already started.", MAL_DEVICE_ALREADY_STARTED); } // The device needs to be in a stopped state. If it's not, we just let the caller know the device is busy. if (mal_device__get_state(pDevice) != MAL_STATE_STOPPED) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_start() called while another thread is in the process of stopping it.", MAL_DEVICE_BUSY); } @@ -8948,15 +9019,15 @@ mal_result mal_device_start(mal_device* pDevice) #endif // Synchronous backends. { - mal_event_signal(pDevice->pContext, &pDevice->wakeupEvent); + mal_event_signal(&pDevice->wakeupEvent); // Wait for the worker thread to finish starting the device. Note that the worker thread will be the one // who puts the device into the started state. Don't call mal_device__set_state() here. - mal_event_wait(pDevice->pContext, &pDevice->startEvent); + mal_event_wait(&pDevice->startEvent); result = pDevice->workResult; } } - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return result; } @@ -8967,22 +9038,22 @@ mal_result mal_device_stop(mal_device* pDevice) if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) return mal_post_error(pDevice, "mal_device_stop() called for an uninitialized device.", MAL_DEVICE_NOT_INITIALIZED); mal_result result = MAL_ERROR; - mal_mutex_lock(pDevice->pContext, &pDevice->lock); + mal_mutex_lock(&pDevice->lock); { // Be a bit more descriptive if the device is already stopped or is already in the process of stopping. This is likely // a bug with the application. if (mal_device__get_state(pDevice) == MAL_STATE_STOPPING) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_stop() called while another thread is already stopping it.", MAL_DEVICE_ALREADY_STOPPING); } if (mal_device__get_state(pDevice) == MAL_STATE_STOPPED) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_stop() called for a device that's already stopped.", MAL_DEVICE_ALREADY_STOPPED); } // The device needs to be in a started state. If it's not, we just let the caller know the device is busy. if (mal_device__get_state(pDevice) != MAL_STATE_STARTED) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_stop() called while another thread is in the process of starting it.", MAL_DEVICE_BUSY); } @@ -9004,11 +9075,11 @@ mal_result mal_device_stop(mal_device* pDevice) // We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be // the one who puts the device into the stopped state. Don't call mal_device__set_state() here. - mal_event_wait(pDevice->pContext, &pDevice->stopEvent); + mal_event_wait(&pDevice->stopEvent); result = MAL_SUCCESS; } } - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return result; } @@ -9186,7 +9257,7 @@ mal_uint32 mal_src_cache_read_frames(mal_src_cache* pCache, mal_uint32 frameCoun framesToReadFromClient = pCache->pSRC->config.cacheSizeInFrames; } - pCache->cachedFrameCount = pCache->pSRC->onRead(framesToReadFromClient, pCache->pCachedFrames, pCache->pSRC->pUserData); + pCache->cachedFrameCount = pCache->pSRC->onRead(pCache->pSRC, framesToReadFromClient, pCache->pCachedFrames, pCache->pSRC->pUserData); } else { // A format conversion is required which means we need to use an intermediary buffer. mal_uint8 pIntermediaryBuffer[sizeof(pCache->pCachedFrames)]; @@ -9195,7 +9266,7 @@ mal_uint32 mal_src_cache_read_frames(mal_src_cache* pCache, mal_uint32 frameCoun framesToReadFromClient = pCache->pSRC->config.cacheSizeInFrames; } - pCache->cachedFrameCount = pCache->pSRC->onRead(framesToReadFromClient, pIntermediaryBuffer, pCache->pSRC->pUserData); + pCache->cachedFrameCount = pCache->pSRC->onRead(pCache->pSRC, framesToReadFromClient, pIntermediaryBuffer, pCache->pSRC->pUserData); // Convert to f32. mal_pcm_convert(pCache->pCachedFrames, mal_format_f32, pIntermediaryBuffer, pCache->pSRC->config.formatIn, pCache->cachedFrameCount * channels); @@ -9263,7 +9334,7 @@ mal_uint32 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint32 frameCount, // Fast path. No need for data conversion - just pass right through. if (pSRC->config.formatIn == pSRC->config.formatOut) { - return pSRC->onRead(frameCount, pFramesOut, pSRC->pUserData); + return pSRC->onRead(pSRC, frameCount, pFramesOut, pSRC->pUserData); } // Slower path. Need to do a format conversion. @@ -9276,7 +9347,7 @@ mal_uint32 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint32 frameCount, framesToRead = frameCount; } - mal_uint32 framesRead = pSRC->onRead(framesToRead, pStagingBuffer, pSRC->pUserData); + mal_uint32 framesRead = pSRC->onRead(pSRC, framesToRead, pStagingBuffer, pSRC->pUserData); if (framesRead == 0) { break; } @@ -9791,12 +9862,14 @@ static void mal_dsp_mix_channels(float* pFramesOut, mal_uint32 channelsOut, cons } -mal_uint32 mal_dsp__src_on_read(mal_uint32 frameCount, void* pFramesOut, void* pUserData) +mal_uint32 mal_dsp__src_on_read(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, void* pUserData) { + (void)pSRC; + mal_dsp* pDSP = (mal_dsp*)pUserData; mal_assert(pDSP != NULL); - return pDSP->onRead(frameCount, pFramesOut, pDSP->pUserDataForOnRead); + return pDSP->onRead(pDSP, frameCount, pFramesOut, pDSP->pUserDataForOnRead); } mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* pUserData, mal_dsp* pDSP) @@ -9899,7 +9972,7 @@ mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFram // Fast path. if (pDSP->isPassthrough) { - return pDSP->onRead(frameCount, pFramesOut, pDSP->pUserDataForOnRead); + return pDSP->onRead(pDSP, frameCount, pFramesOut, pDSP->pUserDataForOnRead); } @@ -9923,7 +9996,7 @@ mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFram framesRead = mal_src_read_frames(&pDSP->src, framesToRead, pFrames[iFrames]); pFramesFormat[iFrames] = pDSP->src.config.formatOut; // Should always be f32. } else { - framesRead = pDSP->onRead(framesToRead, pFrames[iFrames], pDSP->pUserDataForOnRead); + framesRead = pDSP->onRead(pDSP, framesToRead, pFrames[iFrames], pDSP->pUserDataForOnRead); pFramesFormat[iFrames] = pDSP->config.formatIn; } @@ -9990,8 +10063,10 @@ typedef struct mal_uint32 iNextFrame; } mal_convert_frames__data; -mal_uint32 mal_convert_frames__on_read(mal_uint32 frameCount, void* pFramesOut, void* pUserData) +mal_uint32 mal_convert_frames__on_read(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) { + (void)pDSP; + mal_convert_frames__data* pData = (mal_convert_frames__data*)pUserData; mal_assert(pData != NULL); mal_assert(pData->totalFrameCount >= pData->iNextFrame); @@ -10333,9 +10408,12 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) // ================ // // v0.x - 2017-xx-xx +// - API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll +// need to update. +// - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively. +// - API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent. // - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of // audio data to a different format. -// - Expose the mutex APIs. // // v0.5 - 2017-11-11 // - API CHANGE: The mal_context_init() function now takes a pointer to a mal_context_config object for From 68024f1b0bc46b57e87430a961bb6d3adf8ef5c4 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Nov 2017 21:37:00 +0100 Subject: [PATCH 011/139] Added desktop platform check... ...to define proper values --- src/rglfw.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/rglfw.c b/src/rglfw.c index 81949a3d..1a3e587f 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -26,6 +26,19 @@ * **********************************************************************************************/ +#ifdef _WIN32 + #define _GLFW_WIN32 +#endif +#ifdef __linux__ + #define _GLFW_X11 +#endif +#ifdef __APPLE__ + #define _GLFW_COCOA + #define _GLFW_USE_CHDIR + #define _GLFW_USE_MENUBAR + #define _GLFW_USE_RETINA +#endif + #include "external/glfw/src/context.c" #include "external/glfw/src/init.c" #include "external/glfw/src/input.c" From 88d2810fa3d6c87eeec673c54788a6f39e15f77a Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 14 Nov 2017 21:15:50 +1000 Subject: [PATCH 012/139] Bug fixes for Music with mini_al. --- src/audio.c | 54 ++++++++++++++++++++++++++++++++++++++++++ src/external/mini_al.h | 54 ++++++++++++++++++++++++++++++++++-------- src/raylib.h | 2 ++ 3 files changed, 100 insertions(+), 10 deletions(-) diff --git a/src/audio.c b/src/audio.c index d29ad1ba..48e33d19 100644 --- a/src/audio.c +++ b/src/audio.c @@ -1426,6 +1426,13 @@ void UpdateMusicStream(Music music) music->loopCount--; // Decrease loop count PlayMusicStream(music); // Play again } + else + { + if (music->loopCount == -1) + { + PlayMusicStream(music); + } + } } else { @@ -1506,6 +1513,13 @@ void UpdateMusicStream(Music music) music->loopCount--; // Decrease loop count PlayMusicStream(music); // Play again } + else + { + if (music->loopCount == -1) + { + PlayMusicStream(music); + } + } } else { @@ -1537,13 +1551,21 @@ bool IsMusicPlaying(Music music) // Set volume for music void SetMusicVolume(Music music, float volume) { +#if USE_MINI_AL + SetAudioStreamVolume(music->stream, volume); +#else alSourcef(music->stream.source, AL_GAIN, volume); +#endif } // Set pitch for music void SetMusicPitch(Music music, float pitch) { +#if USE_MINI_AL + SetAudioStreamPitch(music->stream, pitch); +#else alSourcef(music->stream.source, AL_PITCH, pitch); +#endif } // Set music loop count (loop repeats) @@ -1964,6 +1986,38 @@ void StopAudioStream(AudioStream stream) #endif } +void SetAudioStreamVolume(AudioStream stream, float volume) +{ +#if USE_MINI_AL + AudioStreamData* internalData = (AudioStreamData*)stream.handle; + if (internalData == NULL) + { + TraceLog(LOG_ERROR, "Invalid audio stream"); + return; + } + + internalData->volume = volume; +#else + alSourcef(stream.source, AL_GAIN, volume); +#endif +} + +void SetAudioStreamPitch(AudioStream stream, float pitch) +{ +#if USE_MINI_AL + AudioStreamData* internalData = (AudioStreamData*)stream.handle; + if (internalData == NULL) + { + TraceLog(LOG_ERROR, "Invalid audio stream"); + return; + } + + internalData->pitch = pitch; +#else + alSourcef(stream.source, AL_PITCH, pitch); +#endif +} + //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- diff --git a/src/external/mini_al.h b/src/external/mini_al.h index abb52295..58f542cf 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -1358,6 +1358,13 @@ mal_result mal_src_init(mal_src_config* pConfig, mal_src_read_proc onRead, void* // Returns the number of frames actually read. mal_uint32 mal_src_read_frames(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut); +// The same mal_src_read_frames() with extra control over whether or not the internal buffers should be flushed at the end. +// +// Internally there exists a buffer that keeps track of the previous and next samples for sample rate conversion. The simple +// version of this function does _not_ flush this buffer because otherwise it causes clitches for streaming based conversion +// pipelines. The problem, however, is that sometimes you need those last few samples (such as if you're doing a bulk conversion +// of a static file). Enabling flushing will fix this for you. +mal_uint32 mal_src_read_frames_ex(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush); /////////////////////////////////////////////////////////////////////////////// @@ -1370,8 +1377,16 @@ mal_uint32 mal_src_read_frames(mal_src* pSRC, mal_uint32 frameCount, void* pFram mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* pUserData, mal_dsp* pDSP); // Reads a number of frames and runs them through the DSP processor. +// +// This this _not_ flush the internal buffers which means you may end up with a few less frames than you may expect. Look at +// mal_dsp_read_frames_ex() if you want to flush the buffers at the end of the read. mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut); +// The same mal_dsp_read_frames() with extra control over whether or not the internal buffers should be flushed at the end. +// +// See documentation for mal_src_read_frames_ex() for an explanation on flushing. +mal_uint32 mal_dsp_read_frames_ex(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush); + // High-level helper for doing a full format conversion in one go. Returns the number of output frames. Call this with pOut set to NULL to // determine the required size of the output buffer. // @@ -9283,8 +9298,8 @@ mal_uint32 mal_src_cache_read_frames(mal_src_cache* pCache, mal_uint32 frameCoun } -mal_uint32 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut); -mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut); +mal_uint32 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush); +mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush); mal_result mal_src_init(mal_src_config* pConfig, mal_src_read_proc onRead, void* pUserData, mal_src* pSRC) { @@ -9314,24 +9329,31 @@ mal_result mal_src_init(mal_src_config* pConfig, mal_src_read_proc onRead, void* } mal_uint32 mal_src_read_frames(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut) +{ + return mal_src_read_frames_ex(pSRC, frameCount, pFramesOut, MAL_FALSE); +} + +mal_uint32 mal_src_read_frames_ex(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush) { if (pSRC == NULL || frameCount == 0 || pFramesOut == NULL) return 0; // Could just use a function pointer instead of a switch for this... switch (pSRC->config.algorithm) { - case mal_src_algorithm_none: return mal_src_read_frames_passthrough(pSRC, frameCount, pFramesOut); - case mal_src_algorithm_linear: return mal_src_read_frames_linear(pSRC, frameCount, pFramesOut); + case mal_src_algorithm_none: return mal_src_read_frames_passthrough(pSRC, frameCount, pFramesOut, flush); + case mal_src_algorithm_linear: return mal_src_read_frames_linear(pSRC, frameCount, pFramesOut, flush); default: return 0; } } -mal_uint32 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut) +mal_uint32 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush) { mal_assert(pSRC != NULL); mal_assert(frameCount > 0); mal_assert(pFramesOut != NULL); + (void)flush; // Passthrough need not care about flushing. + // Fast path. No need for data conversion - just pass right through. if (pSRC->config.formatIn == pSRC->config.formatOut) { return pSRC->onRead(pSRC, frameCount, pFramesOut, pSRC->pUserData); @@ -9362,7 +9384,7 @@ mal_uint32 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint32 frameCount, return totalFramesRead; } -mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut) +mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush) { mal_assert(pSRC != NULL); mal_assert(frameCount > 0); @@ -9414,7 +9436,14 @@ mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void pNextFrame[j] = 0; } - pSRC->linear.isNextFramesLoaded = MAL_FALSE; + if (pSRC->linear.isNextFramesLoaded) { + pSRC->linear.isNextFramesLoaded = MAL_FALSE; + } else { + if (flush) { + pSRC->linear.isPrevFramesLoaded = MAL_FALSE; + } + } + break; } } @@ -9426,7 +9455,7 @@ mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void totalFramesRead += 1; // If there's no frames available we need to get out of this loop. - if (!pSRC->linear.isNextFramesLoaded) { + if (!pSRC->linear.isNextFramesLoaded && (!flush || !pSRC->linear.isPrevFramesLoaded)) { break; } } @@ -9967,6 +9996,11 @@ mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* } mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut) +{ + return mal_dsp_read_frames_ex(pDSP, frameCount, pFramesOut, MAL_FALSE); +} + +mal_uint32 mal_dsp_read_frames_ex(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush) { if (pDSP == NULL || pFramesOut == NULL) return 0; @@ -9993,7 +10027,7 @@ mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFram // The initial filling of sample data depends on whether or not we are using SRC. mal_uint32 framesRead = 0; if (pDSP->isSRCRequired) { - framesRead = mal_src_read_frames(&pDSP->src, framesToRead, pFrames[iFrames]); + framesRead = mal_src_read_frames_ex(&pDSP->src, framesToRead, pFrames[iFrames], flush); pFramesFormat[iFrames] = pDSP->src.config.formatOut; // Should always be f32. } else { framesRead = pDSP->onRead(pDSP, framesToRead, pFrames[iFrames], pDSP->pUserDataForOnRead); @@ -10116,7 +10150,7 @@ mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 chann return 0; } - return mal_dsp_read_frames(&dsp, frameCountOut, pOut); + return mal_dsp_read_frames_ex(&dsp, frameCountOut, pOut, MAL_TRUE); } diff --git a/src/raylib.h b/src/raylib.h index 725eb23b..1f138c2b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1165,6 +1165,8 @@ RLAPI void PauseAudioStream(AudioStream stream); // Pause a RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream +RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) +RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) #ifdef __cplusplus } From 322d868841493e1da6455a7153b4930b284c46df Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 14 Nov 2017 21:44:57 +1000 Subject: [PATCH 013/139] Fix minor errors with the OpenAL backend. --- src/audio.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/audio.c b/src/audio.c index 48e33d19..f159222d 100644 --- a/src/audio.c +++ b/src/audio.c @@ -82,9 +82,9 @@ #include "utils.h" // Required for: fopen() Android mapping #endif -//#if USE_MINI_AL - #include "external/mini_al.h" // Implemented in mini_al.c. Cannot implement this here because it conflicts with Win32 APIs such as CloseWindow(), etc. -//#else +#include "external/mini_al.h" // Implemented in mini_al.c. Cannot implement this here because it conflicts with Win32 APIs such as CloseWindow(), etc. + +#if !defined(USE_MINI_AL) || USE_MINI_AL == 0 #if defined(__APPLE__) #include "OpenAL/al.h" // OpenAL basic header #include "OpenAL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) @@ -96,7 +96,7 @@ // OpenAL extension: AL_EXT_FLOAT32 - Support for 32bit float samples // OpenAL extension: AL_EXT_MCFORMATS - Support for multi-channel formats (Quad, 5.1, 6.1, 7.1) -//#endif +#endif #include // Required for: malloc(), free() #include // Required for: strcmp(), strncmp() @@ -176,22 +176,6 @@ typedef struct MusicData { unsigned int samplesLeft; // Number of samples left to end } MusicData; -// AudioStreamData -typedef struct AudioStreamData AudioStreamData; -struct AudioStreamData { - mal_dsp dsp; // AudioStream data needs to flow through a persistent conversion pipeline. Not doing this will result in glitches between buffer updates. - float volume; - float pitch; - bool playing; - bool paused; - bool isSubBufferProcessed[2]; - unsigned int frameCursorPos; - unsigned int bufferSizeInFrames; - AudioStreamData* next; - AudioStreamData* prev; - unsigned char buffer[1]; -}; - #if defined(AUDIO_STANDALONE) typedef enum { LOG_INFO = 0, LOG_ERROR, LOG_WARNING, LOG_DEBUG, LOG_OTHER } TraceLogType; #endif @@ -245,6 +229,22 @@ struct SoundData mal_uint8 data[1]; // Raw audio data. }; +// AudioStreamData +typedef struct AudioStreamData AudioStreamData; +struct AudioStreamData { + mal_dsp dsp; // AudioStream data needs to flow through a persistent conversion pipeline. Not doing this will result in glitches between buffer updates. + float volume; + float pitch; + bool playing; + bool paused; + bool isSubBufferProcessed[2]; + unsigned int frameCursorPos; + unsigned int bufferSizeInFrames; + AudioStreamData* next; + AudioStreamData* prev; + unsigned char buffer[1]; +}; + static mal_context context; static mal_device device; static mal_bool32 isAudioInitialized = MAL_FALSE; @@ -1594,7 +1594,7 @@ float GetMusicTimePlayed(Music music) return secondsPlayed; } - +#if USE_MINI_AL static mal_uint32 UpdateAudioStream_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) { AudioStreamData* internalData = (AudioStreamData*)pUserData; @@ -1652,6 +1652,7 @@ static mal_uint32 UpdateAudioStream_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCou return frameCount; } +#endif // Init audio stream (to stream audio pcm data) AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) From e03afbf2fa4c3bba129a748c9f25efad46687528 Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 15 Nov 2017 22:04:23 +1000 Subject: [PATCH 014/139] Add support for pitch shifting. This commit should bring the mini_al backend up to feature parity with the OpenAL backend. --- src/audio.c | 189 ++++++++++++++++++++++++++++++----------- src/external/mini_al.h | 93 ++++++++++++++++++-- 2 files changed, 223 insertions(+), 59 deletions(-) diff --git a/src/audio.c b/src/audio.c index f159222d..d20380d0 100644 --- a/src/audio.c +++ b/src/audio.c @@ -72,7 +72,9 @@ #define SUPPORT_FILEFORMAT_MOD //------------------------------------------------- +#ifndef USE_MINI_AL #define USE_MINI_AL 1 // Set to 1 to use mini_al; 0 to use OpenAL. +#endif #if defined(AUDIO_STANDALONE) #include "audio.h" @@ -214,25 +216,24 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo typedef struct SoundData SoundData; struct SoundData { - mal_format format; - mal_uint32 channels; - mal_uint32 sampleRate; - mal_uint32 frameCount; - mal_uint32 frameCursorPos; // Keeps track of the next frame to read when mixing + mal_dsp dsp; // Necessary for pitch shift. This is an optimized passthrough when the pitch == 1. float volume; float pitch; bool playing; bool paused; bool looping; + unsigned int frameCursorPos; // Keeps track of the next frame to read when mixing + unsigned int bufferSizeInFrames; SoundData* next; SoundData* prev; - mal_uint8 data[1]; // Raw audio data. + unsigned char data[1]; // Raw audio data. }; // AudioStreamData typedef struct AudioStreamData AudioStreamData; -struct AudioStreamData { - mal_dsp dsp; // AudioStream data needs to flow through a persistent conversion pipeline. Not doing this will result in glitches between buffer updates. +struct AudioStreamData +{ + mal_dsp dsp; // AudioStream data needs to flow through a persistent conversion pipeline. Not doing this will result in glitches between buffer updates. float volume; float pitch; bool playing; @@ -250,7 +251,7 @@ static mal_device device; static mal_bool32 isAudioInitialized = MAL_FALSE; static float masterVolume = 1; static mal_mutex soundLock; -static SoundData* firstSound; // Sounds are tracked in a linked list. +static SoundData* firstSound; // Sounds are tracked in a linked list. static SoundData* lastSound; static AudioStreamData* firstAudioStream; static AudioStreamData* lastAudioStream; @@ -286,6 +287,9 @@ static void RemoveSound(SoundData* internalSound) } else { internalSound->next->prev = internalSound->prev; } + + internalSound->prev = NULL; + internalSound->next = NULL; } mal_mutex_unlock(&soundLock); } @@ -321,6 +325,9 @@ static void RemoveAudioStream(AudioStreamData* internalAudioStream) } else { internalAudioStream->next->prev = internalAudioStream->prev; } + + internalAudioStream->prev = NULL; + internalAudioStream->next = NULL; } mal_mutex_unlock(&soundLock); } @@ -333,6 +340,21 @@ static void OnLog_MAL(mal_context* pContext, mal_device* pDevice, const char* me TraceLog(LOG_ERROR, message); // All log messages from mini_al are errors. } +// This is the main mixing function. Mixing is pretty simple in this project - it's just an accumulation. +// +// framesOut is both an input and an output. It will be initially filled with zeros outside of this function. +static void MixFrames(float* framesOut, const float* framesIn, mal_uint32 frameCount, float localVolume) +{ + for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { + for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel) { + float* frameOut = framesOut + (iFrame * device.channels); + float* frameIn = framesIn + (iFrame * device.channels); + + frameOut[iChannel] += frameIn[iChannel] * masterVolume * localVolume; + } + } +} + static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameCount, void* pFramesOut) { // This is where all of the mixing takes place. @@ -345,7 +367,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC // want to consider how you might want to avoid this. mal_mutex_lock(&soundLock); { - float* pFramesOutF = (float*)pFramesOut; // <-- Just for convenience. + float* framesOutF = (float*)pFramesOut; // <-- Just for convenience. // Sounds. for (SoundData* internalSound = firstSound; internalSound != NULL; internalSound = internalSound->next) @@ -365,33 +387,48 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC break; } - // Keep reading until the end of the buffer, or we've already read as much as is allowed. + // Just read as much data we can from the stream. mal_uint32 framesToRead = (frameCount - framesRead); - mal_uint32 framesRemaining = (internalSound->frameCount - internalSound->frameCursorPos); - if (framesToRead > framesRemaining) { - framesToRead = framesRemaining; - } + while (framesToRead > 0) { + float tempBuffer[1024]; // 512 frames for stereo. - // This is where the real mixing takes place. This can be optimized. This assumes the device and sound are of the same format. - // - // TODO: Implement pitching. - for (mal_uint32 iFrame = 0; iFrame < framesToRead; ++iFrame) { - float* pFrameOut = pFramesOutF + ((framesRead+iFrame) * device.channels); - float* pFrameIn = ((float*)internalSound->data) + ((internalSound->frameCursorPos+iFrame) * device.channels); + mal_uint32 framesToReadRightNow = framesToRead; + if (framesToReadRightNow > sizeof(tempBuffer)/DEVICE_CHANNELS) { + framesToReadRightNow = sizeof(tempBuffer)/DEVICE_CHANNELS; + } - for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel) { - pFrameOut[iChannel] += pFrameIn[iChannel] * masterVolume * internalSound->volume; + // If we're not looping, we need to make sure we flush the internal buffers of the DSP pipeline to ensure we get the + // last few samples. + mal_bool32 flushDSP = !internalSound->looping; + + mal_uint32 framesJustRead = mal_dsp_read_frames_ex(&internalSound->dsp, framesToReadRightNow, tempBuffer, flushDSP); + if (framesJustRead > 0) { + float* framesOut = framesOutF + (framesRead * device.channels); + float* framesIn = tempBuffer; + MixFrames(framesOut, framesIn, framesJustRead, internalSound->volume); + + framesToRead -= framesJustRead; + framesRead += framesJustRead; + } + + // If we weren't able to read all the frames we requested, break. + if (framesJustRead < framesToReadRightNow) { + if (!internalSound->looping) { + internalSound->playing = MAL_FALSE; + internalSound->frameCursorPos = 0; + break; + } else { + // Should never get here, but just for safety, move the cursor position back to the start and continue the loop. + internalSound->frameCursorPos = 0; + continue; + } } } - framesRead += framesToRead; - internalSound->frameCursorPos += framesToRead; - - // If we've reached the end of the sound's internal buffer we do one of two things: loop back to the start, or just stop. - if (framesToRead == framesRemaining) { - if (!internalSound->looping) { - break; - } + // If for some reason we weren't able to read every frame we'll need to break from the loop. Not doing this could + // theoretically put us into an infinite loop. + if (framesToRead > 0) { + break; } } } @@ -427,17 +464,9 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC mal_uint32 framesJustRead = mal_dsp_read_frames(&internalData->dsp, framesToReadRightNow, tempBuffer); if (framesJustRead > 0) { - // This is where the real mixing takes place. This can be optimized. This assumes the device and sound are of the same format. - // - // TODO: Implement pitching. - for (mal_uint32 iFrame = 0; iFrame < framesToRead; ++iFrame) { - float* pFrameOut = pFramesOutF + ((framesRead+iFrame) * device.channels); - float* pFrameIn = tempBuffer + (iFrame * device.channels); - - for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel) { - pFrameOut[iChannel] += pFrameIn[iChannel] * masterVolume * internalData->volume; - } - } + float* framesOut = framesOutF + (framesRead * device.channels); + float* framesIn = tempBuffer; + MixFrames(framesOut, framesIn, framesJustRead, internalData->volume); framesToRead -= framesJustRead; framesRead += framesJustRead; @@ -667,6 +696,39 @@ Sound LoadSound(const char *fileName) return sound; } +#if USE_MINI_AL +static mal_uint32 Sound_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) +{ + SoundData* internalData = (SoundData*)pUserData; + + mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(internalData->dsp.config.formatIn)*internalData->dsp.config.channelsIn; + + // Just keep reading as much as we can. Do not zero fill excess data in the output buffer. + mal_uint32 framesRead = 0; + while (framesRead < frameCount) + { + mal_uint32 framesRemaining = internalData->bufferSizeInFrames - internalData->frameCursorPos; + mal_uint32 framesToRead = (frameCount - framesRead); + if (framesToRead > framesRemaining) { + framesToRead = framesRemaining; + } + + memcpy((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), internalData->data + (internalData->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes); + internalData->frameCursorPos += framesToRead; + framesRead += framesToRead; + + // If we've reached the end of the buffer but we're not looping, return. + if (framesToRead == framesRemaining) { + if (!internalData->looping) { + break; + } + } + } + + return framesRead; +} +#endif + // Load sound from wave data // NOTE: Wave data must be unallocated manually Sound LoadSoundFromWave(Wave wave) @@ -702,16 +764,28 @@ Sound LoadSoundFromWave(Wave wave) TraceLog(LOG_ERROR, "LoadSoundFromWave() : Format conversion failed."); } - internalSound->format = DEVICE_FORMAT; - internalSound->channels = DEVICE_CHANNELS; - internalSound->sampleRate = DEVICE_SAMPLE_RATE; - internalSound->frameCount = frameCount; - internalSound->frameCursorPos = 0; + // We run audio data through a sample rate converter in order to support pitch shift. By default this will use an optimized passthrough + // algorithm, but when the application changes the pitch it will change to a less optimal linear SRC. + mal_dsp_config dspConfig; + memset(&dspConfig, 0, sizeof(dspConfig)); + dspConfig.formatIn = DEVICE_FORMAT; + dspConfig.formatOut = DEVICE_FORMAT; + dspConfig.channelsIn = DEVICE_CHANNELS; + dspConfig.channelsOut = DEVICE_CHANNELS; + dspConfig.sampleRateIn = DEVICE_SAMPLE_RATE; + dspConfig.sampleRateOut = DEVICE_SAMPLE_RATE; + mal_result resultMAL = mal_dsp_init(&dspConfig, Sound_OnDSPRead, internalSound, &internalSound->dsp); + if (resultMAL != MAL_SUCCESS) { + TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create data conversion pipeline"); + } + internalSound->volume = 1; internalSound->pitch = 1; internalSound->playing = 0; internalSound->paused = 0; internalSound->looping = 0; + internalSound->bufferSizeInFrames = frameCount; + internalSound->frameCursorPos = 0; AppendSound(internalSound); sound.handle = (void*)internalSound; @@ -816,9 +890,8 @@ void UpdateSound(Sound sound, const void *data, int samplesCount) internalSound->paused = false; internalSound->frameCursorPos = 0; - // TODO: May want to lock/unlock this since this data buffer is read at mixing time. However, this puts a mutex in - // in the mixing code which makes it no longer real-time. This is likely not a critical issue for this project, though. - memcpy(internalSound->data, data, samplesCount*internalSound->channels*mal_get_sample_size_in_bytes(internalSound->format)); + // TODO: May want to lock/unlock this since this data buffer is read at mixing time. + memcpy(internalSound->data, data, samplesCount*internalSound->dsp.config.channelsIn*mal_get_sample_size_in_bytes(internalSound->dsp.config.formatIn)); #else ALint sampleRate, sampleSize, channels; alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); @@ -986,6 +1059,11 @@ void SetSoundPitch(Sound sound, float pitch) } internalSound->pitch = pitch; + + // Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches + // will make the sound faster; lower pitches make it slower. + mal_uint32 newOutputSampleRate = (mal_uint32)((((float)internalSound->dsp.config.sampleRateOut / (float)internalSound->dsp.config.sampleRateIn) / pitch) * internalSound->dsp.config.sampleRateIn); + mal_dsp_set_output_sample_rate(&internalSound->dsp, newOutputSampleRate); #else alSourcef(sound.source, AL_PITCH, pitch); #endif @@ -2013,7 +2091,18 @@ void SetAudioStreamPitch(AudioStream stream, float pitch) return; } + if (pitch == 0) + { + TraceLog(LOG_ERROR, "Attempting to set pitch to 0"); + return; + } + internalData->pitch = pitch; + + // Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches + // will make the sound faster; lower pitches make it slower. + mal_uint32 newOutputSampleRate = (mal_uint32)((((float)internalData->dsp.config.sampleRateOut / (float)internalData->dsp.config.sampleRateIn) / pitch) * internalData->dsp.config.sampleRateIn); + mal_dsp_set_output_sample_rate(&internalData->dsp, newOutputSampleRate); #else alSourcef(stream.source, AL_PITCH, pitch); #endif diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 58f542cf..fad9952f 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -570,7 +570,6 @@ struct mal_src mal_src_config config; mal_src_read_proc onRead; void* pUserData; - float ratio; float bin[256]; mal_src_cache cache; // <-- For simplifying and optimizing client -> memory reading. @@ -1353,6 +1352,12 @@ static inline mal_device_config mal_device_config_init_playback(mal_format forma // Initializes a sample rate conversion object. mal_result mal_src_init(mal_src_config* pConfig, mal_src_read_proc onRead, void* pUserData, mal_src* pSRC); +// Dynamically adjusts the output sample rate. +// +// This is useful for dynamically adjust pitch. Keep in mind, however, that this will speed up or slow down the sound. If this +// is not acceptable you will need to use your own algorithm. +mal_result mal_src_set_output_sample_rate(mal_src* pSRC, mal_uint32 sampleRateOut); + // Reads a number of frames. // // Returns the number of frames actually read. @@ -1376,6 +1381,12 @@ mal_uint32 mal_src_read_frames_ex(mal_src* pSRC, mal_uint32 frameCount, void* pF // Initializes a DSP object. mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* pUserData, mal_dsp* pDSP); +// Dynamically adjusts the output sample rate. +// +// This is useful for dynamically adjust pitch. Keep in mind, however, that this will speed up or slow down the sound. If this +// is not acceptable you will need to use your own algorithm. +mal_result mal_dsp_set_output_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateOut); + // Reads a number of frames and runs them through the DSP processor. // // This this _not_ flush the internal buffers which means you may end up with a few less frames than you may expect. Look at @@ -9313,21 +9324,27 @@ mal_result mal_src_init(mal_src_config* pConfig, mal_src_read_proc onRead, void* pSRC->onRead = onRead; pSRC->pUserData = pUserData; - // If the in and out sample rates are the same, fall back to the passthrough algorithm. - if (pSRC->config.sampleRateIn == pSRC->config.sampleRateOut) { - pSRC->config.algorithm = mal_src_algorithm_none; - } - if (pSRC->config.cacheSizeInFrames > MAL_SRC_CACHE_SIZE_IN_FRAMES || pSRC->config.cacheSizeInFrames == 0) { pSRC->config.cacheSizeInFrames = MAL_SRC_CACHE_SIZE_IN_FRAMES; } - pSRC->ratio = (float)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut; - mal_src_cache_init(pSRC, &pSRC->cache); return MAL_SUCCESS; } +mal_result mal_src_set_output_sample_rate(mal_src* pSRC, mal_uint32 sampleRateOut) +{ + if (pSRC == NULL) return MAL_INVALID_ARGS; + + // Must have a sample rate of > 0. + if (sampleRateOut == 0) { + return MAL_INVALID_ARGS; + } + + pSRC->config.sampleRateOut = sampleRateOut; + return MAL_SUCCESS; +} + mal_uint32 mal_src_read_frames(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut) { return mal_src_read_frames_ex(pSRC, frameCount, pFramesOut, MAL_FALSE); @@ -9337,6 +9354,13 @@ mal_uint32 mal_src_read_frames_ex(mal_src* pSRC, mal_uint32 frameCount, void* pF { if (pSRC == NULL || frameCount == 0 || pFramesOut == NULL) return 0; + mal_src_algorithm algorithm = pSRC->config.algorithm; + + // Always use passthrough if the sample rates are the same. + if (pSRC->config.sampleRateIn == pSRC->config.sampleRateOut) { + algorithm = mal_src_algorithm_none; + } + // Could just use a function pointer instead of a switch for this... switch (pSRC->config.algorithm) { @@ -9408,7 +9432,7 @@ mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void pSRC->linear.isNextFramesLoaded = MAL_TRUE; } - float factor = pSRC->ratio; + float factor = (float)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut; mal_uint32 totalFramesRead = 0; while (frameCount > 0) { @@ -9995,6 +10019,57 @@ mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* return MAL_SUCCESS; } +mal_result mal_dsp_set_output_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateOut) +{ + if (pDSP == NULL) return MAL_INVALID_ARGS; + + // Must have a sample rate of > 0. + if (sampleRateOut == 0) { + return MAL_INVALID_ARGS; + } + + pDSP->config.sampleRateOut = sampleRateOut; + + // If we already have an SRC pipeline initialized we do _not_ want to re-create it. Instead we adjust it. If we didn't previously + // have an SRC pipeline in place we'll need to initialize it. + if (pDSP->isSRCRequired) { + if (pDSP->config.sampleRateIn != pDSP->config.sampleRateOut) { + mal_src_set_output_sample_rate(&pDSP->src, sampleRateOut); + } else { + pDSP->isSRCRequired = MAL_FALSE; + } + } else { + // We may need a new SRC pipeline. + if (pDSP->config.sampleRateIn != pDSP->config.sampleRateOut) { + pDSP->isSRCRequired = MAL_TRUE; + + mal_src_config srcConfig; + srcConfig.sampleRateIn = pDSP->config.sampleRateIn; + srcConfig.sampleRateOut = pDSP->config.sampleRateOut; + srcConfig.formatIn = pDSP->config.formatIn; + srcConfig.formatOut = mal_format_f32; + srcConfig.channels = pDSP->config.channelsIn; + srcConfig.algorithm = mal_src_algorithm_linear; + srcConfig.cacheSizeInFrames = pDSP->config.cacheSizeInFrames; + mal_result result = mal_src_init(&srcConfig, mal_dsp__src_on_read, pDSP, &pDSP->src); + if (result != MAL_SUCCESS) { + return result; + } + } else { + pDSP->isSRCRequired = MAL_FALSE; + } + } + + // Update whether or not the pipeline is a passthrough. + if (pDSP->config.formatIn == pDSP->config.formatOut && pDSP->config.channelsIn == pDSP->config.channelsOut && pDSP->config.sampleRateIn == pDSP->config.sampleRateOut && !pDSP->isChannelMappingRequired) { + pDSP->isPassthrough = MAL_TRUE; + } else { + pDSP->isPassthrough = MAL_FALSE; + } + + return MAL_SUCCESS; +} + mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut) { return mal_dsp_read_frames_ex(pDSP, frameCount, pFramesOut, MAL_FALSE); From 96be62e88b7a49b2d263cc1e24f0880421214bbc Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 16 Nov 2017 21:49:45 +1000 Subject: [PATCH 015/139] Update mini_al.h --- src/external/mini_al.h | 57 +++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/src/external/mini_al.h b/src/external/mini_al.h index fad9952f..558fc9aa 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -2534,10 +2534,12 @@ static inline mal_uint32 mal_device__get_state(mal_device* pDevice) #ifdef MAL_WIN32 -static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; -static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; -//static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; -//static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; + #if !defined(MAL_NO_WASAPI) || !defined(MAL_NO_DSOUND) + static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; + static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; + //static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; + //static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; + #endif #endif @@ -8735,7 +8737,7 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi pDevice->onSend = config.onSendCallback; pDevice->onRecv = config.onRecvCallback; - if (((mal_uint64)pDevice % sizeof(pDevice)) != 0) { + if (((size_t)pDevice % sizeof(pDevice)) != 0) { if (pContext->config.onLog) { pContext->config.onLog(pContext, pDevice, "WARNING: mal_device_init() called for a device that is not properly aligned. Thread safety is not supported."); } @@ -9362,7 +9364,7 @@ mal_uint32 mal_src_read_frames_ex(mal_src* pSRC, mal_uint32 frameCount, void* pF } // Could just use a function pointer instead of a switch for this... - switch (pSRC->config.algorithm) + switch (algorithm) { case mal_src_algorithm_none: return mal_src_read_frames_passthrough(pSRC, frameCount, pFramesOut, flush); case mal_src_algorithm_linear: return mal_src_read_frames_linear(pSRC, frameCount, pFramesOut, flush); @@ -10271,9 +10273,6 @@ void mal_blend_f32(float* pOut, float* pInA, float* pInB, float factor, mal_uint // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#if 0 -#include "tools/malgen/bin/malgen_test0.c" -#else void mal_pcm_u8_to_s16(short* pOut, const unsigned char* pIn, unsigned int count) { int r; @@ -10440,10 +10439,10 @@ void mal_pcm_s32_to_f32(float* pOut, const int* pIn, unsigned int count) float r; for (unsigned int i = 0; i < count; ++i) { int x = pIn[i]; - int s; - s = ((*((int*)&x)) & 0x80000000) >> 31; - s = s + 2147483647; - r = x / (float)(unsigned int)s; + double t; + t = (double)(x + 2147483648); + t = t * 0.0000000004656612873077392578125; + r = (float)(t - 1); pOut[i] = (float)r; } } @@ -10454,12 +10453,9 @@ void mal_pcm_f32_to_u8(unsigned char* pOut, const float* pIn, unsigned int count for (unsigned int i = 0; i < count; ++i) { float x = pIn[i]; float c; - int s; c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); - s = ((*((int*)&x)) & 0x80000000) >> 31; - s = s + 127; - r = (int)(c * s); - r = r + 128; + c = c + 1; + r = (int)(c * 127.5f); pOut[i] = (unsigned char)r; } } @@ -10470,11 +10466,10 @@ void mal_pcm_f32_to_s16(short* pOut, const float* pIn, unsigned int count) for (unsigned int i = 0; i < count; ++i) { float x = pIn[i]; float c; - int s; c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); - s = ((*((int*)&x)) & 0x80000000) >> 31; - s = s + 32767; - r = (int)(c * s); + c = c + 1; + r = (int)(c * 32767.5f); + r = r - 32768; pOut[i] = (short)r; } } @@ -10485,11 +10480,10 @@ void mal_pcm_f32_to_s24(void* pOut, const float* pIn, unsigned int count) for (unsigned int i = 0; i < count; ++i) { float x = pIn[i]; float c; - int s; c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); - s = ((*((int*)&x)) & 0x80000000) >> 31; - s = s + 8388607; - r = (int)(c * s); + c = c + 1; + r = (int)(c * 8388607.5f); + r = r - 8388608; ((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16); } } @@ -10500,15 +10494,14 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) for (unsigned int i = 0; i < count; ++i) { float x = pIn[i]; float c; - mal_int64 s; + mal_int64 t; c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); - s = ((*((int*)&x)) & 0x80000000) >> 31; - s = s + 2147483647; - r = (int)(c * s); + c = c + 1; + t = (mal_int64)(c * 2147483647.5); + r = (int)(t - 2147483648); pOut[i] = (int)r; } } -#endif #endif @@ -10523,6 +10516,8 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) // - API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent. // - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of // audio data to a different format. +// - Improvements to f32 -> u8/s16/s24/s32 conversion routines. +// - Warning fixes. // // v0.5 - 2017-11-11 // - API CHANGE: The mal_context_init() function now takes a pointer to a mal_context_config object for From a6416f82a735d15ee556646f4ce362b38ca5b3d0 Mon Sep 17 00:00:00 2001 From: Ray San Date: Thu, 16 Nov 2017 17:59:35 +0100 Subject: [PATCH 016/139] Reviewed file comments --- src/rglfw.c | 77 ++++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/src/rglfw.c b/src/rglfw.c index 1a3e587f..b1b4eed7 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -1,9 +1,9 @@ /********************************************************************************************** * -* raylib GLFW single file compilation +* rglfw - raylib GLFW single file compilation * -* This file includes GLFW sources to be compiled together with raylib for all supported -* platforms, this way, no external dependencies are required. +* This file includes latest GLFW sources (https://github.com/glfw/glfw) to be compiled together +* with raylib for all supported platforms, this way, no external dependencies are required. * * LICENSE: zlib/libpng * @@ -26,6 +26,10 @@ * **********************************************************************************************/ + +//#define _GLFW_BUILD_DLL // To build shared version +//http://www.glfw.org/docs/latest/compile.html#compile_manual + #ifdef _WIN32 #define _GLFW_WIN32 #endif @@ -34,11 +38,13 @@ #endif #ifdef __APPLE__ #define _GLFW_COCOA - #define _GLFW_USE_CHDIR - #define _GLFW_USE_MENUBAR - #define _GLFW_USE_RETINA + #define _GLFW_USE_CHDIR // To chdir to the Resources subdirectory of the application bundle during glfwInit + #define _GLFW_USE_MENUBAR // To create and populate the menu bar when the first window is created + #define _GLFW_USE_RETINA // To have windows use the full resolution of Retina displays #endif +// NOTE: _GLFW_WAYLAND and _GLFW_MIR experimental platforms not supported at this moment + #include "external/glfw/src/context.c" #include "external/glfw/src/init.c" #include "external/glfw/src/input.c" @@ -46,42 +52,39 @@ #include "external/glfw/src/vulkan.c" #include "external/glfw/src/window.c" -// Required compilation defines: -D_GLFW_WIN32 #ifdef _WIN32 -#include "external/glfw/src/win32_init.c" -#include "external/glfw/src/win32_joystick.c" -#include "external/glfw/src/win32_monitor.c" -#include "external/glfw/src/win32_time.c" -#include "external/glfw/src/win32_thread.c" -#include "external/glfw/src/win32_window.c" -#include "external/glfw/src/wgl_context.c" -#include "external/glfw/src/egl_context.c" -#include "external/glfw/src/osmesa_context.c" + #include "external/glfw/src/win32_init.c" + #include "external/glfw/src/win32_joystick.c" + #include "external/glfw/src/win32_monitor.c" + #include "external/glfw/src/win32_time.c" + #include "external/glfw/src/win32_thread.c" + #include "external/glfw/src/win32_window.c" + #include "external/glfw/src/wgl_context.c" + #include "external/glfw/src/egl_context.c" + #include "external/glfw/src/osmesa_context.c" #endif -// Required compilation defines: -D_GLFW_X11 #ifdef __linux__ -#include "external/glfw/src/x11_init.c" -#include "external/glfw/src/x11_monitor.c" -#include "external/glfw/src/x11_window.c" -#include "external/glfw/src/xkb_unicode.c" -#include "external/glfw/src/linux_joystick.c" -#include "external/glfw/src/posix_time.c" -#include "external/glfw/src/posix_thread.c" -#include "external/glfw/src/glx_context.c" -#include "external/glfw/src/egl_context.c" -#include "external/glfw/src/osmesa_context.c" + #include "external/glfw/src/x11_init.c" + #include "external/glfw/src/x11_monitor.c" + #include "external/glfw/src/x11_window.c" + #include "external/glfw/src/xkb_unicode.c" + #include "external/glfw/src/linux_joystick.c" + #include "external/glfw/src/posix_time.c" + #include "external/glfw/src/posix_thread.c" + #include "external/glfw/src/glx_context.c" + #include "external/glfw/src/egl_context.c" + #include "external/glfw/src/osmesa_context.c" #endif -// Required compilation defines: -D_GLFW_COCOA -D_GLFW_USE_CHDIR -D_GLFW_USE_MENUBAR -D_GLFW_USE_RETINA #ifdef __APPLE__ -#include "external/glfw/src/cocoa_init.m" -#include "external/glfw/src/cocoa_joystick.m" -#include "external/glfw/src/cocoa_monitor.m" -#include "external/glfw/src/cocoa_window.m" -#include "external/glfw/src/cocoa_time.c" -#include "external/glfw/src/posix_thread.c" -#include "external/glfw/src/nsgl_context.m" -#include "external/glfw/src/egl_context.c" -#include "external/glfw/src/osmesa_context.c.m" + #include "external/glfw/src/cocoa_init.m" + #include "external/glfw/src/cocoa_joystick.m" + #include "external/glfw/src/cocoa_monitor.m" + #include "external/glfw/src/cocoa_window.m" + #include "external/glfw/src/cocoa_time.c" + #include "external/glfw/src/posix_thread.c" + #include "external/glfw/src/nsgl_context.m" + #include "external/glfw/src/egl_context.c" + #include "external/glfw/src/osmesa_context.c.m" #endif From 261b00e9e8a0b9d90c4e7d26813a09eeee9d2f99 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 17 Nov 2017 21:12:05 +1000 Subject: [PATCH 017/139] Update mini_al. --- src/external/mini_al.h | 209 +++++++++++++++++++++++++---------------- 1 file changed, 129 insertions(+), 80 deletions(-) diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 558fc9aa..18dd3b40 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -1525,6 +1525,52 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form #endif +// Check if we have the necessary development packages for each backend at the top so we can use this to determine whether or not +// certain unused functions and variables can be excluded from the build to avoid warnings. +#ifdef MAL_ENABLE_WASAPI + #define MAL_HAS_WASAPI + #ifdef __has_include + #if !__has_include() + #undef MAL_HAS_WASAPI + #endif + #endif +#endif +#ifdef MAL_ENABLE_DSOUND + #define MAL_HAS_DSOUND + #ifdef __has_include + #if !__has_include() + #undef MAL_HAS_DSOUND + #endif + #endif +#endif +#ifdef MAL_ENABLE_WINMM + #define MAL_HAS_WINMM // Every compiler I'm aware of supports WinMM. +#endif +#ifdef MAL_ENABLE_ALSA + #define MAL_HAS_ALSA + #ifdef __has_include + #if !__has_include() + #undef MAL_HAS_ALSA + #endif + #endif +#endif +#ifdef MAL_ENABLE_COREAUDIO + #define MAL_HAS_COREAUDIO +#endif +#ifdef MAL_ENABLE_OSS + #define MAL_HAS_OSS // OSS is the only supported backend for Unix and BSD, so it must be present else this library is useless. +#endif +#ifdef MAL_ENABLE_OPENSL + #define MAL_HAS_OPENSL // Like OSS, OpenSL is the only supported backend for Android. It must be present. +#endif +#ifdef MAL_ENABLE_OPENAL + #define MAL_HAS_OPENAL // mini_al inlines the necessary OpenAL stuff. +#endif +#ifdef MAL_ENABLE_NULL + #define MAL_HAS_NULL // Everything supports the null backend. +#endif + + #ifdef MAL_WIN32 #define MAL_THREADCALL WINAPI typedef unsigned long mal_thread_result; @@ -2534,7 +2580,7 @@ static inline mal_uint32 mal_device__get_state(mal_device* pDevice) #ifdef MAL_WIN32 - #if !defined(MAL_NO_WASAPI) || !defined(MAL_NO_DSOUND) + #if defined(MAL_HAS_WASAPI) || defined(MAL_HAS_DSOUND) static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; //static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; @@ -2549,7 +2595,7 @@ static inline mal_uint32 mal_device__get_state(mal_device* pDevice) // Null Backend // /////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_ENABLE_NULL +#ifdef MAL_HAS_NULL mal_result mal_context_init__null(mal_context* pContext) { mal_assert(pContext != NULL); @@ -2777,7 +2823,7 @@ static mal_result mal_device__main_loop__null(mal_device* pDevice) #endif #endif -#if defined(MAL_ENABLE_WASAPI) || defined(MAL_ENABLE_DSOUND) +#if defined(MAL_HAS_WASAPI) || defined(MAL_HAS_DSOUND) #include #ifndef SPEAKER_FRONT_LEFT @@ -2916,7 +2962,7 @@ static void mal_channel_mask_to_channel_map__win32(DWORD dwChannelMask, mal_uint // WASAPI Backend // /////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_ENABLE_WASAPI +#ifdef MAL_HAS_WASAPI #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4091) // 'typedef ': ignored on left of '' when no variable is declared @@ -3863,7 +3909,7 @@ static mal_result mal_device__main_loop__wasapi(mal_device* pDevice) // DirectSound Backend // /////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_ENABLE_DSOUND +#ifdef MAL_HAS_DSOUND #include #if 0 // MAL_GUID_NULL is not currently used, but leaving it here in case I need to add it back again. @@ -4467,7 +4513,7 @@ static mal_result mal_device__main_loop__dsound(mal_device* pDevice) // WinMM Backend // /////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_ENABLE_WINMM +#ifdef MAL_HAS_WINMM #include #if !defined(MAXULONG_PTR) @@ -5207,7 +5253,7 @@ static mal_result mal_device__main_loop__winmm(mal_device* pDevice) // ALSA Backend // /////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_ENABLE_ALSA +#ifdef MAL_HAS_ALSA #include typedef int (* mal_snd_pcm_open_proc) (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode); @@ -6338,7 +6384,7 @@ static mal_result mal_device__main_loop__alsa(mal_device* pDevice) // OSS Backend // /////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_ENABLE_OSS +#ifdef MAL_HAS_OSS #include #include #include @@ -6686,7 +6732,7 @@ static mal_result mal_device__main_loop__oss(mal_device* pDevice) // OpenSL|ES Backend // /////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_ENABLE_OPENSL +#ifdef MAL_HAS_OPENSL #include #ifdef MAL_ANDROID #include @@ -7389,7 +7435,7 @@ static mal_result mal_device__stop_backend__opensl(mal_device* pDevice) // OpenAL Backend // /////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_ENABLE_OPENAL +#ifdef MAL_HAS_OPENAL #ifdef MAL_WIN32 #define MAL_AL_APIENTRY __cdecl #else @@ -8129,37 +8175,37 @@ static mal_result mal_device__start_backend(mal_device* pDevice) mal_assert(pDevice != NULL); mal_result result = MAL_NO_BACKEND; -#ifdef MAL_ENABLE_WASAPI +#ifdef MAL_HAS_WASAPI if (pDevice->pContext->backend == mal_backend_wasapi) { result = mal_device__start_backend__wasapi(pDevice); } #endif -#ifdef MAL_ENABLE_DSOUND +#ifdef MAL_HAS_DSOUND if (pDevice->pContext->backend == mal_backend_dsound) { result = mal_device__start_backend__dsound(pDevice); } #endif -#ifdef MAL_ENABLE_WINMM +#ifdef MAL_HAS_WINMM if (pDevice->pContext->backend == mal_backend_winmm) { result = mal_device__start_backend__winmm(pDevice); } #endif -#ifdef MAL_ENABLE_ALSA +#ifdef MAL_HAS_ALSA if (pDevice->pContext->backend == mal_backend_alsa) { result = mal_device__start_backend__alsa(pDevice); } #endif -#ifdef MAL_ENABLE_OSS +#ifdef MAL_HAS_OSS if (pDevice->pContext->backend == mal_backend_oss) { result = mal_device__start_backend__oss(pDevice); } #endif -#ifdef MAL_ENABLE_OPENAL +#ifdef MAL_HAS_OPENAL if (pDevice->pContext->backend == mal_backend_openal) { result = mal_device__start_backend__openal(pDevice); } #endif -#ifdef MAL_ENABLE_NULL +#ifdef MAL_HAS_NULL if (pDevice->pContext->backend == mal_backend_null) { result = mal_device__start_backend__null(pDevice); } @@ -8173,37 +8219,37 @@ static mal_result mal_device__stop_backend(mal_device* pDevice) mal_assert(pDevice != NULL); mal_result result = MAL_NO_BACKEND; -#ifdef MAL_ENABLE_WASAPI +#ifdef MAL_HAS_WASAPI if (pDevice->pContext->backend == mal_backend_wasapi) { result = mal_device__stop_backend__wasapi(pDevice); } #endif -#ifdef MAL_ENABLE_DSOUND +#ifdef MAL_HAS_DSOUND if (pDevice->pContext->backend == mal_backend_dsound) { result = mal_device__stop_backend__dsound(pDevice); } #endif -#ifdef MAL_ENABLE_WINMM +#ifdef MAL_HAS_WINMM if (pDevice->pContext->backend == mal_backend_winmm) { result = mal_device__stop_backend__winmm(pDevice); } #endif -#ifdef MAL_ENABLE_ALSA +#ifdef MAL_HAS_ALSA if (pDevice->pContext->backend == mal_backend_alsa) { result = mal_device__stop_backend__alsa(pDevice); } #endif -#ifdef MAL_ENABLE_OSS +#ifdef MAL_HAS_OSS if (pDevice->pContext->backend == mal_backend_oss) { result = mal_device__stop_backend__oss(pDevice); } #endif -#ifdef MAL_ENABLE_OPENAL +#ifdef MAL_HAS_OPENAL if (pDevice->pContext->backend == mal_backend_openal) { result = mal_device__stop_backend__openal(pDevice); } #endif -#ifdef MAL_ENABLE_NULL +#ifdef MAL_HAS_NULL if (pDevice->pContext->backend == mal_backend_null) { result = mal_device__stop_backend__null(pDevice); } @@ -8217,37 +8263,37 @@ static mal_result mal_device__break_main_loop(mal_device* pDevice) mal_assert(pDevice != NULL); mal_result result = MAL_NO_BACKEND; -#ifdef MAL_ENABLE_WASAPI +#ifdef MAL_HAS_WASAPI if (pDevice->pContext->backend == mal_backend_wasapi) { result = mal_device__break_main_loop__wasapi(pDevice); } #endif -#ifdef MAL_ENABLE_DSOUND +#ifdef MAL_HAS_DSOUND if (pDevice->pContext->backend == mal_backend_dsound) { result = mal_device__break_main_loop__dsound(pDevice); } #endif -#ifdef MAL_ENABLE_WINMM +#ifdef MAL_HAS_WINMM if (pDevice->pContext->backend == mal_backend_winmm) { result = mal_device__break_main_loop__winmm(pDevice); } #endif -#ifdef MAL_ENABLE_ALSA +#ifdef MAL_HAS_ALSA if (pDevice->pContext->backend == mal_backend_alsa) { result = mal_device__break_main_loop__alsa(pDevice); } #endif -#ifdef MAL_ENABLE_OSS +#ifdef MAL_HAS_OSS if (pDevice->pContext->backend == mal_backend_oss) { result = mal_device__break_main_loop__oss(pDevice); } #endif -#ifdef MAL_ENABLE_OPENAL +#ifdef MAL_HAS_OPENAL if (pDevice->pContext->backend == mal_backend_openal) { result = mal_device__break_main_loop__openal(pDevice); } #endif -#ifdef MAL_ENABLE_NULL +#ifdef MAL_HAS_NULL if (pDevice->pContext->backend == mal_backend_null) { result = mal_device__break_main_loop__null(pDevice); } @@ -8261,37 +8307,37 @@ static mal_result mal_device__main_loop(mal_device* pDevice) mal_assert(pDevice != NULL); mal_result result = MAL_NO_BACKEND; -#ifdef MAL_ENABLE_WASAPI +#ifdef MAL_HAS_WASAPI if (pDevice->pContext->backend == mal_backend_wasapi) { result = mal_device__main_loop__wasapi(pDevice); } #endif -#ifdef MAL_ENABLE_DSOUND +#ifdef MAL_HAS_DSOUND if (pDevice->pContext->backend == mal_backend_dsound) { result = mal_device__main_loop__dsound(pDevice); } #endif -#ifdef MAL_ENABLE_WINMM +#ifdef MAL_HAS_WINMM if (pDevice->pContext->backend == mal_backend_winmm) { result = mal_device__main_loop__winmm(pDevice); } #endif -#ifdef MAL_ENABLE_ALSA +#ifdef MAL_HAS_ALSA if (pDevice->pContext->backend == mal_backend_alsa) { result = mal_device__main_loop__alsa(pDevice); } #endif -#ifdef MAL_ENABLE_OSS +#ifdef MAL_HAS_OSS if (pDevice->pContext->backend == mal_backend_oss) { result = mal_device__main_loop__oss(pDevice); } #endif -#ifdef MAL_ENABLE_OPENAL +#ifdef MAL_HAS_OPENAL if (pDevice->pContext->backend == mal_backend_openal) { result = mal_device__main_loop__openal(pDevice); } #endif -#ifdef MAL_ENABLE_NULL +#ifdef MAL_HAS_NULL if (pDevice->pContext->backend == mal_backend_null) { result = mal_device__main_loop__null(pDevice); } @@ -8527,49 +8573,49 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, con result = MAL_NO_BACKEND; switch (backend) { - #ifdef MAL_ENABLE_WASAPI + #ifdef MAL_HAS_WASAPI case mal_backend_wasapi: { result = mal_context_init__wasapi(pContext); } break; #endif - #ifdef MAL_ENABLE_DSOUND + #ifdef MAL_HAS_DSOUND case mal_backend_dsound: { result = mal_context_init__dsound(pContext); } break; #endif - #ifdef MAL_ENABLE_WINMM + #ifdef MAL_HAS_WINMM case mal_backend_winmm: { result = mal_context_init__winmm(pContext); } break; #endif - #ifdef MAL_ENABLE_ALSA + #ifdef MAL_HAS_ALSA case mal_backend_alsa: { result = mal_context_init__alsa(pContext); } break; #endif - #ifdef MAL_ENABLE_OSS + #ifdef MAL_HAS_OSS case mal_backend_oss: { result = mal_context_init__oss(pContext); } break; #endif - #ifdef MAL_ENABLE_OPENSL + #ifdef MAL_HAS_OPENSL case mal_backend_opensl: { result = mal_context_init__opensl(pContext); } break; #endif - #ifdef MAL_ENABLE_OPENAL + #ifdef MAL_HAS_OPENAL case mal_backend_openal: { result = mal_context_init__openal(pContext); } break; #endif - #ifdef MAL_ENABLE_NULL + #ifdef MAL_HAS_NULL case mal_backend_null: { result = mal_context_init__null(pContext); @@ -8595,49 +8641,49 @@ mal_result mal_context_uninit(mal_context* pContext) if (pContext == NULL) return MAL_INVALID_ARGS; switch (pContext->backend) { - #ifdef MAL_ENABLE_WASAPI + #ifdef MAL_HAS_WASAPI case mal_backend_wasapi: { return mal_context_uninit__wasapi(pContext); } break; #endif - #ifdef MAL_ENABLE_DSOUND + #ifdef MAL_HAS_DSOUND case mal_backend_dsound: { return mal_context_uninit__dsound(pContext); } break; #endif - #ifdef MAL_ENABLE_WINMM + #ifdef MAL_HAS_WINMM case mal_backend_winmm: { return mal_context_uninit__winmm(pContext); } break; #endif - #ifdef MAL_ENABLE_ALSA + #ifdef MAL_HAS_ALSA case mal_backend_alsa: { return mal_context_uninit__alsa(pContext); } break; #endif - #ifdef MAL_ENABLE_OSS + #ifdef MAL_HAS_OSS case mal_backend_oss: { return mal_context_uninit__oss(pContext); } break; #endif - #ifdef MAL_ENABLE_OPENSL + #ifdef MAL_HAS_OPENSL case mal_backend_opensl: { return mal_context_uninit__opensl(pContext); } break; #endif - #ifdef MAL_ENABLE_OPENAL + #ifdef MAL_HAS_OPENAL case mal_backend_openal: { return mal_context_uninit__openal(pContext); } break; #endif - #ifdef MAL_ENABLE_NULL + #ifdef MAL_HAS_NULL case mal_backend_null: { return mal_context_uninit__null(pContext); @@ -8660,49 +8706,49 @@ mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, ma switch (pContext->backend) { - #ifdef MAL_ENABLE_WASAPI + #ifdef MAL_HAS_WASAPI case mal_backend_wasapi: { return mal_enumerate_devices__wasapi(pContext, type, pCount, pInfo); } break; #endif - #ifdef MAL_ENABLE_DSOUND + #ifdef MAL_HAS_DSOUND case mal_backend_dsound: { return mal_enumerate_devices__dsound(pContext, type, pCount, pInfo); } break; #endif - #ifdef MAL_ENABLE_WINMM + #ifdef MAL_HAS_WINMM case mal_backend_winmm: { return mal_enumerate_devices__winmm(pContext, type, pCount, pInfo); } break; #endif - #ifdef MAL_ENABLE_ALSA + #ifdef MAL_HAS_ALSA case mal_backend_alsa: { return mal_enumerate_devices__alsa(pContext, type, pCount, pInfo); } break; #endif - #ifdef MAL_ENABLE_OSS + #ifdef MAL_HAS_OSS case mal_backend_oss: { return mal_enumerate_devices__oss(pContext, type, pCount, pInfo); } break; #endif - #ifdef MAL_ENABLE_OPENSL + #ifdef MAL_HAS_OPENSL case mal_backend_opensl: { return mal_enumerate_devices__opensl(pContext, type, pCount, pInfo); } break; #endif - #ifdef MAL_ENABLE_OPENAL + #ifdef MAL_HAS_OPENAL case mal_backend_openal: { return mal_enumerate_devices__openal(pContext, type, pCount, pInfo); } break; #endif - #ifdef MAL_ENABLE_NULL + #ifdef MAL_HAS_NULL case mal_backend_null: { return mal_enumerate_devices__null(pContext, type, pCount, pInfo); @@ -8819,49 +8865,49 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi mal_result result = MAL_NO_BACKEND; switch (pContext->backend) { - #ifdef MAL_ENABLE_WASAPI + #ifdef MAL_HAS_WASAPI case mal_backend_wasapi: { result = mal_device_init__wasapi(pContext, type, pDeviceID, &config, pDevice); } break; #endif - #ifdef MAL_ENABLE_DSOUND + #ifdef MAL_HAS_DSOUND case mal_backend_dsound: { result = mal_device_init__dsound(pContext, type, pDeviceID, &config, pDevice); } break; #endif - #ifdef MAL_ENABLE_WINMM + #ifdef MAL_HAS_WINMM case mal_backend_winmm: { result = mal_device_init__winmm(pContext, type, pDeviceID, &config, pDevice); } break; #endif - #ifdef MAL_ENABLE_ALSA + #ifdef MAL_HAS_ALSA case mal_backend_alsa: { result = mal_device_init__alsa(pContext, type, pDeviceID, &config, pDevice); } break; #endif - #ifdef MAL_ENABLE_OSS + #ifdef MAL_HAS_OSS case mal_backend_oss: { result = mal_device_init__oss(pContext, type, pDeviceID, &config, pDevice); } break; #endif - #ifdef MAL_ENABLE_OPENSL + #ifdef MAL_HAS_OPENSL case mal_backend_opensl: { result = mal_device_init__opensl(pContext, type, pDeviceID, &config, pDevice); } break; #endif - #ifdef MAL_ENABLE_OPENAL + #ifdef MAL_HAS_OPENAL case mal_backend_openal: { result = mal_device_init__openal(pContext, type, pDeviceID, &config, pDevice); } break; #endif - #ifdef MAL_ENABLE_NULL + #ifdef MAL_HAS_NULL case mal_backend_null: { result = mal_device_init__null(pContext, type, pDeviceID, &config, pDevice); @@ -8949,42 +8995,42 @@ void mal_device_uninit(mal_device* pDevice) mal_event_uninit(&pDevice->wakeupEvent); mal_mutex_uninit(&pDevice->lock); -#ifdef MAL_ENABLE_WASAPI +#ifdef MAL_HAS_WASAPI if (pDevice->pContext->backend == mal_backend_wasapi) { mal_device_uninit__wasapi(pDevice); } #endif -#ifdef MAL_ENABLE_DSOUND +#ifdef MAL_HAS_DSOUND if (pDevice->pContext->backend == mal_backend_dsound) { mal_device_uninit__dsound(pDevice); } #endif -#ifdef MAL_ENABLE_WINMM +#ifdef MAL_HAS_WINMM if (pDevice->pContext->backend == mal_backend_winmm) { mal_device_uninit__winmm(pDevice); } #endif -#ifdef MAL_ENABLE_ALSA +#ifdef MAL_HAS_ALSA if (pDevice->pContext->backend == mal_backend_alsa) { mal_device_uninit__alsa(pDevice); } #endif -#ifdef MAL_ENABLE_OSS +#ifdef MAL_HAS_OSS if (pDevice->pContext->backend == mal_backend_oss) { mal_device_uninit__oss(pDevice); } #endif -#ifdef MAL_ENABLE_OPENSL +#ifdef MAL_HAS_OPENSL if (pDevice->pContext->backend == mal_backend_opensl) { mal_device_uninit__opensl(pDevice); } #endif -#ifdef MAL_ENABLE_OPENAL +#ifdef MAL_HAS_OPENAL if (pDevice->pContext->backend == mal_backend_openal) { mal_device_uninit__openal(pDevice); } #endif -#ifdef MAL_ENABLE_NULL +#ifdef MAL_HAS_NULL if (pDevice->pContext->backend == mal_backend_null) { mal_device_uninit__null(pDevice); } @@ -9039,7 +9085,7 @@ mal_result mal_device_start(mal_device* pDevice) mal_device__set_state(pDevice, MAL_STATE_STARTING); // Asynchronous backends need to be handled differently. -#ifdef MAL_ENABLE_OPENSL +#ifdef MAL_HAS_OPENSL if (pDevice->pContext->backend == mal_backend_opensl) { mal_device__start_backend__opensl(pDevice); mal_device__set_state(pDevice, MAL_STATE_STARTED); @@ -9090,7 +9136,7 @@ mal_result mal_device_stop(mal_device* pDevice) // There's no need to wake up the thread like we do when starting. // Asynchronous backends need to be handled differently. -#ifdef MAL_ENABLE_OPENSL +#ifdef MAL_HAS_OPENSL if (pDevice->pContext->backend == mal_backend_opensl) { mal_device__stop_backend__opensl(pDevice); } else @@ -10514,6 +10560,9 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) // need to update. // - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively. // - API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent. +// - Simplify the build system further for when development packages for various backends are not installed. +// With this change, when the compiler supports __has_include, backends without the relevant development +// packages installed will be ignored. This fixes the build for old versions of MinGW. // - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of // audio data to a different format. // - Improvements to f32 -> u8/s16/s24/s32 conversion routines. From a6877c82c6ee7ecdae0c4c94fbbbfd0793985ce4 Mon Sep 17 00:00:00 2001 From: Ray San Date: Fri, 17 Nov 2017 18:30:19 +0100 Subject: [PATCH 018/139] Added alternative license to rgif.h library Just in case of legal conflict with public domain software, added MIT alternative license. --- src/external/rgif.h | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/external/rgif.h b/src/external/rgif.h index e524b375..8a32ef61 100644 --- a/src/external/rgif.h +++ b/src/external/rgif.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* rgif.h original implementation by Charlie Tangora [ctangora -at- gmail -dot- com] +* rgif.h original implementation (gif.h) by Charlie Tangora [ctangora -at- gmail -dot- com] * adapted to C99, reformatted and renamed by Ramon Santamaria (@raysan5) * * This file offers a simple, very limited way to create animated GIFs directly in code. @@ -28,7 +28,32 @@ * 3) Finally, call GifEnd() to close the file handle and free memory. * * -* LICENSE: public domain (www.unlicense.org) +* LICENSE: This software is available under 2 licenses -- choose whichever you prefer +* +* ALTERNATIVE A - MIT License +* +* Copyright (c) 2017 Ramon Santamaria +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of +* this software and associated documentation files (the "Software"), to deal in +* the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is furnished to do +* so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* ------------------------------------------------------------------------------ +* +* ALTERNATIVE B - public domain (www.unlicense.org) * * This is free and unencumbered software released into the public domain. * Anyone is free to copy, modify, publish, use, compile, sell, or distribute this From e2e4b8df28a80a2514308177a2b9e7604455a93b Mon Sep 17 00:00:00 2001 From: Ray San Date: Fri, 17 Nov 2017 18:42:39 +0100 Subject: [PATCH 019/139] Remove unneeded glfw dependencies Only required by examples --- src/external/glfw/deps/KHR/khrplatform.h | 282 - src/external/glfw/deps/getopt.c | 230 - src/external/glfw/deps/getopt.h | 57 - src/external/glfw/deps/glad.c | 1678 -- src/external/glfw/deps/glad/glad.h | 3680 --- src/external/glfw/deps/linmath.h | 574 - src/external/glfw/deps/nuklear.h | 23590 ------------------ src/external/glfw/deps/nuklear_glfw_gl2.h | 372 - src/external/glfw/deps/stb_image_write.h | 1048 - src/external/glfw/deps/tinycthread.c | 594 - src/external/glfw/deps/tinycthread.h | 443 - src/external/glfw/deps/vulkan/vk_platform.h | 120 - src/external/glfw/deps/vulkan/vulkan.h | 4763 ---- 13 files changed, 37431 deletions(-) delete mode 100644 src/external/glfw/deps/KHR/khrplatform.h delete mode 100644 src/external/glfw/deps/getopt.c delete mode 100644 src/external/glfw/deps/getopt.h delete mode 100644 src/external/glfw/deps/glad.c delete mode 100644 src/external/glfw/deps/glad/glad.h delete mode 100644 src/external/glfw/deps/linmath.h delete mode 100644 src/external/glfw/deps/nuklear.h delete mode 100644 src/external/glfw/deps/nuklear_glfw_gl2.h delete mode 100644 src/external/glfw/deps/stb_image_write.h delete mode 100644 src/external/glfw/deps/tinycthread.c delete mode 100644 src/external/glfw/deps/tinycthread.h delete mode 100644 src/external/glfw/deps/vulkan/vk_platform.h delete mode 100644 src/external/glfw/deps/vulkan/vulkan.h diff --git a/src/external/glfw/deps/KHR/khrplatform.h b/src/external/glfw/deps/KHR/khrplatform.h deleted file mode 100644 index c9e6f17d..00000000 --- a/src/external/glfw/deps/KHR/khrplatform.h +++ /dev/null @@ -1,282 +0,0 @@ -#ifndef __khrplatform_h_ -#define __khrplatform_h_ - -/* -** Copyright (c) 2008-2009 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Khronos platform-specific types and definitions. - * - * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $ - * - * Adopters may modify this file to suit their platform. Adopters are - * encouraged to submit platform specific modifications to the Khronos - * group so that they can be included in future versions of this file. - * Please submit changes by sending them to the public Khronos Bugzilla - * (http://khronos.org/bugzilla) by filing a bug against product - * "Khronos (general)" component "Registry". - * - * A predefined template which fills in some of the bug fields can be - * reached using http://tinyurl.com/khrplatform-h-bugreport, but you - * must create a Bugzilla login first. - * - * - * See the Implementer's Guidelines for information about where this file - * should be located on your system and for more details of its use: - * http://www.khronos.org/registry/implementers_guide.pdf - * - * This file should be included as - * #include - * by Khronos client API header files that use its types and defines. - * - * The types in khrplatform.h should only be used to define API-specific types. - * - * Types defined in khrplatform.h: - * khronos_int8_t signed 8 bit - * khronos_uint8_t unsigned 8 bit - * khronos_int16_t signed 16 bit - * khronos_uint16_t unsigned 16 bit - * khronos_int32_t signed 32 bit - * khronos_uint32_t unsigned 32 bit - * khronos_int64_t signed 64 bit - * khronos_uint64_t unsigned 64 bit - * khronos_intptr_t signed same number of bits as a pointer - * khronos_uintptr_t unsigned same number of bits as a pointer - * khronos_ssize_t signed size - * khronos_usize_t unsigned size - * khronos_float_t signed 32 bit floating point - * khronos_time_ns_t unsigned 64 bit time in nanoseconds - * khronos_utime_nanoseconds_t unsigned time interval or absolute time in - * nanoseconds - * khronos_stime_nanoseconds_t signed time interval in nanoseconds - * khronos_boolean_enum_t enumerated boolean type. This should - * only be used as a base type when a client API's boolean type is - * an enum. Client APIs which use an integer or other type for - * booleans cannot use this as the base type for their boolean. - * - * Tokens defined in khrplatform.h: - * - * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. - * - * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. - * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. - * - * Calling convention macros defined in this file: - * KHRONOS_APICALL - * KHRONOS_APIENTRY - * KHRONOS_APIATTRIBUTES - * - * These may be used in function prototypes as: - * - * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( - * int arg1, - * int arg2) KHRONOS_APIATTRIBUTES; - */ - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APICALL - *------------------------------------------------------------------------- - * This precedes the return type of the function in the function prototype. - */ -#if defined(_WIN32) && !defined(__SCITECH_SNAP__) -# define KHRONOS_APICALL __declspec(dllimport) -#elif defined (__SYMBIAN32__) -# define KHRONOS_APICALL IMPORT_C -#else -# define KHRONOS_APICALL -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APIENTRY - *------------------------------------------------------------------------- - * This follows the return type of the function and precedes the function - * name in the function prototype. - */ -#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) - /* Win32 but not WinCE */ -# define KHRONOS_APIENTRY __stdcall -#else -# define KHRONOS_APIENTRY -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APIATTRIBUTES - *------------------------------------------------------------------------- - * This follows the closing parenthesis of the function prototype arguments. - */ -#if defined (__ARMCC_2__) -#define KHRONOS_APIATTRIBUTES __softfp -#else -#define KHRONOS_APIATTRIBUTES -#endif - -/*------------------------------------------------------------------------- - * basic type definitions - *-----------------------------------------------------------------------*/ -#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) - - -/* - * Using - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(__VMS ) || defined(__sgi) - -/* - * Using - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) - -/* - * Win32 - */ -typedef __int32 khronos_int32_t; -typedef unsigned __int32 khronos_uint32_t; -typedef __int64 khronos_int64_t; -typedef unsigned __int64 khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(__sun__) || defined(__digital__) - -/* - * Sun or Digital - */ -typedef int khronos_int32_t; -typedef unsigned int khronos_uint32_t; -#if defined(__arch64__) || defined(_LP64) -typedef long int khronos_int64_t; -typedef unsigned long int khronos_uint64_t; -#else -typedef long long int khronos_int64_t; -typedef unsigned long long int khronos_uint64_t; -#endif /* __arch64__ */ -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif 0 - -/* - * Hypothetical platform with no float or int64 support - */ -typedef int khronos_int32_t; -typedef unsigned int khronos_uint32_t; -#define KHRONOS_SUPPORT_INT64 0 -#define KHRONOS_SUPPORT_FLOAT 0 - -#else - -/* - * Generic fallback - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#endif - - -/* - * Types that are (so far) the same on all platforms - */ -typedef signed char khronos_int8_t; -typedef unsigned char khronos_uint8_t; -typedef signed short int khronos_int16_t; -typedef unsigned short int khronos_uint16_t; - -/* - * Types that differ between LLP64 and LP64 architectures - in LLP64, - * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears - * to be the only LLP64 architecture in current use. - */ -#ifdef _WIN64 -typedef signed long long int khronos_intptr_t; -typedef unsigned long long int khronos_uintptr_t; -typedef signed long long int khronos_ssize_t; -typedef unsigned long long int khronos_usize_t; -#else -typedef signed long int khronos_intptr_t; -typedef unsigned long int khronos_uintptr_t; -typedef signed long int khronos_ssize_t; -typedef unsigned long int khronos_usize_t; -#endif - -#if KHRONOS_SUPPORT_FLOAT -/* - * Float type - */ -typedef float khronos_float_t; -#endif - -#if KHRONOS_SUPPORT_INT64 -/* Time types - * - * These types can be used to represent a time interval in nanoseconds or - * an absolute Unadjusted System Time. Unadjusted System Time is the number - * of nanoseconds since some arbitrary system event (e.g. since the last - * time the system booted). The Unadjusted System Time is an unsigned - * 64 bit value that wraps back to 0 every 584 years. Time intervals - * may be either signed or unsigned. - */ -typedef khronos_uint64_t khronos_utime_nanoseconds_t; -typedef khronos_int64_t khronos_stime_nanoseconds_t; -#endif - -/* - * Dummy value used to pad enum types to 32 bits. - */ -#ifndef KHRONOS_MAX_ENUM -#define KHRONOS_MAX_ENUM 0x7FFFFFFF -#endif - -/* - * Enumerated boolean type - * - * Values other than zero should be considered to be true. Therefore - * comparisons should not be made against KHRONOS_TRUE. - */ -typedef enum { - KHRONOS_FALSE = 0, - KHRONOS_TRUE = 1, - KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM -} khronos_boolean_enum_t; - -#endif /* __khrplatform_h_ */ diff --git a/src/external/glfw/deps/getopt.c b/src/external/glfw/deps/getopt.c deleted file mode 100644 index 9743046f..00000000 --- a/src/external/glfw/deps/getopt.c +++ /dev/null @@ -1,230 +0,0 @@ -/* Copyright (c) 2012, Kim Gräsman - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Kim Gräsman nor the names of contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "getopt.h" - -#include -#include - -const int no_argument = 0; -const int required_argument = 1; -const int optional_argument = 2; - -char* optarg; -int optopt; -/* The variable optind [...] shall be initialized to 1 by the system. */ -int optind = 1; -int opterr; - -static char* optcursor = NULL; - -/* Implemented based on [1] and [2] for optional arguments. - optopt is handled FreeBSD-style, per [3]. - Other GNU and FreeBSD extensions are purely accidental. - -[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html -[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html -[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE -*/ -int getopt(int argc, char* const argv[], const char* optstring) { - int optchar = -1; - const char* optdecl = NULL; - - optarg = NULL; - opterr = 0; - optopt = 0; - - /* Unspecified, but we need it to avoid overrunning the argv bounds. */ - if (optind >= argc) - goto no_more_optchars; - - /* If, when getopt() is called argv[optind] is a null pointer, getopt() - shall return -1 without changing optind. */ - if (argv[optind] == NULL) - goto no_more_optchars; - - /* If, when getopt() is called *argv[optind] is not the character '-', - getopt() shall return -1 without changing optind. */ - if (*argv[optind] != '-') - goto no_more_optchars; - - /* If, when getopt() is called argv[optind] points to the string "-", - getopt() shall return -1 without changing optind. */ - if (strcmp(argv[optind], "-") == 0) - goto no_more_optchars; - - /* If, when getopt() is called argv[optind] points to the string "--", - getopt() shall return -1 after incrementing optind. */ - if (strcmp(argv[optind], "--") == 0) { - ++optind; - goto no_more_optchars; - } - - if (optcursor == NULL || *optcursor == '\0') - optcursor = argv[optind] + 1; - - optchar = *optcursor; - - /* FreeBSD: The variable optopt saves the last known option character - returned by getopt(). */ - optopt = optchar; - - /* The getopt() function shall return the next option character (if one is - found) from argv that matches a character in optstring, if there is - one that matches. */ - optdecl = strchr(optstring, optchar); - if (optdecl) { - /* [I]f a character is followed by a colon, the option takes an - argument. */ - if (optdecl[1] == ':') { - optarg = ++optcursor; - if (*optarg == '\0') { - /* GNU extension: Two colons mean an option takes an - optional arg; if there is text in the current argv-element - (i.e., in the same word as the option name itself, for example, - "-oarg"), then it is returned in optarg, otherwise optarg is set - to zero. */ - if (optdecl[2] != ':') { - /* If the option was the last character in the string pointed to by - an element of argv, then optarg shall contain the next element - of argv, and optind shall be incremented by 2. If the resulting - value of optind is greater than argc, this indicates a missing - option-argument, and getopt() shall return an error indication. - - Otherwise, optarg shall point to the string following the - option character in that element of argv, and optind shall be - incremented by 1. - */ - if (++optind < argc) { - optarg = argv[optind]; - } else { - /* If it detects a missing option-argument, it shall return the - colon character ( ':' ) if the first character of optstring - was a colon, or a question-mark character ( '?' ) otherwise. - */ - optarg = NULL; - optchar = (optstring[0] == ':') ? ':' : '?'; - } - } else { - optarg = NULL; - } - } - - optcursor = NULL; - } - } else { - /* If getopt() encounters an option character that is not contained in - optstring, it shall return the question-mark ( '?' ) character. */ - optchar = '?'; - } - - if (optcursor == NULL || *++optcursor == '\0') - ++optind; - - return optchar; - -no_more_optchars: - optcursor = NULL; - return -1; -} - -/* Implementation based on [1]. - -[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html -*/ -int getopt_long(int argc, char* const argv[], const char* optstring, - const struct option* longopts, int* longindex) { - const struct option* o = longopts; - const struct option* match = NULL; - int num_matches = 0; - size_t argument_name_length = 0; - const char* current_argument = NULL; - int retval = -1; - - optarg = NULL; - optopt = 0; - - if (optind >= argc) - return -1; - - if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) - return getopt(argc, argv, optstring); - - /* It's an option; starts with -- and is longer than two chars. */ - current_argument = argv[optind] + 2; - argument_name_length = strcspn(current_argument, "="); - for (; o->name; ++o) { - if (strncmp(o->name, current_argument, argument_name_length) == 0) { - match = o; - ++num_matches; - } - } - - if (num_matches == 1) { - /* If longindex is not NULL, it points to a variable which is set to the - index of the long option relative to longopts. */ - if (longindex) - *longindex = (int) (match - longopts); - - /* If flag is NULL, then getopt_long() shall return val. - Otherwise, getopt_long() returns 0, and flag shall point to a variable - which shall be set to val if the option is found, but left unchanged if - the option is not found. */ - if (match->flag) - *(match->flag) = match->val; - - retval = match->flag ? 0 : match->val; - - if (match->has_arg != no_argument) { - optarg = strchr(argv[optind], '='); - if (optarg != NULL) - ++optarg; - - if (match->has_arg == required_argument) { - /* Only scan the next argv for required arguments. Behavior is not - specified, but has been observed with Ubuntu and Mac OSX. */ - if (optarg == NULL && ++optind < argc) { - optarg = argv[optind]; - } - - if (optarg == NULL) - retval = ':'; - } - } else if (strchr(argv[optind], '=')) { - /* An argument was provided to a non-argument option. - I haven't seen this specified explicitly, but both GNU and BSD-based - implementations show this behavior. - */ - retval = '?'; - } - } else { - /* Unknown option or ambiguous match. */ - retval = '?'; - } - - ++optind; - return retval; -} diff --git a/src/external/glfw/deps/getopt.h b/src/external/glfw/deps/getopt.h deleted file mode 100644 index e1eb540f..00000000 --- a/src/external/glfw/deps/getopt.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright (c) 2012, Kim Gräsman - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Kim Gräsman nor the names of contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef INCLUDED_GETOPT_PORT_H -#define INCLUDED_GETOPT_PORT_H - -#if defined(__cplusplus) -extern "C" { -#endif - -extern const int no_argument; -extern const int required_argument; -extern const int optional_argument; - -extern char* optarg; -extern int optind, opterr, optopt; - -struct option { - const char* name; - int has_arg; - int* flag; - int val; -}; - -int getopt(int argc, char* const argv[], const char* optstring); - -int getopt_long(int argc, char* const argv[], - const char* optstring, const struct option* longopts, int* longindex); - -#if defined(__cplusplus) -} -#endif - -#endif // INCLUDED_GETOPT_PORT_H diff --git a/src/external/glfw/deps/glad.c b/src/external/glfw/deps/glad.c deleted file mode 100644 index 10b0a00e..00000000 --- a/src/external/glfw/deps/glad.c +++ /dev/null @@ -1,1678 +0,0 @@ -/* - - OpenGL loader generated by glad 0.1.12a0 on Fri Sep 23 13:36:15 2016. - - Language/Generator: C/C++ - Specification: gl - APIs: gl=3.2 - Profile: compatibility - Extensions: - GL_ARB_multisample, - GL_ARB_robustness, - GL_KHR_debug - Loader: False - Local files: False - Omit khrplatform: False - - Commandline: - --profile="compatibility" --api="gl=3.2" --generator="c" --spec="gl" --no-loader --extensions="GL_ARB_multisample,GL_ARB_robustness,GL_KHR_debug" - Online: - http://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&api=gl%3D3.2&extensions=GL_ARB_multisample&extensions=GL_ARB_robustness&extensions=GL_KHR_debug -*/ - -#include -#include -#include -#include - -struct gladGLversionStruct GLVersion; - -#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) -#define _GLAD_IS_SOME_NEW_VERSION 1 -#endif - -static int max_loaded_major; -static int max_loaded_minor; - -static const char *exts = NULL; -static int num_exts_i = 0; -static const char **exts_i = NULL; - -static int get_exts(void) { -#ifdef _GLAD_IS_SOME_NEW_VERSION - if(max_loaded_major < 3) { -#endif - exts = (const char *)glGetString(GL_EXTENSIONS); -#ifdef _GLAD_IS_SOME_NEW_VERSION - } else { - int index; - - num_exts_i = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); - if (num_exts_i > 0) { - exts_i = (const char **)realloc((void *)exts_i, num_exts_i * sizeof *exts_i); - } - - if (exts_i == NULL) { - return 0; - } - - for(index = 0; index < num_exts_i; index++) { - exts_i[index] = (const char*)glGetStringi(GL_EXTENSIONS, index); - } - } -#endif - return 1; -} - -static void free_exts(void) { - if (exts_i != NULL) { - free((char **)exts_i); - exts_i = NULL; - } -} - -static int has_ext(const char *ext) { -#ifdef _GLAD_IS_SOME_NEW_VERSION - if(max_loaded_major < 3) { -#endif - const char *extensions; - const char *loc; - const char *terminator; - extensions = exts; - if(extensions == NULL || ext == NULL) { - return 0; - } - - while(1) { - loc = strstr(extensions, ext); - if(loc == NULL) { - return 0; - } - - terminator = loc + strlen(ext); - if((loc == extensions || *(loc - 1) == ' ') && - (*terminator == ' ' || *terminator == '\0')) { - return 1; - } - extensions = terminator; - } -#ifdef _GLAD_IS_SOME_NEW_VERSION - } else { - int index; - - for(index = 0; index < num_exts_i; index++) { - const char *e = exts_i[index]; - - if(strcmp(e, ext) == 0) { - return 1; - } - } - } -#endif - - return 0; -} -int GLAD_GL_VERSION_1_0; -int GLAD_GL_VERSION_1_1; -int GLAD_GL_VERSION_1_2; -int GLAD_GL_VERSION_1_3; -int GLAD_GL_VERSION_1_4; -int GLAD_GL_VERSION_1_5; -int GLAD_GL_VERSION_2_0; -int GLAD_GL_VERSION_2_1; -int GLAD_GL_VERSION_3_0; -int GLAD_GL_VERSION_3_1; -int GLAD_GL_VERSION_3_2; -PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; -PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; -PFNGLWINDOWPOS2SPROC glad_glWindowPos2s; -PFNGLWINDOWPOS2IPROC glad_glWindowPos2i; -PFNGLWINDOWPOS2FPROC glad_glWindowPos2f; -PFNGLWINDOWPOS2DPROC glad_glWindowPos2d; -PFNGLVERTEX2FVPROC glad_glVertex2fv; -PFNGLINDEXIPROC glad_glIndexi; -PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; -PFNGLRECTDVPROC glad_glRectdv; -PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; -PFNGLEVALCOORD2DPROC glad_glEvalCoord2d; -PFNGLEVALCOORD2FPROC glad_glEvalCoord2f; -PFNGLINDEXDPROC glad_glIndexd; -PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; -PFNGLINDEXFPROC glad_glIndexf; -PFNGLLINEWIDTHPROC glad_glLineWidth; -PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; -PFNGLGETMAPFVPROC glad_glGetMapfv; -PFNGLINDEXSPROC glad_glIndexs; -PFNGLCOMPILESHADERPROC glad_glCompileShader; -PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; -PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv; -PFNGLINDEXFVPROC glad_glIndexfv; -PFNGLFOGIVPROC glad_glFogiv; -PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; -PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv; -PFNGLLIGHTMODELIVPROC glad_glLightModeliv; -PFNGLCOLOR4UIPROC glad_glColor4ui; -PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv; -PFNGLFOGFVPROC glad_glFogfv; -PFNGLENABLEIPROC glad_glEnablei; -PFNGLVERTEX4IVPROC glad_glVertex4iv; -PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv; -PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv; -PFNGLCREATESHADERPROC glad_glCreateShader; -PFNGLISBUFFERPROC glad_glIsBuffer; -PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; -PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; -PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; -PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; -PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; -PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; -PFNGLVERTEX4FVPROC glad_glVertex4fv; -PFNGLBINDTEXTUREPROC glad_glBindTexture; -PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; -PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv; -PFNGLSAMPLEMASKIPROC glad_glSampleMaski; -PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; -PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv; -PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; -PFNGLPOINTSIZEPROC glad_glPointSize; -PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; -PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; -PFNGLCOLOR4BVPROC glad_glColor4bv; -PFNGLRASTERPOS2FPROC glad_glRasterPos2f; -PFNGLRASTERPOS2DPROC glad_glRasterPos2d; -PFNGLLOADIDENTITYPROC glad_glLoadIdentity; -PFNGLRASTERPOS2IPROC glad_glRasterPos2i; -PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; -PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; -PFNGLCOLOR3BPROC glad_glColor3b; -PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; -PFNGLEDGEFLAGPROC glad_glEdgeFlag; -PFNGLVERTEX3DPROC glad_glVertex3d; -PFNGLVERTEX3FPROC glad_glVertex3f; -PFNGLVERTEX3IPROC glad_glVertex3i; -PFNGLCOLOR3IPROC glad_glColor3i; -PFNGLUNIFORM3FPROC glad_glUniform3f; -PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; -PFNGLCOLOR3SPROC glad_glColor3s; -PFNGLVERTEX3SPROC glad_glVertex3s; -PFNGLCOLORMASKIPROC glad_glColorMaski; -PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; -PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv; -PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; -PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; -PFNGLVERTEX2IVPROC glad_glVertex2iv; -PFNGLCOLOR3SVPROC glad_glColor3sv; -PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; -PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; -PFNGLNORMALPOINTERPROC glad_glNormalPointer; -PFNGLVERTEX4SVPROC glad_glVertex4sv; -PFNGLPASSTHROUGHPROC glad_glPassThrough; -PFNGLFOGIPROC glad_glFogi; -PFNGLBEGINPROC glad_glBegin; -PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv; -PFNGLCOLOR3UBVPROC glad_glColor3ubv; -PFNGLVERTEXPOINTERPROC glad_glVertexPointer; -PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv; -PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; -PFNGLDRAWARRAYSPROC glad_glDrawArrays; -PFNGLUNIFORM1UIPROC glad_glUniform1ui; -PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d; -PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f; -PFNGLLIGHTFVPROC glad_glLightfv; -PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; -PFNGLCLEARPROC glad_glClear; -PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i; -PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; -PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s; -PFNGLISENABLEDPROC glad_glIsEnabled; -PFNGLSTENCILOPPROC glad_glStencilOp; -PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; -PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; -PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; -PFNGLTRANSLATEFPROC glad_glTranslatef; -PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; -PFNGLTRANSLATEDPROC glad_glTranslated; -PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv; -PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; -PFNGLTEXIMAGE1DPROC glad_glTexImage1D; -PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; -PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv; -PFNGLGETMATERIALFVPROC glad_glGetMaterialfv; -PFNGLGETTEXIMAGEPROC glad_glGetTexImage; -PFNGLFOGCOORDFVPROC glad_glFogCoordfv; -PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv; -PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; -PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; -PFNGLINDEXSVPROC glad_glIndexsv; -PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; -PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; -PFNGLVERTEX3IVPROC glad_glVertex3iv; -PFNGLBITMAPPROC glad_glBitmap; -PFNGLMATERIALIPROC glad_glMateriali; -PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; -PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; -PFNGLGETQUERYIVPROC glad_glGetQueryiv; -PFNGLTEXCOORD4FPROC glad_glTexCoord4f; -PFNGLTEXCOORD4DPROC glad_glTexCoord4d; -PFNGLTEXCOORD4IPROC glad_glTexCoord4i; -PFNGLMATERIALFPROC glad_glMaterialf; -PFNGLTEXCOORD4SPROC glad_glTexCoord4s; -PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; -PFNGLISSHADERPROC glad_glIsShader; -PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s; -PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; -PFNGLVERTEX3DVPROC glad_glVertex3dv; -PFNGLGETINTEGER64VPROC glad_glGetInteger64v; -PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; -PFNGLENABLEPROC glad_glEnable; -PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; -PFNGLCOLOR4FVPROC glad_glColor4fv; -PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv; -PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv; -PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; -PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv; -PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i; -PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv; -PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv; -PFNGLTEXGENFPROC glad_glTexGenf; -PFNGLGETPOINTERVPROC glad_glGetPointerv; -PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; -PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; -PFNGLNORMAL3FVPROC glad_glNormal3fv; -PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s; -PFNGLDEPTHRANGEPROC glad_glDepthRange; -PFNGLFRUSTUMPROC glad_glFrustum; -PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv; -PFNGLDRAWBUFFERPROC glad_glDrawBuffer; -PFNGLPUSHMATRIXPROC glad_glPushMatrix; -PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv; -PFNGLORTHOPROC glad_glOrtho; -PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; -PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv; -PFNGLCLEARINDEXPROC glad_glClearIndex; -PFNGLMAP1DPROC glad_glMap1d; -PFNGLMAP1FPROC glad_glMap1f; -PFNGLFLUSHPROC glad_glFlush; -PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; -PFNGLINDEXIVPROC glad_glIndexiv; -PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv; -PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; -PFNGLPIXELZOOMPROC glad_glPixelZoom; -PFNGLFENCESYNCPROC glad_glFenceSync; -PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; -PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; -PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; -PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; -PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; -PFNGLLIGHTIPROC glad_glLighti; -PFNGLLIGHTFPROC glad_glLightf; -PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; -PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; -PFNGLCLAMPCOLORPROC glad_glClampColor; -PFNGLUNIFORM4IVPROC glad_glUniform4iv; -PFNGLCLEARSTENCILPROC glad_glClearStencil; -PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv; -PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv; -PFNGLGENTEXTURESPROC glad_glGenTextures; -PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv; -PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; -PFNGLINDEXPOINTERPROC glad_glIndexPointer; -PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; -PFNGLISSYNCPROC glad_glIsSync; -PFNGLVERTEX2FPROC glad_glVertex2f; -PFNGLVERTEX2DPROC glad_glVertex2d; -PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; -PFNGLUNIFORM2IPROC glad_glUniform2i; -PFNGLMAPGRID2DPROC glad_glMapGrid2d; -PFNGLMAPGRID2FPROC glad_glMapGrid2f; -PFNGLVERTEX2IPROC glad_glVertex2i; -PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; -PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; -PFNGLVERTEX2SPROC glad_glVertex2s; -PFNGLNORMAL3BVPROC glad_glNormal3bv; -PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; -PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; -PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv; -PFNGLVERTEX3SVPROC glad_glVertex3sv; -PFNGLGENQUERIESPROC glad_glGenQueries; -PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv; -PFNGLTEXENVFPROC glad_glTexEnvf; -PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; -PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; -PFNGLFOGCOORDDPROC glad_glFogCoordd; -PFNGLFOGCOORDFPROC glad_glFogCoordf; -PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; -PFNGLTEXENVIPROC glad_glTexEnvi; -PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv; -PFNGLISENABLEDIPROC glad_glIsEnabledi; -PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; -PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv; -PFNGLUNIFORM2IVPROC glad_glUniform2iv; -PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; -PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; -PFNGLMATRIXMODEPROC glad_glMatrixMode; -PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer; -PFNGLGETMAPIVPROC glad_glGetMapiv; -PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; -PFNGLGETSHADERIVPROC glad_glGetShaderiv; -PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d; -PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f; -PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; -PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; -PFNGLCALLLISTPROC glad_glCallList; -PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv; -PFNGLGETDOUBLEVPROC glad_glGetDoublev; -PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv; -PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; -PFNGLLIGHTMODELFPROC glad_glLightModelf; -PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; -PFNGLVERTEX2SVPROC glad_glVertex2sv; -PFNGLLIGHTMODELIPROC glad_glLightModeli; -PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv; -PFNGLUNIFORM3FVPROC glad_glUniform3fv; -PFNGLPIXELSTOREIPROC glad_glPixelStorei; -PFNGLCALLLISTSPROC glad_glCallLists; -PFNGLMAPBUFFERPROC glad_glMapBuffer; -PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d; -PFNGLTEXCOORD3IPROC glad_glTexCoord3i; -PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv; -PFNGLRASTERPOS3IPROC glad_glRasterPos3i; -PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b; -PFNGLRASTERPOS3DPROC glad_glRasterPos3d; -PFNGLRASTERPOS3FPROC glad_glRasterPos3f; -PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; -PFNGLTEXCOORD3FPROC glad_glTexCoord3f; -PFNGLDELETESYNCPROC glad_glDeleteSync; -PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; -PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; -PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; -PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; -PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; -PFNGLTEXCOORD3SPROC glad_glTexCoord3s; -PFNGLUNIFORM3IVPROC glad_glUniform3iv; -PFNGLRASTERPOS3SPROC glad_glRasterPos3s; -PFNGLPOLYGONMODEPROC glad_glPolygonMode; -PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; -PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; -PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident; -PFNGLISLISTPROC glad_glIsList; -PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv; -PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv; -PFNGLCOLOR4SPROC glad_glColor4s; -PFNGLUSEPROGRAMPROC glad_glUseProgram; -PFNGLLINESTIPPLEPROC glad_glLineStipple; -PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv; -PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; -PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; -PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv; -PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; -PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; -PFNGLCOLOR4BPROC glad_glColor4b; -PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f; -PFNGLCOLOR4FPROC glad_glColor4f; -PFNGLCOLOR4DPROC glad_glColor4d; -PFNGLCOLOR4IPROC glad_glColor4i; -PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; -PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv; -PFNGLVERTEX2DVPROC glad_glVertex2dv; -PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv; -PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; -PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; -PFNGLFINISHPROC glad_glFinish; -PFNGLGETBOOLEANVPROC glad_glGetBooleanv; -PFNGLDELETESHADERPROC glad_glDeleteShader; -PFNGLDRAWELEMENTSPROC glad_glDrawElements; -PFNGLRASTERPOS2SPROC glad_glRasterPos2s; -PFNGLGETMAPDVPROC glad_glGetMapdv; -PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; -PFNGLMATERIALFVPROC glad_glMaterialfv; -PFNGLVIEWPORTPROC glad_glViewport; -PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; -PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; -PFNGLINDEXDVPROC glad_glIndexdv; -PFNGLTEXCOORD3DPROC glad_glTexCoord3d; -PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv; -PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; -PFNGLCLEARDEPTHPROC glad_glClearDepth; -PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; -PFNGLTEXPARAMETERFPROC glad_glTexParameterf; -PFNGLTEXPARAMETERIPROC glad_glTexParameteri; -PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; -PFNGLTEXBUFFERPROC glad_glTexBuffer; -PFNGLPOPNAMEPROC glad_glPopName; -PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; -PFNGLPIXELSTOREFPROC glad_glPixelStoref; -PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; -PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv; -PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv; -PFNGLRECTIPROC glad_glRecti; -PFNGLCOLOR4UBPROC glad_glColor4ub; -PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf; -PFNGLRECTFPROC glad_glRectf; -PFNGLRECTDPROC glad_glRectd; -PFNGLNORMAL3SVPROC glad_glNormal3sv; -PFNGLNEWLISTPROC glad_glNewList; -PFNGLCOLOR4USPROC glad_glColor4us; -PFNGLLINKPROGRAMPROC glad_glLinkProgram; -PFNGLHINTPROC glad_glHint; -PFNGLRECTSPROC glad_glRects; -PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv; -PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv; -PFNGLGETSTRINGPROC glad_glGetString; -PFNGLEDGEFLAGVPROC glad_glEdgeFlagv; -PFNGLDETACHSHADERPROC glad_glDetachShader; -PFNGLSCALEFPROC glad_glScalef; -PFNGLENDQUERYPROC glad_glEndQuery; -PFNGLSCALEDPROC glad_glScaled; -PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer; -PFNGLCOPYPIXELSPROC glad_glCopyPixels; -PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; -PFNGLPOPATTRIBPROC glad_glPopAttrib; -PFNGLDELETETEXTURESPROC glad_glDeleteTextures; -PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; -PFNGLDELETEQUERIESPROC glad_glDeleteQueries; -PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; -PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; -PFNGLINITNAMESPROC glad_glInitNames; -PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; -PFNGLCOLOR3DVPROC glad_glColor3dv; -PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; -PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; -PFNGLWAITSYNCPROC glad_glWaitSync; -PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; -PFNGLCOLORMATERIALPROC glad_glColorMaterial; -PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; -PFNGLUNIFORM1FPROC glad_glUniform1f; -PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; -PFNGLRENDERMODEPROC glad_glRenderMode; -PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; -PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv; -PFNGLUNIFORM1IPROC glad_glUniform1i; -PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; -PFNGLUNIFORM3IPROC glad_glUniform3i; -PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi; -PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; -PFNGLDISABLEPROC glad_glDisable; -PFNGLLOGICOPPROC glad_glLogicOp; -PFNGLEVALPOINT2PROC glad_glEvalPoint2; -PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf; -PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i; -PFNGLUNIFORM4UIPROC glad_glUniform4ui; -PFNGLCOLOR3FPROC glad_glColor3f; -PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; -PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv; -PFNGLRECTFVPROC glad_glRectfv; -PFNGLCULLFACEPROC glad_glCullFace; -PFNGLGETLIGHTFVPROC glad_glGetLightfv; -PFNGLCOLOR3DPROC glad_glColor3d; -PFNGLTEXGENDPROC glad_glTexGend; -PFNGLTEXGENIPROC glad_glTexGeni; -PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s; -PFNGLGETSTRINGIPROC glad_glGetStringi; -PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i; -PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f; -PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d; -PFNGLATTACHSHADERPROC glad_glAttachShader; -PFNGLFOGCOORDDVPROC glad_glFogCoorddv; -PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; -PFNGLGETTEXGENFVPROC glad_glGetTexGenfv; -PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer; -PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; -PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; -PFNGLTEXGENIVPROC glad_glTexGeniv; -PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv; -PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv; -PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture; -PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; -PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us; -PFNGLTEXENVFVPROC glad_glTexEnvfv; -PFNGLREADBUFFERPROC glad_glReadBuffer; -PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; -PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; -PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; -PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv; -PFNGLLIGHTMODELFVPROC glad_glLightModelfv; -PFNGLDELETELISTSPROC glad_glDeleteLists; -PFNGLGETCLIPPLANEPROC glad_glGetClipPlane; -PFNGLVERTEX4DVPROC glad_glVertex4dv; -PFNGLTEXCOORD2DPROC glad_glTexCoord2d; -PFNGLPOPMATRIXPROC glad_glPopMatrix; -PFNGLTEXCOORD2FPROC glad_glTexCoord2f; -PFNGLCOLOR4IVPROC glad_glColor4iv; -PFNGLINDEXUBVPROC glad_glIndexubv; -PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; -PFNGLTEXCOORD2IPROC glad_glTexCoord2i; -PFNGLRASTERPOS4DPROC glad_glRasterPos4d; -PFNGLRASTERPOS4FPROC glad_glRasterPos4f; -PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; -PFNGLTEXCOORD2SPROC glad_glTexCoord2s; -PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; -PFNGLVERTEX3FVPROC glad_glVertex3fv; -PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv; -PFNGLMATERIALIVPROC glad_glMaterialiv; -PFNGLISPROGRAMPROC glad_glIsProgram; -PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; -PFNGLVERTEX4SPROC glad_glVertex4s; -PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; -PFNGLNORMAL3DVPROC glad_glNormal3dv; -PFNGLUNIFORM4IPROC glad_glUniform4i; -PFNGLACTIVETEXTUREPROC glad_glActiveTexture; -PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; -PFNGLROTATEDPROC glad_glRotated; -PFNGLROTATEFPROC glad_glRotatef; -PFNGLVERTEX4IPROC glad_glVertex4i; -PFNGLREADPIXELSPROC glad_glReadPixels; -PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; -PFNGLLOADNAMEPROC glad_glLoadName; -PFNGLUNIFORM4FPROC glad_glUniform4f; -PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; -PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; -PFNGLSHADEMODELPROC glad_glShadeModel; -PFNGLMAPGRID1DPROC glad_glMapGrid1d; -PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; -PFNGLMAPGRID1FPROC glad_glMapGrid1f; -PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState; -PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv; -PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; -PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer; -PFNGLALPHAFUNCPROC glad_glAlphaFunc; -PFNGLUNIFORM1IVPROC glad_glUniform1iv; -PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv; -PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; -PFNGLSTENCILFUNCPROC glad_glStencilFunc; -PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv; -PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; -PFNGLCOLOR4UIVPROC glad_glColor4uiv; -PFNGLRECTIVPROC glad_glRectiv; -PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv; -PFNGLEVALMESH2PROC glad_glEvalMesh2; -PFNGLEVALMESH1PROC glad_glEvalMesh1; -PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer; -PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; -PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; -PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv; -PFNGLCOLOR4UBVPROC glad_glColor4ubv; -PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd; -PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf; -PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; -PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv; -PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; -PFNGLTEXENVIVPROC glad_glTexEnviv; -PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; -PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; -PFNGLGENBUFFERSPROC glad_glGenBuffers; -PFNGLSELECTBUFFERPROC glad_glSelectBuffer; -PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; -PFNGLPUSHATTRIBPROC glad_glPushAttrib; -PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; -PFNGLBLENDFUNCPROC glad_glBlendFunc; -PFNGLCREATEPROGRAMPROC glad_glCreateProgram; -PFNGLTEXIMAGE3DPROC glad_glTexImage3D; -PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; -PFNGLLIGHTIVPROC glad_glLightiv; -PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; -PFNGLTEXGENFVPROC glad_glTexGenfv; -PFNGLENDPROC glad_glEnd; -PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; -PFNGLSCISSORPROC glad_glScissor; -PFNGLCLIPPLANEPROC glad_glClipPlane; -PFNGLPUSHNAMEPROC glad_glPushName; -PFNGLTEXGENDVPROC glad_glTexGendv; -PFNGLINDEXUBPROC glad_glIndexub; -PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv; -PFNGLRASTERPOS4IPROC glad_glRasterPos4i; -PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd; -PFNGLCLEARCOLORPROC glad_glClearColor; -PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; -PFNGLNORMAL3SPROC glad_glNormal3s; -PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; -PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; -PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; -PFNGLBLENDCOLORPROC glad_glBlendColor; -PFNGLWINDOWPOS3DPROC glad_glWindowPos3d; -PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; -PFNGLUNIFORM3UIPROC glad_glUniform3ui; -PFNGLCOLOR4DVPROC glad_glColor4dv; -PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; -PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; -PFNGLUNIFORM2FVPROC glad_glUniform2fv; -PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub; -PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui; -PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv; -PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; -PFNGLNORMAL3IVPROC glad_glNormal3iv; -PFNGLWINDOWPOS3SPROC glad_glWindowPos3s; -PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; -PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; -PFNGLWINDOWPOS3IPROC glad_glWindowPos3i; -PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s; -PFNGLWINDOWPOS3FPROC glad_glWindowPos3f; -PFNGLCOLOR3USPROC glad_glColor3us; -PFNGLCOLOR3UIVPROC glad_glColor3uiv; -PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; -PFNGLGETLIGHTIVPROC glad_glGetLightiv; -PFNGLDEPTHFUNCPROC glad_glDepthFunc; -PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; -PFNGLLISTBASEPROC glad_glListBase; -PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f; -PFNGLCOLOR3UBPROC glad_glColor3ub; -PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d; -PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; -PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; -PFNGLCOLOR3UIPROC glad_glColor3ui; -PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i; -PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; -PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; -PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; -PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv; -PFNGLCOLORMASKPROC glad_glColorMask; -PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; -PFNGLBLENDEQUATIONPROC glad_glBlendEquation; -PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; -PFNGLRASTERPOS4SPROC glad_glRasterPos4s; -PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; -PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; -PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv; -PFNGLCOLOR4SVPROC glad_glColor4sv; -PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib; -PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; -PFNGLFOGFPROC glad_glFogf; -PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; -PFNGLCOLOR3IVPROC glad_glColor3iv; -PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; -PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; -PFNGLTEXCOORD1IPROC glad_glTexCoord1i; -PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; -PFNGLTEXCOORD1DPROC glad_glTexCoord1d; -PFNGLTEXCOORD1FPROC glad_glTexCoord1f; -PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; -PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState; -PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; -PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; -PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv; -PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; -PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; -PFNGLTEXCOORD1SPROC glad_glTexCoord1s; -PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; -PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; -PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; -PFNGLGENLISTSPROC glad_glGenLists; -PFNGLCOLOR3BVPROC glad_glColor3bv; -PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; -PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; -PFNGLGETTEXGENDVPROC glad_glGetTexGendv; -PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; -PFNGLENDLISTPROC glad_glEndList; -PFNGLUNIFORM2UIPROC glad_glUniform2ui; -PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; -PFNGLCOLOR3USVPROC glad_glColor3usv; -PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv; -PFNGLDISABLEIPROC glad_glDisablei; -PFNGLINDEXMASKPROC glad_glIndexMask; -PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib; -PFNGLSHADERSOURCEPROC glad_glShaderSource; -PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; -PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; -PFNGLCLEARACCUMPROC glad_glClearAccum; -PFNGLGETSYNCIVPROC glad_glGetSynciv; -PFNGLUNIFORM2FPROC glad_glUniform2f; -PFNGLBEGINQUERYPROC glad_glBeginQuery; -PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; -PFNGLBINDBUFFERPROC glad_glBindBuffer; -PFNGLMAP2DPROC glad_glMap2d; -PFNGLMAP2FPROC glad_glMap2f; -PFNGLVERTEX4DPROC glad_glVertex4d; -PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; -PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv; -PFNGLBUFFERDATAPROC glad_glBufferData; -PFNGLEVALPOINT1PROC glad_glEvalPoint1; -PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; -PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv; -PFNGLGETERRORPROC glad_glGetError; -PFNGLGETTEXENVIVPROC glad_glGetTexEnviv; -PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; -PFNGLGETFLOATVPROC glad_glGetFloatv; -PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; -PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv; -PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; -PFNGLEVALCOORD1DPROC glad_glEvalCoord1d; -PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; -PFNGLEVALCOORD1FPROC glad_glEvalCoord1f; -PFNGLPIXELMAPFVPROC glad_glPixelMapfv; -PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv; -PFNGLGETINTEGERVPROC glad_glGetIntegerv; -PFNGLACCUMPROC glad_glAccum; -PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; -PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; -PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv; -PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv; -PFNGLISQUERYPROC glad_glIsQuery; -PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; -PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv; -PFNGLTEXIMAGE2DPROC glad_glTexImage2D; -PFNGLSTENCILMASKPROC glad_glStencilMask; -PFNGLDRAWPIXELSPROC glad_glDrawPixels; -PFNGLMULTMATRIXDPROC glad_glMultMatrixd; -PFNGLMULTMATRIXFPROC glad_glMultMatrixf; -PFNGLISTEXTUREPROC glad_glIsTexture; -PFNGLGETMATERIALIVPROC glad_glGetMaterialiv; -PFNGLUNIFORM1FVPROC glad_glUniform1fv; -PFNGLLOADMATRIXFPROC glad_glLoadMatrixf; -PFNGLLOADMATRIXDPROC glad_glLoadMatrixd; -PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; -PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; -PFNGLVERTEX4FPROC glad_glVertex4f; -PFNGLRECTSVPROC glad_glRectsv; -PFNGLCOLOR4USVPROC glad_glColor4usv; -PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple; -PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays; -PFNGLNORMAL3IPROC glad_glNormal3i; -PFNGLNORMAL3FPROC glad_glNormal3f; -PFNGLNORMAL3DPROC glad_glNormal3d; -PFNGLNORMAL3BPROC glad_glNormal3b; -PFNGLPIXELMAPUSVPROC glad_glPixelMapusv; -PFNGLGETTEXGENIVPROC glad_glGetTexGeniv; -PFNGLARRAYELEMENTPROC glad_glArrayElement; -PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; -PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; -PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; -PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; -PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; -PFNGLDEPTHMASKPROC glad_glDepthMask; -PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; -PFNGLCOLOR3FVPROC glad_glColor3fv; -PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; -PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; -PFNGLUNIFORM4FVPROC glad_glUniform4fv; -PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; -PFNGLCOLORPOINTERPROC glad_glColorPointer; -PFNGLFRONTFACEPROC glad_glFrontFace; -PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; -PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; -int GLAD_GL_KHR_debug; -int GLAD_GL_ARB_robustness; -int GLAD_GL_ARB_multisample; -PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB; -PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB; -PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB; -PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB; -PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB; -PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB; -PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB; -PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB; -PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB; -PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB; -PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB; -PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB; -PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB; -PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB; -PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB; -PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB; -PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB; -PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB; -PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB; -PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB; -PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB; -PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl; -PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert; -PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback; -PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog; -PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup; -PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup; -PFNGLOBJECTLABELPROC glad_glObjectLabel; -PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel; -PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel; -PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel; -PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR; -PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR; -PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR; -PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR; -PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR; -PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR; -PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR; -PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR; -PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR; -PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR; -PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR; -static void load_GL_VERSION_1_0(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_0) return; - glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); - glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); - glad_glHint = (PFNGLHINTPROC)load("glHint"); - glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); - glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize"); - glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode"); - glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); - glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); - glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); - glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); - glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); - glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D"); - glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); - glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer"); - glad_glClear = (PFNGLCLEARPROC)load("glClear"); - glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); - glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); - glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth"); - glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); - glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); - glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); - glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); - glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); - glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); - glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); - glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); - glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp"); - glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); - glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); - glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); - glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref"); - glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); - glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); - glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); - glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); - glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev"); - glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); - glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); - glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); - glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); - glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage"); - glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); - glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); - glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); - glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); - glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); - glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange"); - glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); - glad_glNewList = (PFNGLNEWLISTPROC)load("glNewList"); - glad_glEndList = (PFNGLENDLISTPROC)load("glEndList"); - glad_glCallList = (PFNGLCALLLISTPROC)load("glCallList"); - glad_glCallLists = (PFNGLCALLLISTSPROC)load("glCallLists"); - glad_glDeleteLists = (PFNGLDELETELISTSPROC)load("glDeleteLists"); - glad_glGenLists = (PFNGLGENLISTSPROC)load("glGenLists"); - glad_glListBase = (PFNGLLISTBASEPROC)load("glListBase"); - glad_glBegin = (PFNGLBEGINPROC)load("glBegin"); - glad_glBitmap = (PFNGLBITMAPPROC)load("glBitmap"); - glad_glColor3b = (PFNGLCOLOR3BPROC)load("glColor3b"); - glad_glColor3bv = (PFNGLCOLOR3BVPROC)load("glColor3bv"); - glad_glColor3d = (PFNGLCOLOR3DPROC)load("glColor3d"); - glad_glColor3dv = (PFNGLCOLOR3DVPROC)load("glColor3dv"); - glad_glColor3f = (PFNGLCOLOR3FPROC)load("glColor3f"); - glad_glColor3fv = (PFNGLCOLOR3FVPROC)load("glColor3fv"); - glad_glColor3i = (PFNGLCOLOR3IPROC)load("glColor3i"); - glad_glColor3iv = (PFNGLCOLOR3IVPROC)load("glColor3iv"); - glad_glColor3s = (PFNGLCOLOR3SPROC)load("glColor3s"); - glad_glColor3sv = (PFNGLCOLOR3SVPROC)load("glColor3sv"); - glad_glColor3ub = (PFNGLCOLOR3UBPROC)load("glColor3ub"); - glad_glColor3ubv = (PFNGLCOLOR3UBVPROC)load("glColor3ubv"); - glad_glColor3ui = (PFNGLCOLOR3UIPROC)load("glColor3ui"); - glad_glColor3uiv = (PFNGLCOLOR3UIVPROC)load("glColor3uiv"); - glad_glColor3us = (PFNGLCOLOR3USPROC)load("glColor3us"); - glad_glColor3usv = (PFNGLCOLOR3USVPROC)load("glColor3usv"); - glad_glColor4b = (PFNGLCOLOR4BPROC)load("glColor4b"); - glad_glColor4bv = (PFNGLCOLOR4BVPROC)load("glColor4bv"); - glad_glColor4d = (PFNGLCOLOR4DPROC)load("glColor4d"); - glad_glColor4dv = (PFNGLCOLOR4DVPROC)load("glColor4dv"); - glad_glColor4f = (PFNGLCOLOR4FPROC)load("glColor4f"); - glad_glColor4fv = (PFNGLCOLOR4FVPROC)load("glColor4fv"); - glad_glColor4i = (PFNGLCOLOR4IPROC)load("glColor4i"); - glad_glColor4iv = (PFNGLCOLOR4IVPROC)load("glColor4iv"); - glad_glColor4s = (PFNGLCOLOR4SPROC)load("glColor4s"); - glad_glColor4sv = (PFNGLCOLOR4SVPROC)load("glColor4sv"); - glad_glColor4ub = (PFNGLCOLOR4UBPROC)load("glColor4ub"); - glad_glColor4ubv = (PFNGLCOLOR4UBVPROC)load("glColor4ubv"); - glad_glColor4ui = (PFNGLCOLOR4UIPROC)load("glColor4ui"); - glad_glColor4uiv = (PFNGLCOLOR4UIVPROC)load("glColor4uiv"); - glad_glColor4us = (PFNGLCOLOR4USPROC)load("glColor4us"); - glad_glColor4usv = (PFNGLCOLOR4USVPROC)load("glColor4usv"); - glad_glEdgeFlag = (PFNGLEDGEFLAGPROC)load("glEdgeFlag"); - glad_glEdgeFlagv = (PFNGLEDGEFLAGVPROC)load("glEdgeFlagv"); - glad_glEnd = (PFNGLENDPROC)load("glEnd"); - glad_glIndexd = (PFNGLINDEXDPROC)load("glIndexd"); - glad_glIndexdv = (PFNGLINDEXDVPROC)load("glIndexdv"); - glad_glIndexf = (PFNGLINDEXFPROC)load("glIndexf"); - glad_glIndexfv = (PFNGLINDEXFVPROC)load("glIndexfv"); - glad_glIndexi = (PFNGLINDEXIPROC)load("glIndexi"); - glad_glIndexiv = (PFNGLINDEXIVPROC)load("glIndexiv"); - glad_glIndexs = (PFNGLINDEXSPROC)load("glIndexs"); - glad_glIndexsv = (PFNGLINDEXSVPROC)load("glIndexsv"); - glad_glNormal3b = (PFNGLNORMAL3BPROC)load("glNormal3b"); - glad_glNormal3bv = (PFNGLNORMAL3BVPROC)load("glNormal3bv"); - glad_glNormal3d = (PFNGLNORMAL3DPROC)load("glNormal3d"); - glad_glNormal3dv = (PFNGLNORMAL3DVPROC)load("glNormal3dv"); - glad_glNormal3f = (PFNGLNORMAL3FPROC)load("glNormal3f"); - glad_glNormal3fv = (PFNGLNORMAL3FVPROC)load("glNormal3fv"); - glad_glNormal3i = (PFNGLNORMAL3IPROC)load("glNormal3i"); - glad_glNormal3iv = (PFNGLNORMAL3IVPROC)load("glNormal3iv"); - glad_glNormal3s = (PFNGLNORMAL3SPROC)load("glNormal3s"); - glad_glNormal3sv = (PFNGLNORMAL3SVPROC)load("glNormal3sv"); - glad_glRasterPos2d = (PFNGLRASTERPOS2DPROC)load("glRasterPos2d"); - glad_glRasterPos2dv = (PFNGLRASTERPOS2DVPROC)load("glRasterPos2dv"); - glad_glRasterPos2f = (PFNGLRASTERPOS2FPROC)load("glRasterPos2f"); - glad_glRasterPos2fv = (PFNGLRASTERPOS2FVPROC)load("glRasterPos2fv"); - glad_glRasterPos2i = (PFNGLRASTERPOS2IPROC)load("glRasterPos2i"); - glad_glRasterPos2iv = (PFNGLRASTERPOS2IVPROC)load("glRasterPos2iv"); - glad_glRasterPos2s = (PFNGLRASTERPOS2SPROC)load("glRasterPos2s"); - glad_glRasterPos2sv = (PFNGLRASTERPOS2SVPROC)load("glRasterPos2sv"); - glad_glRasterPos3d = (PFNGLRASTERPOS3DPROC)load("glRasterPos3d"); - glad_glRasterPos3dv = (PFNGLRASTERPOS3DVPROC)load("glRasterPos3dv"); - glad_glRasterPos3f = (PFNGLRASTERPOS3FPROC)load("glRasterPos3f"); - glad_glRasterPos3fv = (PFNGLRASTERPOS3FVPROC)load("glRasterPos3fv"); - glad_glRasterPos3i = (PFNGLRASTERPOS3IPROC)load("glRasterPos3i"); - glad_glRasterPos3iv = (PFNGLRASTERPOS3IVPROC)load("glRasterPos3iv"); - glad_glRasterPos3s = (PFNGLRASTERPOS3SPROC)load("glRasterPos3s"); - glad_glRasterPos3sv = (PFNGLRASTERPOS3SVPROC)load("glRasterPos3sv"); - glad_glRasterPos4d = (PFNGLRASTERPOS4DPROC)load("glRasterPos4d"); - glad_glRasterPos4dv = (PFNGLRASTERPOS4DVPROC)load("glRasterPos4dv"); - glad_glRasterPos4f = (PFNGLRASTERPOS4FPROC)load("glRasterPos4f"); - glad_glRasterPos4fv = (PFNGLRASTERPOS4FVPROC)load("glRasterPos4fv"); - glad_glRasterPos4i = (PFNGLRASTERPOS4IPROC)load("glRasterPos4i"); - glad_glRasterPos4iv = (PFNGLRASTERPOS4IVPROC)load("glRasterPos4iv"); - glad_glRasterPos4s = (PFNGLRASTERPOS4SPROC)load("glRasterPos4s"); - glad_glRasterPos4sv = (PFNGLRASTERPOS4SVPROC)load("glRasterPos4sv"); - glad_glRectd = (PFNGLRECTDPROC)load("glRectd"); - glad_glRectdv = (PFNGLRECTDVPROC)load("glRectdv"); - glad_glRectf = (PFNGLRECTFPROC)load("glRectf"); - glad_glRectfv = (PFNGLRECTFVPROC)load("glRectfv"); - glad_glRecti = (PFNGLRECTIPROC)load("glRecti"); - glad_glRectiv = (PFNGLRECTIVPROC)load("glRectiv"); - glad_glRects = (PFNGLRECTSPROC)load("glRects"); - glad_glRectsv = (PFNGLRECTSVPROC)load("glRectsv"); - glad_glTexCoord1d = (PFNGLTEXCOORD1DPROC)load("glTexCoord1d"); - glad_glTexCoord1dv = (PFNGLTEXCOORD1DVPROC)load("glTexCoord1dv"); - glad_glTexCoord1f = (PFNGLTEXCOORD1FPROC)load("glTexCoord1f"); - glad_glTexCoord1fv = (PFNGLTEXCOORD1FVPROC)load("glTexCoord1fv"); - glad_glTexCoord1i = (PFNGLTEXCOORD1IPROC)load("glTexCoord1i"); - glad_glTexCoord1iv = (PFNGLTEXCOORD1IVPROC)load("glTexCoord1iv"); - glad_glTexCoord1s = (PFNGLTEXCOORD1SPROC)load("glTexCoord1s"); - glad_glTexCoord1sv = (PFNGLTEXCOORD1SVPROC)load("glTexCoord1sv"); - glad_glTexCoord2d = (PFNGLTEXCOORD2DPROC)load("glTexCoord2d"); - glad_glTexCoord2dv = (PFNGLTEXCOORD2DVPROC)load("glTexCoord2dv"); - glad_glTexCoord2f = (PFNGLTEXCOORD2FPROC)load("glTexCoord2f"); - glad_glTexCoord2fv = (PFNGLTEXCOORD2FVPROC)load("glTexCoord2fv"); - glad_glTexCoord2i = (PFNGLTEXCOORD2IPROC)load("glTexCoord2i"); - glad_glTexCoord2iv = (PFNGLTEXCOORD2IVPROC)load("glTexCoord2iv"); - glad_glTexCoord2s = (PFNGLTEXCOORD2SPROC)load("glTexCoord2s"); - glad_glTexCoord2sv = (PFNGLTEXCOORD2SVPROC)load("glTexCoord2sv"); - glad_glTexCoord3d = (PFNGLTEXCOORD3DPROC)load("glTexCoord3d"); - glad_glTexCoord3dv = (PFNGLTEXCOORD3DVPROC)load("glTexCoord3dv"); - glad_glTexCoord3f = (PFNGLTEXCOORD3FPROC)load("glTexCoord3f"); - glad_glTexCoord3fv = (PFNGLTEXCOORD3FVPROC)load("glTexCoord3fv"); - glad_glTexCoord3i = (PFNGLTEXCOORD3IPROC)load("glTexCoord3i"); - glad_glTexCoord3iv = (PFNGLTEXCOORD3IVPROC)load("glTexCoord3iv"); - glad_glTexCoord3s = (PFNGLTEXCOORD3SPROC)load("glTexCoord3s"); - glad_glTexCoord3sv = (PFNGLTEXCOORD3SVPROC)load("glTexCoord3sv"); - glad_glTexCoord4d = (PFNGLTEXCOORD4DPROC)load("glTexCoord4d"); - glad_glTexCoord4dv = (PFNGLTEXCOORD4DVPROC)load("glTexCoord4dv"); - glad_glTexCoord4f = (PFNGLTEXCOORD4FPROC)load("glTexCoord4f"); - glad_glTexCoord4fv = (PFNGLTEXCOORD4FVPROC)load("glTexCoord4fv"); - glad_glTexCoord4i = (PFNGLTEXCOORD4IPROC)load("glTexCoord4i"); - glad_glTexCoord4iv = (PFNGLTEXCOORD4IVPROC)load("glTexCoord4iv"); - glad_glTexCoord4s = (PFNGLTEXCOORD4SPROC)load("glTexCoord4s"); - glad_glTexCoord4sv = (PFNGLTEXCOORD4SVPROC)load("glTexCoord4sv"); - glad_glVertex2d = (PFNGLVERTEX2DPROC)load("glVertex2d"); - glad_glVertex2dv = (PFNGLVERTEX2DVPROC)load("glVertex2dv"); - glad_glVertex2f = (PFNGLVERTEX2FPROC)load("glVertex2f"); - glad_glVertex2fv = (PFNGLVERTEX2FVPROC)load("glVertex2fv"); - glad_glVertex2i = (PFNGLVERTEX2IPROC)load("glVertex2i"); - glad_glVertex2iv = (PFNGLVERTEX2IVPROC)load("glVertex2iv"); - glad_glVertex2s = (PFNGLVERTEX2SPROC)load("glVertex2s"); - glad_glVertex2sv = (PFNGLVERTEX2SVPROC)load("glVertex2sv"); - glad_glVertex3d = (PFNGLVERTEX3DPROC)load("glVertex3d"); - glad_glVertex3dv = (PFNGLVERTEX3DVPROC)load("glVertex3dv"); - glad_glVertex3f = (PFNGLVERTEX3FPROC)load("glVertex3f"); - glad_glVertex3fv = (PFNGLVERTEX3FVPROC)load("glVertex3fv"); - glad_glVertex3i = (PFNGLVERTEX3IPROC)load("glVertex3i"); - glad_glVertex3iv = (PFNGLVERTEX3IVPROC)load("glVertex3iv"); - glad_glVertex3s = (PFNGLVERTEX3SPROC)load("glVertex3s"); - glad_glVertex3sv = (PFNGLVERTEX3SVPROC)load("glVertex3sv"); - glad_glVertex4d = (PFNGLVERTEX4DPROC)load("glVertex4d"); - glad_glVertex4dv = (PFNGLVERTEX4DVPROC)load("glVertex4dv"); - glad_glVertex4f = (PFNGLVERTEX4FPROC)load("glVertex4f"); - glad_glVertex4fv = (PFNGLVERTEX4FVPROC)load("glVertex4fv"); - glad_glVertex4i = (PFNGLVERTEX4IPROC)load("glVertex4i"); - glad_glVertex4iv = (PFNGLVERTEX4IVPROC)load("glVertex4iv"); - glad_glVertex4s = (PFNGLVERTEX4SPROC)load("glVertex4s"); - glad_glVertex4sv = (PFNGLVERTEX4SVPROC)load("glVertex4sv"); - glad_glClipPlane = (PFNGLCLIPPLANEPROC)load("glClipPlane"); - glad_glColorMaterial = (PFNGLCOLORMATERIALPROC)load("glColorMaterial"); - glad_glFogf = (PFNGLFOGFPROC)load("glFogf"); - glad_glFogfv = (PFNGLFOGFVPROC)load("glFogfv"); - glad_glFogi = (PFNGLFOGIPROC)load("glFogi"); - glad_glFogiv = (PFNGLFOGIVPROC)load("glFogiv"); - glad_glLightf = (PFNGLLIGHTFPROC)load("glLightf"); - glad_glLightfv = (PFNGLLIGHTFVPROC)load("glLightfv"); - glad_glLighti = (PFNGLLIGHTIPROC)load("glLighti"); - glad_glLightiv = (PFNGLLIGHTIVPROC)load("glLightiv"); - glad_glLightModelf = (PFNGLLIGHTMODELFPROC)load("glLightModelf"); - glad_glLightModelfv = (PFNGLLIGHTMODELFVPROC)load("glLightModelfv"); - glad_glLightModeli = (PFNGLLIGHTMODELIPROC)load("glLightModeli"); - glad_glLightModeliv = (PFNGLLIGHTMODELIVPROC)load("glLightModeliv"); - glad_glLineStipple = (PFNGLLINESTIPPLEPROC)load("glLineStipple"); - glad_glMaterialf = (PFNGLMATERIALFPROC)load("glMaterialf"); - glad_glMaterialfv = (PFNGLMATERIALFVPROC)load("glMaterialfv"); - glad_glMateriali = (PFNGLMATERIALIPROC)load("glMateriali"); - glad_glMaterialiv = (PFNGLMATERIALIVPROC)load("glMaterialiv"); - glad_glPolygonStipple = (PFNGLPOLYGONSTIPPLEPROC)load("glPolygonStipple"); - glad_glShadeModel = (PFNGLSHADEMODELPROC)load("glShadeModel"); - glad_glTexEnvf = (PFNGLTEXENVFPROC)load("glTexEnvf"); - glad_glTexEnvfv = (PFNGLTEXENVFVPROC)load("glTexEnvfv"); - glad_glTexEnvi = (PFNGLTEXENVIPROC)load("glTexEnvi"); - glad_glTexEnviv = (PFNGLTEXENVIVPROC)load("glTexEnviv"); - glad_glTexGend = (PFNGLTEXGENDPROC)load("glTexGend"); - glad_glTexGendv = (PFNGLTEXGENDVPROC)load("glTexGendv"); - glad_glTexGenf = (PFNGLTEXGENFPROC)load("glTexGenf"); - glad_glTexGenfv = (PFNGLTEXGENFVPROC)load("glTexGenfv"); - glad_glTexGeni = (PFNGLTEXGENIPROC)load("glTexGeni"); - glad_glTexGeniv = (PFNGLTEXGENIVPROC)load("glTexGeniv"); - glad_glFeedbackBuffer = (PFNGLFEEDBACKBUFFERPROC)load("glFeedbackBuffer"); - glad_glSelectBuffer = (PFNGLSELECTBUFFERPROC)load("glSelectBuffer"); - glad_glRenderMode = (PFNGLRENDERMODEPROC)load("glRenderMode"); - glad_glInitNames = (PFNGLINITNAMESPROC)load("glInitNames"); - glad_glLoadName = (PFNGLLOADNAMEPROC)load("glLoadName"); - glad_glPassThrough = (PFNGLPASSTHROUGHPROC)load("glPassThrough"); - glad_glPopName = (PFNGLPOPNAMEPROC)load("glPopName"); - glad_glPushName = (PFNGLPUSHNAMEPROC)load("glPushName"); - glad_glClearAccum = (PFNGLCLEARACCUMPROC)load("glClearAccum"); - glad_glClearIndex = (PFNGLCLEARINDEXPROC)load("glClearIndex"); - glad_glIndexMask = (PFNGLINDEXMASKPROC)load("glIndexMask"); - glad_glAccum = (PFNGLACCUMPROC)load("glAccum"); - glad_glPopAttrib = (PFNGLPOPATTRIBPROC)load("glPopAttrib"); - glad_glPushAttrib = (PFNGLPUSHATTRIBPROC)load("glPushAttrib"); - glad_glMap1d = (PFNGLMAP1DPROC)load("glMap1d"); - glad_glMap1f = (PFNGLMAP1FPROC)load("glMap1f"); - glad_glMap2d = (PFNGLMAP2DPROC)load("glMap2d"); - glad_glMap2f = (PFNGLMAP2FPROC)load("glMap2f"); - glad_glMapGrid1d = (PFNGLMAPGRID1DPROC)load("glMapGrid1d"); - glad_glMapGrid1f = (PFNGLMAPGRID1FPROC)load("glMapGrid1f"); - glad_glMapGrid2d = (PFNGLMAPGRID2DPROC)load("glMapGrid2d"); - glad_glMapGrid2f = (PFNGLMAPGRID2FPROC)load("glMapGrid2f"); - glad_glEvalCoord1d = (PFNGLEVALCOORD1DPROC)load("glEvalCoord1d"); - glad_glEvalCoord1dv = (PFNGLEVALCOORD1DVPROC)load("glEvalCoord1dv"); - glad_glEvalCoord1f = (PFNGLEVALCOORD1FPROC)load("glEvalCoord1f"); - glad_glEvalCoord1fv = (PFNGLEVALCOORD1FVPROC)load("glEvalCoord1fv"); - glad_glEvalCoord2d = (PFNGLEVALCOORD2DPROC)load("glEvalCoord2d"); - glad_glEvalCoord2dv = (PFNGLEVALCOORD2DVPROC)load("glEvalCoord2dv"); - glad_glEvalCoord2f = (PFNGLEVALCOORD2FPROC)load("glEvalCoord2f"); - glad_glEvalCoord2fv = (PFNGLEVALCOORD2FVPROC)load("glEvalCoord2fv"); - glad_glEvalMesh1 = (PFNGLEVALMESH1PROC)load("glEvalMesh1"); - glad_glEvalPoint1 = (PFNGLEVALPOINT1PROC)load("glEvalPoint1"); - glad_glEvalMesh2 = (PFNGLEVALMESH2PROC)load("glEvalMesh2"); - glad_glEvalPoint2 = (PFNGLEVALPOINT2PROC)load("glEvalPoint2"); - glad_glAlphaFunc = (PFNGLALPHAFUNCPROC)load("glAlphaFunc"); - glad_glPixelZoom = (PFNGLPIXELZOOMPROC)load("glPixelZoom"); - glad_glPixelTransferf = (PFNGLPIXELTRANSFERFPROC)load("glPixelTransferf"); - glad_glPixelTransferi = (PFNGLPIXELTRANSFERIPROC)load("glPixelTransferi"); - glad_glPixelMapfv = (PFNGLPIXELMAPFVPROC)load("glPixelMapfv"); - glad_glPixelMapuiv = (PFNGLPIXELMAPUIVPROC)load("glPixelMapuiv"); - glad_glPixelMapusv = (PFNGLPIXELMAPUSVPROC)load("glPixelMapusv"); - glad_glCopyPixels = (PFNGLCOPYPIXELSPROC)load("glCopyPixels"); - glad_glDrawPixels = (PFNGLDRAWPIXELSPROC)load("glDrawPixels"); - glad_glGetClipPlane = (PFNGLGETCLIPPLANEPROC)load("glGetClipPlane"); - glad_glGetLightfv = (PFNGLGETLIGHTFVPROC)load("glGetLightfv"); - glad_glGetLightiv = (PFNGLGETLIGHTIVPROC)load("glGetLightiv"); - glad_glGetMapdv = (PFNGLGETMAPDVPROC)load("glGetMapdv"); - glad_glGetMapfv = (PFNGLGETMAPFVPROC)load("glGetMapfv"); - glad_glGetMapiv = (PFNGLGETMAPIVPROC)load("glGetMapiv"); - glad_glGetMaterialfv = (PFNGLGETMATERIALFVPROC)load("glGetMaterialfv"); - glad_glGetMaterialiv = (PFNGLGETMATERIALIVPROC)load("glGetMaterialiv"); - glad_glGetPixelMapfv = (PFNGLGETPIXELMAPFVPROC)load("glGetPixelMapfv"); - glad_glGetPixelMapuiv = (PFNGLGETPIXELMAPUIVPROC)load("glGetPixelMapuiv"); - glad_glGetPixelMapusv = (PFNGLGETPIXELMAPUSVPROC)load("glGetPixelMapusv"); - glad_glGetPolygonStipple = (PFNGLGETPOLYGONSTIPPLEPROC)load("glGetPolygonStipple"); - glad_glGetTexEnvfv = (PFNGLGETTEXENVFVPROC)load("glGetTexEnvfv"); - glad_glGetTexEnviv = (PFNGLGETTEXENVIVPROC)load("glGetTexEnviv"); - glad_glGetTexGendv = (PFNGLGETTEXGENDVPROC)load("glGetTexGendv"); - glad_glGetTexGenfv = (PFNGLGETTEXGENFVPROC)load("glGetTexGenfv"); - glad_glGetTexGeniv = (PFNGLGETTEXGENIVPROC)load("glGetTexGeniv"); - glad_glIsList = (PFNGLISLISTPROC)load("glIsList"); - glad_glFrustum = (PFNGLFRUSTUMPROC)load("glFrustum"); - glad_glLoadIdentity = (PFNGLLOADIDENTITYPROC)load("glLoadIdentity"); - glad_glLoadMatrixf = (PFNGLLOADMATRIXFPROC)load("glLoadMatrixf"); - glad_glLoadMatrixd = (PFNGLLOADMATRIXDPROC)load("glLoadMatrixd"); - glad_glMatrixMode = (PFNGLMATRIXMODEPROC)load("glMatrixMode"); - glad_glMultMatrixf = (PFNGLMULTMATRIXFPROC)load("glMultMatrixf"); - glad_glMultMatrixd = (PFNGLMULTMATRIXDPROC)load("glMultMatrixd"); - glad_glOrtho = (PFNGLORTHOPROC)load("glOrtho"); - glad_glPopMatrix = (PFNGLPOPMATRIXPROC)load("glPopMatrix"); - glad_glPushMatrix = (PFNGLPUSHMATRIXPROC)load("glPushMatrix"); - glad_glRotated = (PFNGLROTATEDPROC)load("glRotated"); - glad_glRotatef = (PFNGLROTATEFPROC)load("glRotatef"); - glad_glScaled = (PFNGLSCALEDPROC)load("glScaled"); - glad_glScalef = (PFNGLSCALEFPROC)load("glScalef"); - glad_glTranslated = (PFNGLTRANSLATEDPROC)load("glTranslated"); - glad_glTranslatef = (PFNGLTRANSLATEFPROC)load("glTranslatef"); -} -static void load_GL_VERSION_1_1(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_1) return; - glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); - glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); - glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv"); - glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); - glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D"); - glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); - glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D"); - glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); - glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D"); - glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); - glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); - glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); - glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); - glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); - glad_glArrayElement = (PFNGLARRAYELEMENTPROC)load("glArrayElement"); - glad_glColorPointer = (PFNGLCOLORPOINTERPROC)load("glColorPointer"); - glad_glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC)load("glDisableClientState"); - glad_glEdgeFlagPointer = (PFNGLEDGEFLAGPOINTERPROC)load("glEdgeFlagPointer"); - glad_glEnableClientState = (PFNGLENABLECLIENTSTATEPROC)load("glEnableClientState"); - glad_glIndexPointer = (PFNGLINDEXPOINTERPROC)load("glIndexPointer"); - glad_glInterleavedArrays = (PFNGLINTERLEAVEDARRAYSPROC)load("glInterleavedArrays"); - glad_glNormalPointer = (PFNGLNORMALPOINTERPROC)load("glNormalPointer"); - glad_glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC)load("glTexCoordPointer"); - glad_glVertexPointer = (PFNGLVERTEXPOINTERPROC)load("glVertexPointer"); - glad_glAreTexturesResident = (PFNGLARETEXTURESRESIDENTPROC)load("glAreTexturesResident"); - glad_glPrioritizeTextures = (PFNGLPRIORITIZETEXTURESPROC)load("glPrioritizeTextures"); - glad_glIndexub = (PFNGLINDEXUBPROC)load("glIndexub"); - glad_glIndexubv = (PFNGLINDEXUBVPROC)load("glIndexubv"); - glad_glPopClientAttrib = (PFNGLPOPCLIENTATTRIBPROC)load("glPopClientAttrib"); - glad_glPushClientAttrib = (PFNGLPUSHCLIENTATTRIBPROC)load("glPushClientAttrib"); -} -static void load_GL_VERSION_1_2(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_2) return; - glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); - glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); - glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); - glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); -} -static void load_GL_VERSION_1_3(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_3) return; - glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); - glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); - glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); - glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); - glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D"); - glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); - glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); - glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D"); - glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage"); - glad_glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)load("glClientActiveTexture"); - glad_glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC)load("glMultiTexCoord1d"); - glad_glMultiTexCoord1dv = (PFNGLMULTITEXCOORD1DVPROC)load("glMultiTexCoord1dv"); - glad_glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC)load("glMultiTexCoord1f"); - glad_glMultiTexCoord1fv = (PFNGLMULTITEXCOORD1FVPROC)load("glMultiTexCoord1fv"); - glad_glMultiTexCoord1i = (PFNGLMULTITEXCOORD1IPROC)load("glMultiTexCoord1i"); - glad_glMultiTexCoord1iv = (PFNGLMULTITEXCOORD1IVPROC)load("glMultiTexCoord1iv"); - glad_glMultiTexCoord1s = (PFNGLMULTITEXCOORD1SPROC)load("glMultiTexCoord1s"); - glad_glMultiTexCoord1sv = (PFNGLMULTITEXCOORD1SVPROC)load("glMultiTexCoord1sv"); - glad_glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC)load("glMultiTexCoord2d"); - glad_glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC)load("glMultiTexCoord2dv"); - glad_glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC)load("glMultiTexCoord2f"); - glad_glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC)load("glMultiTexCoord2fv"); - glad_glMultiTexCoord2i = (PFNGLMULTITEXCOORD2IPROC)load("glMultiTexCoord2i"); - glad_glMultiTexCoord2iv = (PFNGLMULTITEXCOORD2IVPROC)load("glMultiTexCoord2iv"); - glad_glMultiTexCoord2s = (PFNGLMULTITEXCOORD2SPROC)load("glMultiTexCoord2s"); - glad_glMultiTexCoord2sv = (PFNGLMULTITEXCOORD2SVPROC)load("glMultiTexCoord2sv"); - glad_glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC)load("glMultiTexCoord3d"); - glad_glMultiTexCoord3dv = (PFNGLMULTITEXCOORD3DVPROC)load("glMultiTexCoord3dv"); - glad_glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC)load("glMultiTexCoord3f"); - glad_glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC)load("glMultiTexCoord3fv"); - glad_glMultiTexCoord3i = (PFNGLMULTITEXCOORD3IPROC)load("glMultiTexCoord3i"); - glad_glMultiTexCoord3iv = (PFNGLMULTITEXCOORD3IVPROC)load("glMultiTexCoord3iv"); - glad_glMultiTexCoord3s = (PFNGLMULTITEXCOORD3SPROC)load("glMultiTexCoord3s"); - glad_glMultiTexCoord3sv = (PFNGLMULTITEXCOORD3SVPROC)load("glMultiTexCoord3sv"); - glad_glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC)load("glMultiTexCoord4d"); - glad_glMultiTexCoord4dv = (PFNGLMULTITEXCOORD4DVPROC)load("glMultiTexCoord4dv"); - glad_glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)load("glMultiTexCoord4f"); - glad_glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC)load("glMultiTexCoord4fv"); - glad_glMultiTexCoord4i = (PFNGLMULTITEXCOORD4IPROC)load("glMultiTexCoord4i"); - glad_glMultiTexCoord4iv = (PFNGLMULTITEXCOORD4IVPROC)load("glMultiTexCoord4iv"); - glad_glMultiTexCoord4s = (PFNGLMULTITEXCOORD4SPROC)load("glMultiTexCoord4s"); - glad_glMultiTexCoord4sv = (PFNGLMULTITEXCOORD4SVPROC)load("glMultiTexCoord4sv"); - glad_glLoadTransposeMatrixf = (PFNGLLOADTRANSPOSEMATRIXFPROC)load("glLoadTransposeMatrixf"); - glad_glLoadTransposeMatrixd = (PFNGLLOADTRANSPOSEMATRIXDPROC)load("glLoadTransposeMatrixd"); - glad_glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC)load("glMultTransposeMatrixf"); - glad_glMultTransposeMatrixd = (PFNGLMULTTRANSPOSEMATRIXDPROC)load("glMultTransposeMatrixd"); -} -static void load_GL_VERSION_1_4(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_4) return; - glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); - glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays"); - glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements"); - glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf"); - glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv"); - glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri"); - glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv"); - glad_glFogCoordf = (PFNGLFOGCOORDFPROC)load("glFogCoordf"); - glad_glFogCoordfv = (PFNGLFOGCOORDFVPROC)load("glFogCoordfv"); - glad_glFogCoordd = (PFNGLFOGCOORDDPROC)load("glFogCoordd"); - glad_glFogCoorddv = (PFNGLFOGCOORDDVPROC)load("glFogCoorddv"); - glad_glFogCoordPointer = (PFNGLFOGCOORDPOINTERPROC)load("glFogCoordPointer"); - glad_glSecondaryColor3b = (PFNGLSECONDARYCOLOR3BPROC)load("glSecondaryColor3b"); - glad_glSecondaryColor3bv = (PFNGLSECONDARYCOLOR3BVPROC)load("glSecondaryColor3bv"); - glad_glSecondaryColor3d = (PFNGLSECONDARYCOLOR3DPROC)load("glSecondaryColor3d"); - glad_glSecondaryColor3dv = (PFNGLSECONDARYCOLOR3DVPROC)load("glSecondaryColor3dv"); - glad_glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FPROC)load("glSecondaryColor3f"); - glad_glSecondaryColor3fv = (PFNGLSECONDARYCOLOR3FVPROC)load("glSecondaryColor3fv"); - glad_glSecondaryColor3i = (PFNGLSECONDARYCOLOR3IPROC)load("glSecondaryColor3i"); - glad_glSecondaryColor3iv = (PFNGLSECONDARYCOLOR3IVPROC)load("glSecondaryColor3iv"); - glad_glSecondaryColor3s = (PFNGLSECONDARYCOLOR3SPROC)load("glSecondaryColor3s"); - glad_glSecondaryColor3sv = (PFNGLSECONDARYCOLOR3SVPROC)load("glSecondaryColor3sv"); - glad_glSecondaryColor3ub = (PFNGLSECONDARYCOLOR3UBPROC)load("glSecondaryColor3ub"); - glad_glSecondaryColor3ubv = (PFNGLSECONDARYCOLOR3UBVPROC)load("glSecondaryColor3ubv"); - glad_glSecondaryColor3ui = (PFNGLSECONDARYCOLOR3UIPROC)load("glSecondaryColor3ui"); - glad_glSecondaryColor3uiv = (PFNGLSECONDARYCOLOR3UIVPROC)load("glSecondaryColor3uiv"); - glad_glSecondaryColor3us = (PFNGLSECONDARYCOLOR3USPROC)load("glSecondaryColor3us"); - glad_glSecondaryColor3usv = (PFNGLSECONDARYCOLOR3USVPROC)load("glSecondaryColor3usv"); - glad_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)load("glSecondaryColorPointer"); - glad_glWindowPos2d = (PFNGLWINDOWPOS2DPROC)load("glWindowPos2d"); - glad_glWindowPos2dv = (PFNGLWINDOWPOS2DVPROC)load("glWindowPos2dv"); - glad_glWindowPos2f = (PFNGLWINDOWPOS2FPROC)load("glWindowPos2f"); - glad_glWindowPos2fv = (PFNGLWINDOWPOS2FVPROC)load("glWindowPos2fv"); - glad_glWindowPos2i = (PFNGLWINDOWPOS2IPROC)load("glWindowPos2i"); - glad_glWindowPos2iv = (PFNGLWINDOWPOS2IVPROC)load("glWindowPos2iv"); - glad_glWindowPos2s = (PFNGLWINDOWPOS2SPROC)load("glWindowPos2s"); - glad_glWindowPos2sv = (PFNGLWINDOWPOS2SVPROC)load("glWindowPos2sv"); - glad_glWindowPos3d = (PFNGLWINDOWPOS3DPROC)load("glWindowPos3d"); - glad_glWindowPos3dv = (PFNGLWINDOWPOS3DVPROC)load("glWindowPos3dv"); - glad_glWindowPos3f = (PFNGLWINDOWPOS3FPROC)load("glWindowPos3f"); - glad_glWindowPos3fv = (PFNGLWINDOWPOS3FVPROC)load("glWindowPos3fv"); - glad_glWindowPos3i = (PFNGLWINDOWPOS3IPROC)load("glWindowPos3i"); - glad_glWindowPos3iv = (PFNGLWINDOWPOS3IVPROC)load("glWindowPos3iv"); - glad_glWindowPos3s = (PFNGLWINDOWPOS3SPROC)load("glWindowPos3s"); - glad_glWindowPos3sv = (PFNGLWINDOWPOS3SVPROC)load("glWindowPos3sv"); - glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); - glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); -} -static void load_GL_VERSION_1_5(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_5) return; - glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); - glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); - glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); - glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); - glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); - glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); - glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv"); - glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); - glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); - glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); - glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); - glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); - glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); - glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); - glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData"); - glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer"); - glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); - glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); - glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); -} -static void load_GL_VERSION_2_0(GLADloadproc load) { - if(!GLAD_GL_VERSION_2_0) return; - glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); - glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); - glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); - glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); - glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); - glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); - glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); - glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); - glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); - glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); - glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); - glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); - glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); - glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); - glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); - glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); - glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); - glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); - glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); - glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); - glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); - glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); - glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); - glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); - glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); - glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); - glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); - glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv"); - glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); - glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); - glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); - glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); - glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); - glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); - glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); - glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); - glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); - glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); - glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); - glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); - glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); - glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); - glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); - glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); - glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); - glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); - glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); - glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); - glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); - glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); - glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); - glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); - glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); - glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); - glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); - glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); - glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d"); - glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv"); - glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); - glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); - glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s"); - glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv"); - glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d"); - glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv"); - glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); - glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); - glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s"); - glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv"); - glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d"); - glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv"); - glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); - glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); - glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s"); - glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv"); - glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv"); - glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv"); - glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv"); - glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub"); - glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv"); - glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv"); - glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv"); - glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv"); - glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d"); - glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv"); - glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); - glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); - glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv"); - glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s"); - glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv"); - glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv"); - glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv"); - glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv"); - glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); -} -static void load_GL_VERSION_2_1(GLADloadproc load) { - if(!GLAD_GL_VERSION_2_1) return; - glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); - glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); - glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); - glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); - glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); - glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); -} -static void load_GL_VERSION_3_0(GLADloadproc load) { - if(!GLAD_GL_VERSION_3_0) return; - glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); - glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); - glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); - glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); - glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); - glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); - glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); - glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); - glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); - glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); - glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); - glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); - glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor"); - glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender"); - glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender"); - glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); - glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); - glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); - glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i"); - glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i"); - glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i"); - glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); - glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui"); - glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui"); - glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui"); - glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); - glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv"); - glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv"); - glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv"); - glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); - glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv"); - glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv"); - glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv"); - glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); - glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv"); - glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv"); - glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv"); - glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv"); - glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); - glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation"); - glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); - glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); - glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); - glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); - glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); - glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); - glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); - glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); - glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); - glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); - glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); - glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); - glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); - glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); - glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); - glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); - glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); - glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); - glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); - glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); - glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); - glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); - glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); - glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); - glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); - glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); - glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); - glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); - glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); - glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); - glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); - glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); - glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); - glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); - glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); - glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); - glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); - glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); - glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); - glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); - glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); - glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); - glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); - glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); -} -static void load_GL_VERSION_3_1(GLADloadproc load) { - if(!GLAD_GL_VERSION_3_1) return; - glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); - glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); - glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer"); - glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex"); - glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); - glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); - glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); - glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName"); - glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); - glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); - glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); - glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); - glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); - glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); - glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); -} -static void load_GL_VERSION_3_2(GLADloadproc load) { - if(!GLAD_GL_VERSION_3_2) return; - glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex"); - glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex"); - glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex"); - glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex"); - glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex"); - glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); - glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); - glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); - glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); - glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); - glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); - glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); - glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); - glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); - glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture"); - glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample"); - glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample"); - glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); - glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); -} -static void load_GL_ARB_multisample(GLADloadproc load) { - if(!GLAD_GL_ARB_multisample) return; - glad_glSampleCoverageARB = (PFNGLSAMPLECOVERAGEARBPROC)load("glSampleCoverageARB"); -} -static void load_GL_ARB_robustness(GLADloadproc load) { - if(!GLAD_GL_ARB_robustness) return; - glad_glGetGraphicsResetStatusARB = (PFNGLGETGRAPHICSRESETSTATUSARBPROC)load("glGetGraphicsResetStatusARB"); - glad_glGetnTexImageARB = (PFNGLGETNTEXIMAGEARBPROC)load("glGetnTexImageARB"); - glad_glReadnPixelsARB = (PFNGLREADNPIXELSARBPROC)load("glReadnPixelsARB"); - glad_glGetnCompressedTexImageARB = (PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC)load("glGetnCompressedTexImageARB"); - glad_glGetnUniformfvARB = (PFNGLGETNUNIFORMFVARBPROC)load("glGetnUniformfvARB"); - glad_glGetnUniformivARB = (PFNGLGETNUNIFORMIVARBPROC)load("glGetnUniformivARB"); - glad_glGetnUniformuivARB = (PFNGLGETNUNIFORMUIVARBPROC)load("glGetnUniformuivARB"); - glad_glGetnUniformdvARB = (PFNGLGETNUNIFORMDVARBPROC)load("glGetnUniformdvARB"); - glad_glGetnMapdvARB = (PFNGLGETNMAPDVARBPROC)load("glGetnMapdvARB"); - glad_glGetnMapfvARB = (PFNGLGETNMAPFVARBPROC)load("glGetnMapfvARB"); - glad_glGetnMapivARB = (PFNGLGETNMAPIVARBPROC)load("glGetnMapivARB"); - glad_glGetnPixelMapfvARB = (PFNGLGETNPIXELMAPFVARBPROC)load("glGetnPixelMapfvARB"); - glad_glGetnPixelMapuivARB = (PFNGLGETNPIXELMAPUIVARBPROC)load("glGetnPixelMapuivARB"); - glad_glGetnPixelMapusvARB = (PFNGLGETNPIXELMAPUSVARBPROC)load("glGetnPixelMapusvARB"); - glad_glGetnPolygonStippleARB = (PFNGLGETNPOLYGONSTIPPLEARBPROC)load("glGetnPolygonStippleARB"); - glad_glGetnColorTableARB = (PFNGLGETNCOLORTABLEARBPROC)load("glGetnColorTableARB"); - glad_glGetnConvolutionFilterARB = (PFNGLGETNCONVOLUTIONFILTERARBPROC)load("glGetnConvolutionFilterARB"); - glad_glGetnSeparableFilterARB = (PFNGLGETNSEPARABLEFILTERARBPROC)load("glGetnSeparableFilterARB"); - glad_glGetnHistogramARB = (PFNGLGETNHISTOGRAMARBPROC)load("glGetnHistogramARB"); - glad_glGetnMinmaxARB = (PFNGLGETNMINMAXARBPROC)load("glGetnMinmaxARB"); -} -static void load_GL_KHR_debug(GLADloadproc load) { - if(!GLAD_GL_KHR_debug) return; - glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)load("glDebugMessageControl"); - glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC)load("glDebugMessageInsert"); - glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)load("glDebugMessageCallback"); - glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)load("glGetDebugMessageLog"); - glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)load("glPushDebugGroup"); - glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)load("glPopDebugGroup"); - glad_glObjectLabel = (PFNGLOBJECTLABELPROC)load("glObjectLabel"); - glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)load("glGetObjectLabel"); - glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)load("glObjectPtrLabel"); - glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)load("glGetObjectPtrLabel"); - glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv"); - glad_glDebugMessageControlKHR = (PFNGLDEBUGMESSAGECONTROLKHRPROC)load("glDebugMessageControlKHR"); - glad_glDebugMessageInsertKHR = (PFNGLDEBUGMESSAGEINSERTKHRPROC)load("glDebugMessageInsertKHR"); - glad_glDebugMessageCallbackKHR = (PFNGLDEBUGMESSAGECALLBACKKHRPROC)load("glDebugMessageCallbackKHR"); - glad_glGetDebugMessageLogKHR = (PFNGLGETDEBUGMESSAGELOGKHRPROC)load("glGetDebugMessageLogKHR"); - glad_glPushDebugGroupKHR = (PFNGLPUSHDEBUGGROUPKHRPROC)load("glPushDebugGroupKHR"); - glad_glPopDebugGroupKHR = (PFNGLPOPDEBUGGROUPKHRPROC)load("glPopDebugGroupKHR"); - glad_glObjectLabelKHR = (PFNGLOBJECTLABELKHRPROC)load("glObjectLabelKHR"); - glad_glGetObjectLabelKHR = (PFNGLGETOBJECTLABELKHRPROC)load("glGetObjectLabelKHR"); - glad_glObjectPtrLabelKHR = (PFNGLOBJECTPTRLABELKHRPROC)load("glObjectPtrLabelKHR"); - glad_glGetObjectPtrLabelKHR = (PFNGLGETOBJECTPTRLABELKHRPROC)load("glGetObjectPtrLabelKHR"); - glad_glGetPointervKHR = (PFNGLGETPOINTERVKHRPROC)load("glGetPointervKHR"); -} -static int find_extensionsGL(void) { - if (!get_exts()) return 0; - GLAD_GL_ARB_multisample = has_ext("GL_ARB_multisample"); - GLAD_GL_ARB_robustness = has_ext("GL_ARB_robustness"); - GLAD_GL_KHR_debug = has_ext("GL_KHR_debug"); - free_exts(); - return 1; -} - -static void find_coreGL(void) { - - /* Thank you @elmindreda - * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 - * https://github.com/glfw/glfw/blob/master/src/context.c#L36 - */ - int i, major, minor; - - const char* version; - const char* prefixes[] = { - "OpenGL ES-CM ", - "OpenGL ES-CL ", - "OpenGL ES ", - NULL - }; - - version = (const char*) glGetString(GL_VERSION); - if (!version) return; - - for (i = 0; prefixes[i]; i++) { - const size_t length = strlen(prefixes[i]); - if (strncmp(version, prefixes[i], length) == 0) { - version += length; - break; - } - } - -/* PR #18 */ -#ifdef _MSC_VER - sscanf_s(version, "%d.%d", &major, &minor); -#else - sscanf(version, "%d.%d", &major, &minor); -#endif - - GLVersion.major = major; GLVersion.minor = minor; - max_loaded_major = major; max_loaded_minor = minor; - GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; - GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; - GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; - GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; - GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; - GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; - GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; - GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; - GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; - GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; - GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; - if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 2)) { - max_loaded_major = 3; - max_loaded_minor = 2; - } -} - -int gladLoadGLLoader(GLADloadproc load) { - GLVersion.major = 0; GLVersion.minor = 0; - glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); - if(glGetString == NULL) return 0; - if(glGetString(GL_VERSION) == NULL) return 0; - find_coreGL(); - load_GL_VERSION_1_0(load); - load_GL_VERSION_1_1(load); - load_GL_VERSION_1_2(load); - load_GL_VERSION_1_3(load); - load_GL_VERSION_1_4(load); - load_GL_VERSION_1_5(load); - load_GL_VERSION_2_0(load); - load_GL_VERSION_2_1(load); - load_GL_VERSION_3_0(load); - load_GL_VERSION_3_1(load); - load_GL_VERSION_3_2(load); - - if (!find_extensionsGL()) return 0; - load_GL_ARB_multisample(load); - load_GL_ARB_robustness(load); - load_GL_KHR_debug(load); - return GLVersion.major != 0 || GLVersion.minor != 0; -} - diff --git a/src/external/glfw/deps/glad/glad.h b/src/external/glfw/deps/glad/glad.h deleted file mode 100644 index 7d81e98e..00000000 --- a/src/external/glfw/deps/glad/glad.h +++ /dev/null @@ -1,3680 +0,0 @@ -/* - - OpenGL loader generated by glad 0.1.12a0 on Fri Sep 23 13:36:15 2016. - - Language/Generator: C/C++ - Specification: gl - APIs: gl=3.2 - Profile: compatibility - Extensions: - GL_ARB_multisample, - GL_ARB_robustness, - GL_KHR_debug - Loader: False - Local files: False - Omit khrplatform: False - - Commandline: - --profile="compatibility" --api="gl=3.2" --generator="c" --spec="gl" --no-loader --extensions="GL_ARB_multisample,GL_ARB_robustness,GL_KHR_debug" - Online: - http://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&api=gl%3D3.2&extensions=GL_ARB_multisample&extensions=GL_ARB_robustness&extensions=GL_KHR_debug -*/ - - -#ifndef __glad_h_ -#define __glad_h_ - -#ifdef __gl_h_ -#error OpenGL header already included, remove this include, glad already provides it -#endif -#define __gl_h_ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#include -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct gladGLversionStruct { - int major; - int minor; -}; - -typedef void* (* GLADloadproc)(const char *name); - -#ifndef GLAPI -# if defined(GLAD_GLAPI_EXPORT) -# if defined(WIN32) || defined(__CYGWIN__) -# if defined(GLAD_GLAPI_EXPORT_BUILD) -# if defined(__GNUC__) -# define GLAPI __attribute__ ((dllexport)) extern -# else -# define GLAPI __declspec(dllexport) extern -# endif -# else -# if defined(__GNUC__) -# define GLAPI __attribute__ ((dllimport)) extern -# else -# define GLAPI __declspec(dllimport) extern -# endif -# endif -# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) -# define GLAPI __attribute__ ((visibility ("default"))) extern -# else -# define GLAPI extern -# endif -# else -# define GLAPI extern -# endif -#endif - -GLAPI struct gladGLversionStruct GLVersion; -GLAPI int gladLoadGLLoader(GLADloadproc); - -#include -#include -#ifndef GLEXT_64_TYPES_DEFINED -/* This code block is duplicated in glxext.h, so must be protected */ -#define GLEXT_64_TYPES_DEFINED -/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ -/* (as used in the GL_EXT_timer_query extension). */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#include -#elif defined(__sun__) || defined(__digital__) -#include -#if defined(__STDC__) -#if defined(__arch64__) || defined(_LP64) -typedef long int int64_t; -typedef unsigned long int uint64_t; -#else -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#endif /* __arch64__ */ -#endif /* __STDC__ */ -#elif defined( __VMS ) || defined(__sgi) -#include -#elif defined(__SCO__) || defined(__USLC__) -#include -#elif defined(__UNIXOS2__) || defined(__SOL64__) -typedef long int int32_t; -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#elif defined(_WIN32) && defined(__GNUC__) -#include -#elif defined(_WIN32) -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -/* Fallback if nothing above works */ -#include -#endif -#endif -typedef unsigned int GLenum; -typedef unsigned char GLboolean; -typedef unsigned int GLbitfield; -typedef void GLvoid; -typedef signed char GLbyte; -typedef short GLshort; -typedef int GLint; -typedef int GLclampx; -typedef unsigned char GLubyte; -typedef unsigned short GLushort; -typedef unsigned int GLuint; -typedef int GLsizei; -typedef float GLfloat; -typedef float GLclampf; -typedef double GLdouble; -typedef double GLclampd; -typedef void *GLeglImageOES; -typedef char GLchar; -typedef char GLcharARB; -#ifdef __APPLE__ -typedef void *GLhandleARB; -#else -typedef unsigned int GLhandleARB; -#endif -typedef unsigned short GLhalfARB; -typedef unsigned short GLhalf; -typedef GLint GLfixed; -typedef ptrdiff_t GLintptr; -typedef ptrdiff_t GLsizeiptr; -typedef int64_t GLint64; -typedef uint64_t GLuint64; -typedef ptrdiff_t GLintptrARB; -typedef ptrdiff_t GLsizeiptrARB; -typedef int64_t GLint64EXT; -typedef uint64_t GLuint64EXT; -typedef struct __GLsync *GLsync; -struct _cl_context; -struct _cl_event; -typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); -typedef unsigned short GLhalfNV; -typedef GLintptr GLvdpauSurfaceNV; -#define GL_DEPTH_BUFFER_BIT 0x00000100 -#define GL_STENCIL_BUFFER_BIT 0x00000400 -#define GL_COLOR_BUFFER_BIT 0x00004000 -#define GL_FALSE 0 -#define GL_TRUE 1 -#define GL_POINTS 0x0000 -#define GL_LINES 0x0001 -#define GL_LINE_LOOP 0x0002 -#define GL_LINE_STRIP 0x0003 -#define GL_TRIANGLES 0x0004 -#define GL_TRIANGLE_STRIP 0x0005 -#define GL_TRIANGLE_FAN 0x0006 -#define GL_QUADS 0x0007 -#define GL_NEVER 0x0200 -#define GL_LESS 0x0201 -#define GL_EQUAL 0x0202 -#define GL_LEQUAL 0x0203 -#define GL_GREATER 0x0204 -#define GL_NOTEQUAL 0x0205 -#define GL_GEQUAL 0x0206 -#define GL_ALWAYS 0x0207 -#define GL_ZERO 0 -#define GL_ONE 1 -#define GL_SRC_COLOR 0x0300 -#define GL_ONE_MINUS_SRC_COLOR 0x0301 -#define GL_SRC_ALPHA 0x0302 -#define GL_ONE_MINUS_SRC_ALPHA 0x0303 -#define GL_DST_ALPHA 0x0304 -#define GL_ONE_MINUS_DST_ALPHA 0x0305 -#define GL_DST_COLOR 0x0306 -#define GL_ONE_MINUS_DST_COLOR 0x0307 -#define GL_SRC_ALPHA_SATURATE 0x0308 -#define GL_NONE 0 -#define GL_FRONT_LEFT 0x0400 -#define GL_FRONT_RIGHT 0x0401 -#define GL_BACK_LEFT 0x0402 -#define GL_BACK_RIGHT 0x0403 -#define GL_FRONT 0x0404 -#define GL_BACK 0x0405 -#define GL_LEFT 0x0406 -#define GL_RIGHT 0x0407 -#define GL_FRONT_AND_BACK 0x0408 -#define GL_NO_ERROR 0 -#define GL_INVALID_ENUM 0x0500 -#define GL_INVALID_VALUE 0x0501 -#define GL_INVALID_OPERATION 0x0502 -#define GL_OUT_OF_MEMORY 0x0505 -#define GL_CW 0x0900 -#define GL_CCW 0x0901 -#define GL_POINT_SIZE 0x0B11 -#define GL_POINT_SIZE_RANGE 0x0B12 -#define GL_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_LINE_SMOOTH 0x0B20 -#define GL_LINE_WIDTH 0x0B21 -#define GL_LINE_WIDTH_RANGE 0x0B22 -#define GL_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_POLYGON_MODE 0x0B40 -#define GL_POLYGON_SMOOTH 0x0B41 -#define GL_CULL_FACE 0x0B44 -#define GL_CULL_FACE_MODE 0x0B45 -#define GL_FRONT_FACE 0x0B46 -#define GL_DEPTH_RANGE 0x0B70 -#define GL_DEPTH_TEST 0x0B71 -#define GL_DEPTH_WRITEMASK 0x0B72 -#define GL_DEPTH_CLEAR_VALUE 0x0B73 -#define GL_DEPTH_FUNC 0x0B74 -#define GL_STENCIL_TEST 0x0B90 -#define GL_STENCIL_CLEAR_VALUE 0x0B91 -#define GL_STENCIL_FUNC 0x0B92 -#define GL_STENCIL_VALUE_MASK 0x0B93 -#define GL_STENCIL_FAIL 0x0B94 -#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 -#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 -#define GL_STENCIL_REF 0x0B97 -#define GL_STENCIL_WRITEMASK 0x0B98 -#define GL_VIEWPORT 0x0BA2 -#define GL_DITHER 0x0BD0 -#define GL_BLEND_DST 0x0BE0 -#define GL_BLEND_SRC 0x0BE1 -#define GL_BLEND 0x0BE2 -#define GL_LOGIC_OP_MODE 0x0BF0 -#define GL_COLOR_LOGIC_OP 0x0BF2 -#define GL_DRAW_BUFFER 0x0C01 -#define GL_READ_BUFFER 0x0C02 -#define GL_SCISSOR_BOX 0x0C10 -#define GL_SCISSOR_TEST 0x0C11 -#define GL_COLOR_CLEAR_VALUE 0x0C22 -#define GL_COLOR_WRITEMASK 0x0C23 -#define GL_DOUBLEBUFFER 0x0C32 -#define GL_STEREO 0x0C33 -#define GL_LINE_SMOOTH_HINT 0x0C52 -#define GL_POLYGON_SMOOTH_HINT 0x0C53 -#define GL_UNPACK_SWAP_BYTES 0x0CF0 -#define GL_UNPACK_LSB_FIRST 0x0CF1 -#define GL_UNPACK_ROW_LENGTH 0x0CF2 -#define GL_UNPACK_SKIP_ROWS 0x0CF3 -#define GL_UNPACK_SKIP_PIXELS 0x0CF4 -#define GL_UNPACK_ALIGNMENT 0x0CF5 -#define GL_PACK_SWAP_BYTES 0x0D00 -#define GL_PACK_LSB_FIRST 0x0D01 -#define GL_PACK_ROW_LENGTH 0x0D02 -#define GL_PACK_SKIP_ROWS 0x0D03 -#define GL_PACK_SKIP_PIXELS 0x0D04 -#define GL_PACK_ALIGNMENT 0x0D05 -#define GL_MAX_TEXTURE_SIZE 0x0D33 -#define GL_MAX_VIEWPORT_DIMS 0x0D3A -#define GL_SUBPIXEL_BITS 0x0D50 -#define GL_TEXTURE_1D 0x0DE0 -#define GL_TEXTURE_2D 0x0DE1 -#define GL_POLYGON_OFFSET_UNITS 0x2A00 -#define GL_POLYGON_OFFSET_POINT 0x2A01 -#define GL_POLYGON_OFFSET_LINE 0x2A02 -#define GL_POLYGON_OFFSET_FILL 0x8037 -#define GL_POLYGON_OFFSET_FACTOR 0x8038 -#define GL_TEXTURE_BINDING_1D 0x8068 -#define GL_TEXTURE_BINDING_2D 0x8069 -#define GL_TEXTURE_WIDTH 0x1000 -#define GL_TEXTURE_HEIGHT 0x1001 -#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 -#define GL_TEXTURE_BORDER_COLOR 0x1004 -#define GL_TEXTURE_RED_SIZE 0x805C -#define GL_TEXTURE_GREEN_SIZE 0x805D -#define GL_TEXTURE_BLUE_SIZE 0x805E -#define GL_TEXTURE_ALPHA_SIZE 0x805F -#define GL_DONT_CARE 0x1100 -#define GL_FASTEST 0x1101 -#define GL_NICEST 0x1102 -#define GL_BYTE 0x1400 -#define GL_UNSIGNED_BYTE 0x1401 -#define GL_SHORT 0x1402 -#define GL_UNSIGNED_SHORT 0x1403 -#define GL_INT 0x1404 -#define GL_UNSIGNED_INT 0x1405 -#define GL_FLOAT 0x1406 -#define GL_DOUBLE 0x140A -#define GL_STACK_OVERFLOW 0x0503 -#define GL_STACK_UNDERFLOW 0x0504 -#define GL_CLEAR 0x1500 -#define GL_AND 0x1501 -#define GL_AND_REVERSE 0x1502 -#define GL_COPY 0x1503 -#define GL_AND_INVERTED 0x1504 -#define GL_NOOP 0x1505 -#define GL_XOR 0x1506 -#define GL_OR 0x1507 -#define GL_NOR 0x1508 -#define GL_EQUIV 0x1509 -#define GL_INVERT 0x150A -#define GL_OR_REVERSE 0x150B -#define GL_COPY_INVERTED 0x150C -#define GL_OR_INVERTED 0x150D -#define GL_NAND 0x150E -#define GL_SET 0x150F -#define GL_TEXTURE 0x1702 -#define GL_COLOR 0x1800 -#define GL_DEPTH 0x1801 -#define GL_STENCIL 0x1802 -#define GL_STENCIL_INDEX 0x1901 -#define GL_DEPTH_COMPONENT 0x1902 -#define GL_RED 0x1903 -#define GL_GREEN 0x1904 -#define GL_BLUE 0x1905 -#define GL_ALPHA 0x1906 -#define GL_RGB 0x1907 -#define GL_RGBA 0x1908 -#define GL_POINT 0x1B00 -#define GL_LINE 0x1B01 -#define GL_FILL 0x1B02 -#define GL_KEEP 0x1E00 -#define GL_REPLACE 0x1E01 -#define GL_INCR 0x1E02 -#define GL_DECR 0x1E03 -#define GL_VENDOR 0x1F00 -#define GL_RENDERER 0x1F01 -#define GL_VERSION 0x1F02 -#define GL_EXTENSIONS 0x1F03 -#define GL_NEAREST 0x2600 -#define GL_LINEAR 0x2601 -#define GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define GL_LINEAR_MIPMAP_LINEAR 0x2703 -#define GL_TEXTURE_MAG_FILTER 0x2800 -#define GL_TEXTURE_MIN_FILTER 0x2801 -#define GL_TEXTURE_WRAP_S 0x2802 -#define GL_TEXTURE_WRAP_T 0x2803 -#define GL_PROXY_TEXTURE_1D 0x8063 -#define GL_PROXY_TEXTURE_2D 0x8064 -#define GL_REPEAT 0x2901 -#define GL_R3_G3_B2 0x2A10 -#define GL_RGB4 0x804F -#define GL_RGB5 0x8050 -#define GL_RGB8 0x8051 -#define GL_RGB10 0x8052 -#define GL_RGB12 0x8053 -#define GL_RGB16 0x8054 -#define GL_RGBA2 0x8055 -#define GL_RGBA4 0x8056 -#define GL_RGB5_A1 0x8057 -#define GL_RGBA8 0x8058 -#define GL_RGB10_A2 0x8059 -#define GL_RGBA12 0x805A -#define GL_RGBA16 0x805B -#define GL_CURRENT_BIT 0x00000001 -#define GL_POINT_BIT 0x00000002 -#define GL_LINE_BIT 0x00000004 -#define GL_POLYGON_BIT 0x00000008 -#define GL_POLYGON_STIPPLE_BIT 0x00000010 -#define GL_PIXEL_MODE_BIT 0x00000020 -#define GL_LIGHTING_BIT 0x00000040 -#define GL_FOG_BIT 0x00000080 -#define GL_ACCUM_BUFFER_BIT 0x00000200 -#define GL_VIEWPORT_BIT 0x00000800 -#define GL_TRANSFORM_BIT 0x00001000 -#define GL_ENABLE_BIT 0x00002000 -#define GL_HINT_BIT 0x00008000 -#define GL_EVAL_BIT 0x00010000 -#define GL_LIST_BIT 0x00020000 -#define GL_TEXTURE_BIT 0x00040000 -#define GL_SCISSOR_BIT 0x00080000 -#define GL_ALL_ATTRIB_BITS 0xFFFFFFFF -#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 -#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 -#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF -#define GL_QUAD_STRIP 0x0008 -#define GL_POLYGON 0x0009 -#define GL_ACCUM 0x0100 -#define GL_LOAD 0x0101 -#define GL_RETURN 0x0102 -#define GL_MULT 0x0103 -#define GL_ADD 0x0104 -#define GL_AUX0 0x0409 -#define GL_AUX1 0x040A -#define GL_AUX2 0x040B -#define GL_AUX3 0x040C -#define GL_2D 0x0600 -#define GL_3D 0x0601 -#define GL_3D_COLOR 0x0602 -#define GL_3D_COLOR_TEXTURE 0x0603 -#define GL_4D_COLOR_TEXTURE 0x0604 -#define GL_PASS_THROUGH_TOKEN 0x0700 -#define GL_POINT_TOKEN 0x0701 -#define GL_LINE_TOKEN 0x0702 -#define GL_POLYGON_TOKEN 0x0703 -#define GL_BITMAP_TOKEN 0x0704 -#define GL_DRAW_PIXEL_TOKEN 0x0705 -#define GL_COPY_PIXEL_TOKEN 0x0706 -#define GL_LINE_RESET_TOKEN 0x0707 -#define GL_EXP 0x0800 -#define GL_EXP2 0x0801 -#define GL_COEFF 0x0A00 -#define GL_ORDER 0x0A01 -#define GL_DOMAIN 0x0A02 -#define GL_PIXEL_MAP_I_TO_I 0x0C70 -#define GL_PIXEL_MAP_S_TO_S 0x0C71 -#define GL_PIXEL_MAP_I_TO_R 0x0C72 -#define GL_PIXEL_MAP_I_TO_G 0x0C73 -#define GL_PIXEL_MAP_I_TO_B 0x0C74 -#define GL_PIXEL_MAP_I_TO_A 0x0C75 -#define GL_PIXEL_MAP_R_TO_R 0x0C76 -#define GL_PIXEL_MAP_G_TO_G 0x0C77 -#define GL_PIXEL_MAP_B_TO_B 0x0C78 -#define GL_PIXEL_MAP_A_TO_A 0x0C79 -#define GL_VERTEX_ARRAY_POINTER 0x808E -#define GL_NORMAL_ARRAY_POINTER 0x808F -#define GL_COLOR_ARRAY_POINTER 0x8090 -#define GL_INDEX_ARRAY_POINTER 0x8091 -#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 -#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 -#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 -#define GL_SELECTION_BUFFER_POINTER 0x0DF3 -#define GL_CURRENT_COLOR 0x0B00 -#define GL_CURRENT_INDEX 0x0B01 -#define GL_CURRENT_NORMAL 0x0B02 -#define GL_CURRENT_TEXTURE_COORDS 0x0B03 -#define GL_CURRENT_RASTER_COLOR 0x0B04 -#define GL_CURRENT_RASTER_INDEX 0x0B05 -#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 -#define GL_CURRENT_RASTER_POSITION 0x0B07 -#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 -#define GL_CURRENT_RASTER_DISTANCE 0x0B09 -#define GL_POINT_SMOOTH 0x0B10 -#define GL_LINE_STIPPLE 0x0B24 -#define GL_LINE_STIPPLE_PATTERN 0x0B25 -#define GL_LINE_STIPPLE_REPEAT 0x0B26 -#define GL_LIST_MODE 0x0B30 -#define GL_MAX_LIST_NESTING 0x0B31 -#define GL_LIST_BASE 0x0B32 -#define GL_LIST_INDEX 0x0B33 -#define GL_POLYGON_STIPPLE 0x0B42 -#define GL_EDGE_FLAG 0x0B43 -#define GL_LIGHTING 0x0B50 -#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 -#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 -#define GL_LIGHT_MODEL_AMBIENT 0x0B53 -#define GL_SHADE_MODEL 0x0B54 -#define GL_COLOR_MATERIAL_FACE 0x0B55 -#define GL_COLOR_MATERIAL_PARAMETER 0x0B56 -#define GL_COLOR_MATERIAL 0x0B57 -#define GL_FOG 0x0B60 -#define GL_FOG_INDEX 0x0B61 -#define GL_FOG_DENSITY 0x0B62 -#define GL_FOG_START 0x0B63 -#define GL_FOG_END 0x0B64 -#define GL_FOG_MODE 0x0B65 -#define GL_FOG_COLOR 0x0B66 -#define GL_ACCUM_CLEAR_VALUE 0x0B80 -#define GL_MATRIX_MODE 0x0BA0 -#define GL_NORMALIZE 0x0BA1 -#define GL_MODELVIEW_STACK_DEPTH 0x0BA3 -#define GL_PROJECTION_STACK_DEPTH 0x0BA4 -#define GL_TEXTURE_STACK_DEPTH 0x0BA5 -#define GL_MODELVIEW_MATRIX 0x0BA6 -#define GL_PROJECTION_MATRIX 0x0BA7 -#define GL_TEXTURE_MATRIX 0x0BA8 -#define GL_ATTRIB_STACK_DEPTH 0x0BB0 -#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 -#define GL_ALPHA_TEST 0x0BC0 -#define GL_ALPHA_TEST_FUNC 0x0BC1 -#define GL_ALPHA_TEST_REF 0x0BC2 -#define GL_INDEX_LOGIC_OP 0x0BF1 -#define GL_LOGIC_OP 0x0BF1 -#define GL_AUX_BUFFERS 0x0C00 -#define GL_INDEX_CLEAR_VALUE 0x0C20 -#define GL_INDEX_WRITEMASK 0x0C21 -#define GL_INDEX_MODE 0x0C30 -#define GL_RGBA_MODE 0x0C31 -#define GL_RENDER_MODE 0x0C40 -#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 -#define GL_POINT_SMOOTH_HINT 0x0C51 -#define GL_FOG_HINT 0x0C54 -#define GL_TEXTURE_GEN_S 0x0C60 -#define GL_TEXTURE_GEN_T 0x0C61 -#define GL_TEXTURE_GEN_R 0x0C62 -#define GL_TEXTURE_GEN_Q 0x0C63 -#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 -#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 -#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 -#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 -#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 -#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 -#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 -#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 -#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 -#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 -#define GL_MAP_COLOR 0x0D10 -#define GL_MAP_STENCIL 0x0D11 -#define GL_INDEX_SHIFT 0x0D12 -#define GL_INDEX_OFFSET 0x0D13 -#define GL_RED_SCALE 0x0D14 -#define GL_RED_BIAS 0x0D15 -#define GL_ZOOM_X 0x0D16 -#define GL_ZOOM_Y 0x0D17 -#define GL_GREEN_SCALE 0x0D18 -#define GL_GREEN_BIAS 0x0D19 -#define GL_BLUE_SCALE 0x0D1A -#define GL_BLUE_BIAS 0x0D1B -#define GL_ALPHA_SCALE 0x0D1C -#define GL_ALPHA_BIAS 0x0D1D -#define GL_DEPTH_SCALE 0x0D1E -#define GL_DEPTH_BIAS 0x0D1F -#define GL_MAX_EVAL_ORDER 0x0D30 -#define GL_MAX_LIGHTS 0x0D31 -#define GL_MAX_CLIP_PLANES 0x0D32 -#define GL_MAX_PIXEL_MAP_TABLE 0x0D34 -#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 -#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 -#define GL_MAX_NAME_STACK_DEPTH 0x0D37 -#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 -#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 -#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B -#define GL_INDEX_BITS 0x0D51 -#define GL_RED_BITS 0x0D52 -#define GL_GREEN_BITS 0x0D53 -#define GL_BLUE_BITS 0x0D54 -#define GL_ALPHA_BITS 0x0D55 -#define GL_DEPTH_BITS 0x0D56 -#define GL_STENCIL_BITS 0x0D57 -#define GL_ACCUM_RED_BITS 0x0D58 -#define GL_ACCUM_GREEN_BITS 0x0D59 -#define GL_ACCUM_BLUE_BITS 0x0D5A -#define GL_ACCUM_ALPHA_BITS 0x0D5B -#define GL_NAME_STACK_DEPTH 0x0D70 -#define GL_AUTO_NORMAL 0x0D80 -#define GL_MAP1_COLOR_4 0x0D90 -#define GL_MAP1_INDEX 0x0D91 -#define GL_MAP1_NORMAL 0x0D92 -#define GL_MAP1_TEXTURE_COORD_1 0x0D93 -#define GL_MAP1_TEXTURE_COORD_2 0x0D94 -#define GL_MAP1_TEXTURE_COORD_3 0x0D95 -#define GL_MAP1_TEXTURE_COORD_4 0x0D96 -#define GL_MAP1_VERTEX_3 0x0D97 -#define GL_MAP1_VERTEX_4 0x0D98 -#define GL_MAP2_COLOR_4 0x0DB0 -#define GL_MAP2_INDEX 0x0DB1 -#define GL_MAP2_NORMAL 0x0DB2 -#define GL_MAP2_TEXTURE_COORD_1 0x0DB3 -#define GL_MAP2_TEXTURE_COORD_2 0x0DB4 -#define GL_MAP2_TEXTURE_COORD_3 0x0DB5 -#define GL_MAP2_TEXTURE_COORD_4 0x0DB6 -#define GL_MAP2_VERTEX_3 0x0DB7 -#define GL_MAP2_VERTEX_4 0x0DB8 -#define GL_MAP1_GRID_DOMAIN 0x0DD0 -#define GL_MAP1_GRID_SEGMENTS 0x0DD1 -#define GL_MAP2_GRID_DOMAIN 0x0DD2 -#define GL_MAP2_GRID_SEGMENTS 0x0DD3 -#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 -#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 -#define GL_SELECTION_BUFFER_SIZE 0x0DF4 -#define GL_VERTEX_ARRAY 0x8074 -#define GL_NORMAL_ARRAY 0x8075 -#define GL_COLOR_ARRAY 0x8076 -#define GL_INDEX_ARRAY 0x8077 -#define GL_TEXTURE_COORD_ARRAY 0x8078 -#define GL_EDGE_FLAG_ARRAY 0x8079 -#define GL_VERTEX_ARRAY_SIZE 0x807A -#define GL_VERTEX_ARRAY_TYPE 0x807B -#define GL_VERTEX_ARRAY_STRIDE 0x807C -#define GL_NORMAL_ARRAY_TYPE 0x807E -#define GL_NORMAL_ARRAY_STRIDE 0x807F -#define GL_COLOR_ARRAY_SIZE 0x8081 -#define GL_COLOR_ARRAY_TYPE 0x8082 -#define GL_COLOR_ARRAY_STRIDE 0x8083 -#define GL_INDEX_ARRAY_TYPE 0x8085 -#define GL_INDEX_ARRAY_STRIDE 0x8086 -#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 -#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 -#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A -#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C -#define GL_TEXTURE_COMPONENTS 0x1003 -#define GL_TEXTURE_BORDER 0x1005 -#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 -#define GL_TEXTURE_INTENSITY_SIZE 0x8061 -#define GL_TEXTURE_PRIORITY 0x8066 -#define GL_TEXTURE_RESIDENT 0x8067 -#define GL_AMBIENT 0x1200 -#define GL_DIFFUSE 0x1201 -#define GL_SPECULAR 0x1202 -#define GL_POSITION 0x1203 -#define GL_SPOT_DIRECTION 0x1204 -#define GL_SPOT_EXPONENT 0x1205 -#define GL_SPOT_CUTOFF 0x1206 -#define GL_CONSTANT_ATTENUATION 0x1207 -#define GL_LINEAR_ATTENUATION 0x1208 -#define GL_QUADRATIC_ATTENUATION 0x1209 -#define GL_COMPILE 0x1300 -#define GL_COMPILE_AND_EXECUTE 0x1301 -#define GL_2_BYTES 0x1407 -#define GL_3_BYTES 0x1408 -#define GL_4_BYTES 0x1409 -#define GL_EMISSION 0x1600 -#define GL_SHININESS 0x1601 -#define GL_AMBIENT_AND_DIFFUSE 0x1602 -#define GL_COLOR_INDEXES 0x1603 -#define GL_MODELVIEW 0x1700 -#define GL_PROJECTION 0x1701 -#define GL_COLOR_INDEX 0x1900 -#define GL_LUMINANCE 0x1909 -#define GL_LUMINANCE_ALPHA 0x190A -#define GL_BITMAP 0x1A00 -#define GL_RENDER 0x1C00 -#define GL_FEEDBACK 0x1C01 -#define GL_SELECT 0x1C02 -#define GL_FLAT 0x1D00 -#define GL_SMOOTH 0x1D01 -#define GL_S 0x2000 -#define GL_T 0x2001 -#define GL_R 0x2002 -#define GL_Q 0x2003 -#define GL_MODULATE 0x2100 -#define GL_DECAL 0x2101 -#define GL_TEXTURE_ENV_MODE 0x2200 -#define GL_TEXTURE_ENV_COLOR 0x2201 -#define GL_TEXTURE_ENV 0x2300 -#define GL_EYE_LINEAR 0x2400 -#define GL_OBJECT_LINEAR 0x2401 -#define GL_SPHERE_MAP 0x2402 -#define GL_TEXTURE_GEN_MODE 0x2500 -#define GL_OBJECT_PLANE 0x2501 -#define GL_EYE_PLANE 0x2502 -#define GL_CLAMP 0x2900 -#define GL_ALPHA4 0x803B -#define GL_ALPHA8 0x803C -#define GL_ALPHA12 0x803D -#define GL_ALPHA16 0x803E -#define GL_LUMINANCE4 0x803F -#define GL_LUMINANCE8 0x8040 -#define GL_LUMINANCE12 0x8041 -#define GL_LUMINANCE16 0x8042 -#define GL_LUMINANCE4_ALPHA4 0x8043 -#define GL_LUMINANCE6_ALPHA2 0x8044 -#define GL_LUMINANCE8_ALPHA8 0x8045 -#define GL_LUMINANCE12_ALPHA4 0x8046 -#define GL_LUMINANCE12_ALPHA12 0x8047 -#define GL_LUMINANCE16_ALPHA16 0x8048 -#define GL_INTENSITY 0x8049 -#define GL_INTENSITY4 0x804A -#define GL_INTENSITY8 0x804B -#define GL_INTENSITY12 0x804C -#define GL_INTENSITY16 0x804D -#define GL_V2F 0x2A20 -#define GL_V3F 0x2A21 -#define GL_C4UB_V2F 0x2A22 -#define GL_C4UB_V3F 0x2A23 -#define GL_C3F_V3F 0x2A24 -#define GL_N3F_V3F 0x2A25 -#define GL_C4F_N3F_V3F 0x2A26 -#define GL_T2F_V3F 0x2A27 -#define GL_T4F_V4F 0x2A28 -#define GL_T2F_C4UB_V3F 0x2A29 -#define GL_T2F_C3F_V3F 0x2A2A -#define GL_T2F_N3F_V3F 0x2A2B -#define GL_T2F_C4F_N3F_V3F 0x2A2C -#define GL_T4F_C4F_N3F_V4F 0x2A2D -#define GL_CLIP_PLANE0 0x3000 -#define GL_CLIP_PLANE1 0x3001 -#define GL_CLIP_PLANE2 0x3002 -#define GL_CLIP_PLANE3 0x3003 -#define GL_CLIP_PLANE4 0x3004 -#define GL_CLIP_PLANE5 0x3005 -#define GL_LIGHT0 0x4000 -#define GL_LIGHT1 0x4001 -#define GL_LIGHT2 0x4002 -#define GL_LIGHT3 0x4003 -#define GL_LIGHT4 0x4004 -#define GL_LIGHT5 0x4005 -#define GL_LIGHT6 0x4006 -#define GL_LIGHT7 0x4007 -#define GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_UNSIGNED_INT_8_8_8_8 0x8035 -#define GL_UNSIGNED_INT_10_10_10_2 0x8036 -#define GL_TEXTURE_BINDING_3D 0x806A -#define GL_PACK_SKIP_IMAGES 0x806B -#define GL_PACK_IMAGE_HEIGHT 0x806C -#define GL_UNPACK_SKIP_IMAGES 0x806D -#define GL_UNPACK_IMAGE_HEIGHT 0x806E -#define GL_TEXTURE_3D 0x806F -#define GL_PROXY_TEXTURE_3D 0x8070 -#define GL_TEXTURE_DEPTH 0x8071 -#define GL_TEXTURE_WRAP_R 0x8072 -#define GL_MAX_3D_TEXTURE_SIZE 0x8073 -#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#define GL_BGR 0x80E0 -#define GL_BGRA 0x80E1 -#define GL_MAX_ELEMENTS_VERTICES 0x80E8 -#define GL_MAX_ELEMENTS_INDICES 0x80E9 -#define GL_CLAMP_TO_EDGE 0x812F -#define GL_TEXTURE_MIN_LOD 0x813A -#define GL_TEXTURE_MAX_LOD 0x813B -#define GL_TEXTURE_BASE_LEVEL 0x813C -#define GL_TEXTURE_MAX_LEVEL 0x813D -#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 -#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 -#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E -#define GL_RESCALE_NORMAL 0x803A -#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 -#define GL_SINGLE_COLOR 0x81F9 -#define GL_SEPARATE_SPECULAR_COLOR 0x81FA -#define GL_ALIASED_POINT_SIZE_RANGE 0x846D -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE2 0x84C2 -#define GL_TEXTURE3 0x84C3 -#define GL_TEXTURE4 0x84C4 -#define GL_TEXTURE5 0x84C5 -#define GL_TEXTURE6 0x84C6 -#define GL_TEXTURE7 0x84C7 -#define GL_TEXTURE8 0x84C8 -#define GL_TEXTURE9 0x84C9 -#define GL_TEXTURE10 0x84CA -#define GL_TEXTURE11 0x84CB -#define GL_TEXTURE12 0x84CC -#define GL_TEXTURE13 0x84CD -#define GL_TEXTURE14 0x84CE -#define GL_TEXTURE15 0x84CF -#define GL_TEXTURE16 0x84D0 -#define GL_TEXTURE17 0x84D1 -#define GL_TEXTURE18 0x84D2 -#define GL_TEXTURE19 0x84D3 -#define GL_TEXTURE20 0x84D4 -#define GL_TEXTURE21 0x84D5 -#define GL_TEXTURE22 0x84D6 -#define GL_TEXTURE23 0x84D7 -#define GL_TEXTURE24 0x84D8 -#define GL_TEXTURE25 0x84D9 -#define GL_TEXTURE26 0x84DA -#define GL_TEXTURE27 0x84DB -#define GL_TEXTURE28 0x84DC -#define GL_TEXTURE29 0x84DD -#define GL_TEXTURE30 0x84DE -#define GL_TEXTURE31 0x84DF -#define GL_ACTIVE_TEXTURE 0x84E0 -#define GL_MULTISAMPLE 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE 0x809F -#define GL_SAMPLE_COVERAGE 0x80A0 -#define GL_SAMPLE_BUFFERS 0x80A8 -#define GL_SAMPLES 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT 0x80AB -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -#define GL_COMPRESSED_RGB 0x84ED -#define GL_COMPRESSED_RGBA 0x84EE -#define GL_TEXTURE_COMPRESSION_HINT 0x84EF -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 -#define GL_TEXTURE_COMPRESSED 0x86A1 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 -#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 -#define GL_CLAMP_TO_BORDER 0x812D -#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 -#define GL_MAX_TEXTURE_UNITS 0x84E2 -#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 -#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 -#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 -#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 -#define GL_MULTISAMPLE_BIT 0x20000000 -#define GL_NORMAL_MAP 0x8511 -#define GL_REFLECTION_MAP 0x8512 -#define GL_COMPRESSED_ALPHA 0x84E9 -#define GL_COMPRESSED_LUMINANCE 0x84EA -#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB -#define GL_COMPRESSED_INTENSITY 0x84EC -#define GL_COMBINE 0x8570 -#define GL_COMBINE_RGB 0x8571 -#define GL_COMBINE_ALPHA 0x8572 -#define GL_SOURCE0_RGB 0x8580 -#define GL_SOURCE1_RGB 0x8581 -#define GL_SOURCE2_RGB 0x8582 -#define GL_SOURCE0_ALPHA 0x8588 -#define GL_SOURCE1_ALPHA 0x8589 -#define GL_SOURCE2_ALPHA 0x858A -#define GL_OPERAND0_RGB 0x8590 -#define GL_OPERAND1_RGB 0x8591 -#define GL_OPERAND2_RGB 0x8592 -#define GL_OPERAND0_ALPHA 0x8598 -#define GL_OPERAND1_ALPHA 0x8599 -#define GL_OPERAND2_ALPHA 0x859A -#define GL_RGB_SCALE 0x8573 -#define GL_ADD_SIGNED 0x8574 -#define GL_INTERPOLATE 0x8575 -#define GL_SUBTRACT 0x84E7 -#define GL_CONSTANT 0x8576 -#define GL_PRIMARY_COLOR 0x8577 -#define GL_PREVIOUS 0x8578 -#define GL_DOT3_RGB 0x86AE -#define GL_DOT3_RGBA 0x86AF -#define GL_BLEND_DST_RGB 0x80C8 -#define GL_BLEND_SRC_RGB 0x80C9 -#define GL_BLEND_DST_ALPHA 0x80CA -#define GL_BLEND_SRC_ALPHA 0x80CB -#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_DEPTH_COMPONENT24 0x81A6 -#define GL_DEPTH_COMPONENT32 0x81A7 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD -#define GL_TEXTURE_LOD_BIAS 0x8501 -#define GL_INCR_WRAP 0x8507 -#define GL_DECR_WRAP 0x8508 -#define GL_TEXTURE_DEPTH_SIZE 0x884A -#define GL_TEXTURE_COMPARE_MODE 0x884C -#define GL_TEXTURE_COMPARE_FUNC 0x884D -#define GL_POINT_SIZE_MIN 0x8126 -#define GL_POINT_SIZE_MAX 0x8127 -#define GL_POINT_DISTANCE_ATTENUATION 0x8129 -#define GL_GENERATE_MIPMAP 0x8191 -#define GL_GENERATE_MIPMAP_HINT 0x8192 -#define GL_FOG_COORDINATE_SOURCE 0x8450 -#define GL_FOG_COORDINATE 0x8451 -#define GL_FRAGMENT_DEPTH 0x8452 -#define GL_CURRENT_FOG_COORDINATE 0x8453 -#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 -#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 -#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 -#define GL_FOG_COORDINATE_ARRAY 0x8457 -#define GL_COLOR_SUM 0x8458 -#define GL_CURRENT_SECONDARY_COLOR 0x8459 -#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A -#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B -#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C -#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D -#define GL_SECONDARY_COLOR_ARRAY 0x845E -#define GL_TEXTURE_FILTER_CONTROL 0x8500 -#define GL_DEPTH_TEXTURE_MODE 0x884B -#define GL_COMPARE_R_TO_TEXTURE 0x884E -#define GL_FUNC_ADD 0x8006 -#define GL_FUNC_SUBTRACT 0x800A -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#define GL_MIN 0x8007 -#define GL_MAX 0x8008 -#define GL_CONSTANT_COLOR 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_USAGE 0x8765 -#define GL_QUERY_COUNTER_BITS 0x8864 -#define GL_CURRENT_QUERY 0x8865 -#define GL_QUERY_RESULT 0x8866 -#define GL_QUERY_RESULT_AVAILABLE 0x8867 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_READ_ONLY 0x88B8 -#define GL_WRITE_ONLY 0x88B9 -#define GL_READ_WRITE 0x88BA -#define GL_BUFFER_ACCESS 0x88BB -#define GL_BUFFER_MAPPED 0x88BC -#define GL_BUFFER_MAP_POINTER 0x88BD -#define GL_STREAM_DRAW 0x88E0 -#define GL_STREAM_READ 0x88E1 -#define GL_STREAM_COPY 0x88E2 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STATIC_READ 0x88E5 -#define GL_STATIC_COPY 0x88E6 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_READ 0x88E9 -#define GL_DYNAMIC_COPY 0x88EA -#define GL_SAMPLES_PASSED 0x8914 -#define GL_SRC1_ALPHA 0x8589 -#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 -#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 -#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 -#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 -#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A -#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B -#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C -#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D -#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E -#define GL_FOG_COORD_SRC 0x8450 -#define GL_FOG_COORD 0x8451 -#define GL_CURRENT_FOG_COORD 0x8453 -#define GL_FOG_COORD_ARRAY_TYPE 0x8454 -#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 -#define GL_FOG_COORD_ARRAY_POINTER 0x8456 -#define GL_FOG_COORD_ARRAY 0x8457 -#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D -#define GL_SRC0_RGB 0x8580 -#define GL_SRC1_RGB 0x8581 -#define GL_SRC2_RGB 0x8582 -#define GL_SRC0_ALPHA 0x8588 -#define GL_SRC2_ALPHA 0x858A -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_MAX_DRAW_BUFFERS 0x8824 -#define GL_DRAW_BUFFER0 0x8825 -#define GL_DRAW_BUFFER1 0x8826 -#define GL_DRAW_BUFFER2 0x8827 -#define GL_DRAW_BUFFER3 0x8828 -#define GL_DRAW_BUFFER4 0x8829 -#define GL_DRAW_BUFFER5 0x882A -#define GL_DRAW_BUFFER6 0x882B -#define GL_DRAW_BUFFER7 0x882C -#define GL_DRAW_BUFFER8 0x882D -#define GL_DRAW_BUFFER9 0x882E -#define GL_DRAW_BUFFER10 0x882F -#define GL_DRAW_BUFFER11 0x8830 -#define GL_DRAW_BUFFER12 0x8831 -#define GL_DRAW_BUFFER13 0x8832 -#define GL_DRAW_BUFFER14 0x8833 -#define GL_DRAW_BUFFER15 0x8834 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_MAX_VERTEX_ATTRIBS 0x8869 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define GL_MAX_VARYING_FLOATS 0x8B4B -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_SHADER_TYPE 0x8B4F -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_BOOL 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT4 0x8B5C -#define GL_SAMPLER_1D 0x8B5D -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_3D 0x8B5F -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_1D_SHADOW 0x8B61 -#define GL_SAMPLER_2D_SHADOW 0x8B62 -#define GL_DELETE_STATUS 0x8B80 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_LINK_STATUS 0x8B82 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 -#define GL_POINT_SPRITE 0x8861 -#define GL_COORD_REPLACE 0x8862 -#define GL_MAX_TEXTURE_COORDS 0x8871 -#define GL_PIXEL_PACK_BUFFER 0x88EB -#define GL_PIXEL_UNPACK_BUFFER 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF -#define GL_FLOAT_MAT2x3 0x8B65 -#define GL_FLOAT_MAT2x4 0x8B66 -#define GL_FLOAT_MAT3x2 0x8B67 -#define GL_FLOAT_MAT3x4 0x8B68 -#define GL_FLOAT_MAT4x2 0x8B69 -#define GL_FLOAT_MAT4x3 0x8B6A -#define GL_SRGB 0x8C40 -#define GL_SRGB8 0x8C41 -#define GL_SRGB_ALPHA 0x8C42 -#define GL_SRGB8_ALPHA8 0x8C43 -#define GL_COMPRESSED_SRGB 0x8C48 -#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 -#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F -#define GL_SLUMINANCE_ALPHA 0x8C44 -#define GL_SLUMINANCE8_ALPHA8 0x8C45 -#define GL_SLUMINANCE 0x8C46 -#define GL_SLUMINANCE8 0x8C47 -#define GL_COMPRESSED_SLUMINANCE 0x8C4A -#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B -#define GL_COMPARE_REF_TO_TEXTURE 0x884E -#define GL_CLIP_DISTANCE0 0x3000 -#define GL_CLIP_DISTANCE1 0x3001 -#define GL_CLIP_DISTANCE2 0x3002 -#define GL_CLIP_DISTANCE3 0x3003 -#define GL_CLIP_DISTANCE4 0x3004 -#define GL_CLIP_DISTANCE5 0x3005 -#define GL_CLIP_DISTANCE6 0x3006 -#define GL_CLIP_DISTANCE7 0x3007 -#define GL_MAX_CLIP_DISTANCES 0x0D32 -#define GL_MAJOR_VERSION 0x821B -#define GL_MINOR_VERSION 0x821C -#define GL_NUM_EXTENSIONS 0x821D -#define GL_CONTEXT_FLAGS 0x821E -#define GL_COMPRESSED_RED 0x8225 -#define GL_COMPRESSED_RG 0x8226 -#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 -#define GL_RGBA32F 0x8814 -#define GL_RGB32F 0x8815 -#define GL_RGBA16F 0x881A -#define GL_RGB16F 0x881B -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD -#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF -#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 -#define GL_CLAMP_READ_COLOR 0x891C -#define GL_FIXED_ONLY 0x891D -#define GL_MAX_VARYING_COMPONENTS 0x8B4B -#define GL_TEXTURE_1D_ARRAY 0x8C18 -#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B -#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C -#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D -#define GL_R11F_G11F_B10F 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B -#define GL_RGB9_E5 0x8C3D -#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E -#define GL_TEXTURE_SHARED_SIZE 0x8C3F -#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 -#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 -#define GL_PRIMITIVES_GENERATED 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 -#define GL_RASTERIZER_DISCARD 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B -#define GL_INTERLEAVED_ATTRIBS 0x8C8C -#define GL_SEPARATE_ATTRIBS 0x8C8D -#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F -#define GL_RGBA32UI 0x8D70 -#define GL_RGB32UI 0x8D71 -#define GL_RGBA16UI 0x8D76 -#define GL_RGB16UI 0x8D77 -#define GL_RGBA8UI 0x8D7C -#define GL_RGB8UI 0x8D7D -#define GL_RGBA32I 0x8D82 -#define GL_RGB32I 0x8D83 -#define GL_RGBA16I 0x8D88 -#define GL_RGB16I 0x8D89 -#define GL_RGBA8I 0x8D8E -#define GL_RGB8I 0x8D8F -#define GL_RED_INTEGER 0x8D94 -#define GL_GREEN_INTEGER 0x8D95 -#define GL_BLUE_INTEGER 0x8D96 -#define GL_RGB_INTEGER 0x8D98 -#define GL_RGBA_INTEGER 0x8D99 -#define GL_BGR_INTEGER 0x8D9A -#define GL_BGRA_INTEGER 0x8D9B -#define GL_SAMPLER_1D_ARRAY 0x8DC0 -#define GL_SAMPLER_2D_ARRAY 0x8DC1 -#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 -#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 -#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 -#define GL_UNSIGNED_INT_VEC2 0x8DC6 -#define GL_UNSIGNED_INT_VEC3 0x8DC7 -#define GL_UNSIGNED_INT_VEC4 0x8DC8 -#define GL_INT_SAMPLER_1D 0x8DC9 -#define GL_INT_SAMPLER_2D 0x8DCA -#define GL_INT_SAMPLER_3D 0x8DCB -#define GL_INT_SAMPLER_CUBE 0x8DCC -#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE -#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF -#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 -#define GL_QUERY_WAIT 0x8E13 -#define GL_QUERY_NO_WAIT 0x8E14 -#define GL_QUERY_BY_REGION_WAIT 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 -#define GL_BUFFER_ACCESS_FLAGS 0x911F -#define GL_BUFFER_MAP_LENGTH 0x9120 -#define GL_BUFFER_MAP_OFFSET 0x9121 -#define GL_DEPTH_COMPONENT32F 0x8CAC -#define GL_DEPTH32F_STENCIL8 0x8CAD -#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD -#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 -#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 -#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 -#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 -#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 -#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 -#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 -#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 -#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 -#define GL_FRAMEBUFFER_DEFAULT 0x8218 -#define GL_FRAMEBUFFER_UNDEFINED 0x8219 -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 -#define GL_DEPTH_STENCIL 0x84F9 -#define GL_UNSIGNED_INT_24_8 0x84FA -#define GL_DEPTH24_STENCIL8 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE 0x88F1 -#define GL_TEXTURE_RED_TYPE 0x8C10 -#define GL_TEXTURE_GREEN_TYPE 0x8C11 -#define GL_TEXTURE_BLUE_TYPE 0x8C12 -#define GL_TEXTURE_ALPHA_TYPE 0x8C13 -#define GL_TEXTURE_DEPTH_TYPE 0x8C16 -#define GL_UNSIGNED_NORMALIZED 0x8C17 -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_RENDERBUFFER_BINDING 0x8CA7 -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA -#define GL_RENDERBUFFER_SAMPLES 0x8CAB -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#define GL_COLOR_ATTACHMENT1 0x8CE1 -#define GL_COLOR_ATTACHMENT2 0x8CE2 -#define GL_COLOR_ATTACHMENT3 0x8CE3 -#define GL_COLOR_ATTACHMENT4 0x8CE4 -#define GL_COLOR_ATTACHMENT5 0x8CE5 -#define GL_COLOR_ATTACHMENT6 0x8CE6 -#define GL_COLOR_ATTACHMENT7 0x8CE7 -#define GL_COLOR_ATTACHMENT8 0x8CE8 -#define GL_COLOR_ATTACHMENT9 0x8CE9 -#define GL_COLOR_ATTACHMENT10 0x8CEA -#define GL_COLOR_ATTACHMENT11 0x8CEB -#define GL_COLOR_ATTACHMENT12 0x8CEC -#define GL_COLOR_ATTACHMENT13 0x8CED -#define GL_COLOR_ATTACHMENT14 0x8CEE -#define GL_COLOR_ATTACHMENT15 0x8CEF -#define GL_COLOR_ATTACHMENT16 0x8CF0 -#define GL_COLOR_ATTACHMENT17 0x8CF1 -#define GL_COLOR_ATTACHMENT18 0x8CF2 -#define GL_COLOR_ATTACHMENT19 0x8CF3 -#define GL_COLOR_ATTACHMENT20 0x8CF4 -#define GL_COLOR_ATTACHMENT21 0x8CF5 -#define GL_COLOR_ATTACHMENT22 0x8CF6 -#define GL_COLOR_ATTACHMENT23 0x8CF7 -#define GL_COLOR_ATTACHMENT24 0x8CF8 -#define GL_COLOR_ATTACHMENT25 0x8CF9 -#define GL_COLOR_ATTACHMENT26 0x8CFA -#define GL_COLOR_ATTACHMENT27 0x8CFB -#define GL_COLOR_ATTACHMENT28 0x8CFC -#define GL_COLOR_ATTACHMENT29 0x8CFD -#define GL_COLOR_ATTACHMENT30 0x8CFE -#define GL_COLOR_ATTACHMENT31 0x8CFF -#define GL_DEPTH_ATTACHMENT 0x8D00 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_FRAMEBUFFER 0x8D40 -#define GL_RENDERBUFFER 0x8D41 -#define GL_RENDERBUFFER_WIDTH 0x8D42 -#define GL_RENDERBUFFER_HEIGHT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 -#define GL_STENCIL_INDEX1 0x8D46 -#define GL_STENCIL_INDEX4 0x8D47 -#define GL_STENCIL_INDEX8 0x8D48 -#define GL_STENCIL_INDEX16 0x8D49 -#define GL_RENDERBUFFER_RED_SIZE 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 -#define GL_MAX_SAMPLES 0x8D57 -#define GL_INDEX 0x8222 -#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 -#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 -#define GL_FRAMEBUFFER_SRGB 0x8DB9 -#define GL_HALF_FLOAT 0x140B -#define GL_MAP_READ_BIT 0x0001 -#define GL_MAP_WRITE_BIT 0x0002 -#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 -#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 -#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 -#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 -#define GL_COMPRESSED_RED_RGTC1 0x8DBB -#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define GL_COMPRESSED_RG_RGTC2 0x8DBD -#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#define GL_RG 0x8227 -#define GL_RG_INTEGER 0x8228 -#define GL_R8 0x8229 -#define GL_R16 0x822A -#define GL_RG8 0x822B -#define GL_RG16 0x822C -#define GL_R16F 0x822D -#define GL_R32F 0x822E -#define GL_RG16F 0x822F -#define GL_RG32F 0x8230 -#define GL_R8I 0x8231 -#define GL_R8UI 0x8232 -#define GL_R16I 0x8233 -#define GL_R16UI 0x8234 -#define GL_R32I 0x8235 -#define GL_R32UI 0x8236 -#define GL_RG8I 0x8237 -#define GL_RG8UI 0x8238 -#define GL_RG16I 0x8239 -#define GL_RG16UI 0x823A -#define GL_RG32I 0x823B -#define GL_RG32UI 0x823C -#define GL_VERTEX_ARRAY_BINDING 0x85B5 -#define GL_CLAMP_VERTEX_COLOR 0x891A -#define GL_CLAMP_FRAGMENT_COLOR 0x891B -#define GL_ALPHA_INTEGER 0x8D97 -#define GL_SAMPLER_2D_RECT 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 -#define GL_SAMPLER_BUFFER 0x8DC2 -#define GL_INT_SAMPLER_2D_RECT 0x8DCD -#define GL_INT_SAMPLER_BUFFER 0x8DD0 -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 -#define GL_TEXTURE_BUFFER 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D -#define GL_TEXTURE_RECTANGLE 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 -#define GL_R8_SNORM 0x8F94 -#define GL_RG8_SNORM 0x8F95 -#define GL_RGB8_SNORM 0x8F96 -#define GL_RGBA8_SNORM 0x8F97 -#define GL_R16_SNORM 0x8F98 -#define GL_RG16_SNORM 0x8F99 -#define GL_RGB16_SNORM 0x8F9A -#define GL_RGBA16_SNORM 0x8F9B -#define GL_SIGNED_NORMALIZED 0x8F9C -#define GL_PRIMITIVE_RESTART 0x8F9D -#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E -#define GL_COPY_READ_BUFFER 0x8F36 -#define GL_COPY_WRITE_BUFFER 0x8F37 -#define GL_UNIFORM_BUFFER 0x8A11 -#define GL_UNIFORM_BUFFER_BINDING 0x8A28 -#define GL_UNIFORM_BUFFER_START 0x8A29 -#define GL_UNIFORM_BUFFER_SIZE 0x8A2A -#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C -#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D -#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E -#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F -#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 -#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 -#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 -#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 -#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 -#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 -#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 -#define GL_UNIFORM_TYPE 0x8A37 -#define GL_UNIFORM_SIZE 0x8A38 -#define GL_UNIFORM_NAME_LENGTH 0x8A39 -#define GL_UNIFORM_BLOCK_INDEX 0x8A3A -#define GL_UNIFORM_OFFSET 0x8A3B -#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C -#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D -#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E -#define GL_UNIFORM_BLOCK_BINDING 0x8A3F -#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 -#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 -#define GL_INVALID_INDEX 0xFFFFFFFF -#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 -#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 -#define GL_LINES_ADJACENCY 0x000A -#define GL_LINE_STRIP_ADJACENCY 0x000B -#define GL_TRIANGLES_ADJACENCY 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D -#define GL_PROGRAM_POINT_SIZE 0x8642 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 -#define GL_GEOMETRY_SHADER 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT 0x8916 -#define GL_GEOMETRY_INPUT_TYPE 0x8917 -#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 -#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 -#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 -#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 -#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 -#define GL_CONTEXT_PROFILE_MASK 0x9126 -#define GL_DEPTH_CLAMP 0x864F -#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C -#define GL_FIRST_VERTEX_CONVENTION 0x8E4D -#define GL_LAST_VERTEX_CONVENTION 0x8E4E -#define GL_PROVOKING_VERTEX 0x8E4F -#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F -#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 -#define GL_OBJECT_TYPE 0x9112 -#define GL_SYNC_CONDITION 0x9113 -#define GL_SYNC_STATUS 0x9114 -#define GL_SYNC_FLAGS 0x9115 -#define GL_SYNC_FENCE 0x9116 -#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 -#define GL_UNSIGNALED 0x9118 -#define GL_SIGNALED 0x9119 -#define GL_ALREADY_SIGNALED 0x911A -#define GL_TIMEOUT_EXPIRED 0x911B -#define GL_CONDITION_SATISFIED 0x911C -#define GL_WAIT_FAILED 0x911D -#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF -#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 -#define GL_SAMPLE_POSITION 0x8E50 -#define GL_SAMPLE_MASK 0x8E51 -#define GL_SAMPLE_MASK_VALUE 0x8E52 -#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 -#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 -#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 -#define GL_TEXTURE_SAMPLES 0x9106 -#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 -#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 -#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A -#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B -#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D -#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E -#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F -#define GL_MAX_INTEGER_SAMPLES 0x9110 -#ifndef GL_VERSION_1_0 -#define GL_VERSION_1_0 1 -GLAPI int GLAD_GL_VERSION_1_0; -typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); -GLAPI PFNGLCULLFACEPROC glad_glCullFace; -#define glCullFace glad_glCullFace -typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); -GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; -#define glFrontFace glad_glFrontFace -typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); -GLAPI PFNGLHINTPROC glad_glHint; -#define glHint glad_glHint -typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); -GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; -#define glLineWidth glad_glLineWidth -typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size); -GLAPI PFNGLPOINTSIZEPROC glad_glPointSize; -#define glPointSize glad_glPointSize -typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); -GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode; -#define glPolygonMode glad_glPolygonMode -typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLSCISSORPROC glad_glScissor; -#define glScissor glad_glScissor -typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); -GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; -#define glTexParameterf glad_glTexParameterf -typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params); -GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; -#define glTexParameterfv glad_glTexParameterfv -typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); -GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; -#define glTexParameteri glad_glTexParameteri -typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params); -GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; -#define glTexParameteriv glad_glTexParameteriv -typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D; -#define glTexImage1D glad_glTexImage1D -typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; -#define glTexImage2D glad_glTexImage2D -typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf); -GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer; -#define glDrawBuffer glad_glDrawBuffer -typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); -GLAPI PFNGLCLEARPROC glad_glClear; -#define glClear glad_glClear -typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; -#define glClearColor glad_glClearColor -typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); -GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; -#define glClearStencil glad_glClearStencil -typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth); -GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth; -#define glClearDepth glad_glClearDepth -typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); -GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; -#define glStencilMask glad_glStencilMask -typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -GLAPI PFNGLCOLORMASKPROC glad_glColorMask; -#define glColorMask glad_glColorMask -typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); -GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; -#define glDepthMask glad_glDepthMask -typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); -GLAPI PFNGLDISABLEPROC glad_glDisable; -#define glDisable glad_glDisable -typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); -GLAPI PFNGLENABLEPROC glad_glEnable; -#define glEnable glad_glEnable -typedef void (APIENTRYP PFNGLFINISHPROC)(); -GLAPI PFNGLFINISHPROC glad_glFinish; -#define glFinish glad_glFinish -typedef void (APIENTRYP PFNGLFLUSHPROC)(); -GLAPI PFNGLFLUSHPROC glad_glFlush; -#define glFlush glad_glFlush -typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); -GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; -#define glBlendFunc glad_glBlendFunc -typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode); -GLAPI PFNGLLOGICOPPROC glad_glLogicOp; -#define glLogicOp glad_glLogicOp -typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); -GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; -#define glStencilFunc glad_glStencilFunc -typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); -GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; -#define glStencilOp glad_glStencilOp -typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); -GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; -#define glDepthFunc glad_glDepthFunc -typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); -GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref; -#define glPixelStoref glad_glPixelStoref -typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); -GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; -#define glPixelStorei glad_glPixelStorei -typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src); -GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer; -#define glReadBuffer glad_glReadBuffer -typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); -GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; -#define glReadPixels glad_glReadPixels -typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data); -GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; -#define glGetBooleanv glad_glGetBooleanv -typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble *data); -GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev; -#define glGetDoublev glad_glGetDoublev -typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(); -GLAPI PFNGLGETERRORPROC glad_glGetError; -#define glGetError glad_glGetError -typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data); -GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; -#define glGetFloatv glad_glGetFloatv -typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data); -GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; -#define glGetIntegerv glad_glGetIntegerv -typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); -GLAPI PFNGLGETSTRINGPROC glad_glGetString; -#define glGetString glad_glGetString -typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage; -#define glGetTexImage glad_glGetTexImage -typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params); -GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; -#define glGetTexParameterfv glad_glGetTexParameterfv -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; -#define glGetTexParameteriv glad_glGetTexParameteriv -typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; -#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv -typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; -#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv -typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); -GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; -#define glIsEnabled glad_glIsEnabled -typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble near, GLdouble far); -GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange; -#define glDepthRange glad_glDepthRange -typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLVIEWPORTPROC glad_glViewport; -#define glViewport glad_glViewport -typedef void (APIENTRYP PFNGLNEWLISTPROC)(GLuint list, GLenum mode); -GLAPI PFNGLNEWLISTPROC glad_glNewList; -#define glNewList glad_glNewList -typedef void (APIENTRYP PFNGLENDLISTPROC)(); -GLAPI PFNGLENDLISTPROC glad_glEndList; -#define glEndList glad_glEndList -typedef void (APIENTRYP PFNGLCALLLISTPROC)(GLuint list); -GLAPI PFNGLCALLLISTPROC glad_glCallList; -#define glCallList glad_glCallList -typedef void (APIENTRYP PFNGLCALLLISTSPROC)(GLsizei n, GLenum type, const void *lists); -GLAPI PFNGLCALLLISTSPROC glad_glCallLists; -#define glCallLists glad_glCallLists -typedef void (APIENTRYP PFNGLDELETELISTSPROC)(GLuint list, GLsizei range); -GLAPI PFNGLDELETELISTSPROC glad_glDeleteLists; -#define glDeleteLists glad_glDeleteLists -typedef GLuint (APIENTRYP PFNGLGENLISTSPROC)(GLsizei range); -GLAPI PFNGLGENLISTSPROC glad_glGenLists; -#define glGenLists glad_glGenLists -typedef void (APIENTRYP PFNGLLISTBASEPROC)(GLuint base); -GLAPI PFNGLLISTBASEPROC glad_glListBase; -#define glListBase glad_glListBase -typedef void (APIENTRYP PFNGLBEGINPROC)(GLenum mode); -GLAPI PFNGLBEGINPROC glad_glBegin; -#define glBegin glad_glBegin -typedef void (APIENTRYP PFNGLBITMAPPROC)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); -GLAPI PFNGLBITMAPPROC glad_glBitmap; -#define glBitmap glad_glBitmap -typedef void (APIENTRYP PFNGLCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); -GLAPI PFNGLCOLOR3BPROC glad_glColor3b; -#define glColor3b glad_glColor3b -typedef void (APIENTRYP PFNGLCOLOR3BVPROC)(const GLbyte *v); -GLAPI PFNGLCOLOR3BVPROC glad_glColor3bv; -#define glColor3bv glad_glColor3bv -typedef void (APIENTRYP PFNGLCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); -GLAPI PFNGLCOLOR3DPROC glad_glColor3d; -#define glColor3d glad_glColor3d -typedef void (APIENTRYP PFNGLCOLOR3DVPROC)(const GLdouble *v); -GLAPI PFNGLCOLOR3DVPROC glad_glColor3dv; -#define glColor3dv glad_glColor3dv -typedef void (APIENTRYP PFNGLCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); -GLAPI PFNGLCOLOR3FPROC glad_glColor3f; -#define glColor3f glad_glColor3f -typedef void (APIENTRYP PFNGLCOLOR3FVPROC)(const GLfloat *v); -GLAPI PFNGLCOLOR3FVPROC glad_glColor3fv; -#define glColor3fv glad_glColor3fv -typedef void (APIENTRYP PFNGLCOLOR3IPROC)(GLint red, GLint green, GLint blue); -GLAPI PFNGLCOLOR3IPROC glad_glColor3i; -#define glColor3i glad_glColor3i -typedef void (APIENTRYP PFNGLCOLOR3IVPROC)(const GLint *v); -GLAPI PFNGLCOLOR3IVPROC glad_glColor3iv; -#define glColor3iv glad_glColor3iv -typedef void (APIENTRYP PFNGLCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); -GLAPI PFNGLCOLOR3SPROC glad_glColor3s; -#define glColor3s glad_glColor3s -typedef void (APIENTRYP PFNGLCOLOR3SVPROC)(const GLshort *v); -GLAPI PFNGLCOLOR3SVPROC glad_glColor3sv; -#define glColor3sv glad_glColor3sv -typedef void (APIENTRYP PFNGLCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); -GLAPI PFNGLCOLOR3UBPROC glad_glColor3ub; -#define glColor3ub glad_glColor3ub -typedef void (APIENTRYP PFNGLCOLOR3UBVPROC)(const GLubyte *v); -GLAPI PFNGLCOLOR3UBVPROC glad_glColor3ubv; -#define glColor3ubv glad_glColor3ubv -typedef void (APIENTRYP PFNGLCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); -GLAPI PFNGLCOLOR3UIPROC glad_glColor3ui; -#define glColor3ui glad_glColor3ui -typedef void (APIENTRYP PFNGLCOLOR3UIVPROC)(const GLuint *v); -GLAPI PFNGLCOLOR3UIVPROC glad_glColor3uiv; -#define glColor3uiv glad_glColor3uiv -typedef void (APIENTRYP PFNGLCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); -GLAPI PFNGLCOLOR3USPROC glad_glColor3us; -#define glColor3us glad_glColor3us -typedef void (APIENTRYP PFNGLCOLOR3USVPROC)(const GLushort *v); -GLAPI PFNGLCOLOR3USVPROC glad_glColor3usv; -#define glColor3usv glad_glColor3usv -typedef void (APIENTRYP PFNGLCOLOR4BPROC)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); -GLAPI PFNGLCOLOR4BPROC glad_glColor4b; -#define glColor4b glad_glColor4b -typedef void (APIENTRYP PFNGLCOLOR4BVPROC)(const GLbyte *v); -GLAPI PFNGLCOLOR4BVPROC glad_glColor4bv; -#define glColor4bv glad_glColor4bv -typedef void (APIENTRYP PFNGLCOLOR4DPROC)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); -GLAPI PFNGLCOLOR4DPROC glad_glColor4d; -#define glColor4d glad_glColor4d -typedef void (APIENTRYP PFNGLCOLOR4DVPROC)(const GLdouble *v); -GLAPI PFNGLCOLOR4DVPROC glad_glColor4dv; -#define glColor4dv glad_glColor4dv -typedef void (APIENTRYP PFNGLCOLOR4FPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI PFNGLCOLOR4FPROC glad_glColor4f; -#define glColor4f glad_glColor4f -typedef void (APIENTRYP PFNGLCOLOR4FVPROC)(const GLfloat *v); -GLAPI PFNGLCOLOR4FVPROC glad_glColor4fv; -#define glColor4fv glad_glColor4fv -typedef void (APIENTRYP PFNGLCOLOR4IPROC)(GLint red, GLint green, GLint blue, GLint alpha); -GLAPI PFNGLCOLOR4IPROC glad_glColor4i; -#define glColor4i glad_glColor4i -typedef void (APIENTRYP PFNGLCOLOR4IVPROC)(const GLint *v); -GLAPI PFNGLCOLOR4IVPROC glad_glColor4iv; -#define glColor4iv glad_glColor4iv -typedef void (APIENTRYP PFNGLCOLOR4SPROC)(GLshort red, GLshort green, GLshort blue, GLshort alpha); -GLAPI PFNGLCOLOR4SPROC glad_glColor4s; -#define glColor4s glad_glColor4s -typedef void (APIENTRYP PFNGLCOLOR4SVPROC)(const GLshort *v); -GLAPI PFNGLCOLOR4SVPROC glad_glColor4sv; -#define glColor4sv glad_glColor4sv -typedef void (APIENTRYP PFNGLCOLOR4UBPROC)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); -GLAPI PFNGLCOLOR4UBPROC glad_glColor4ub; -#define glColor4ub glad_glColor4ub -typedef void (APIENTRYP PFNGLCOLOR4UBVPROC)(const GLubyte *v); -GLAPI PFNGLCOLOR4UBVPROC glad_glColor4ubv; -#define glColor4ubv glad_glColor4ubv -typedef void (APIENTRYP PFNGLCOLOR4UIPROC)(GLuint red, GLuint green, GLuint blue, GLuint alpha); -GLAPI PFNGLCOLOR4UIPROC glad_glColor4ui; -#define glColor4ui glad_glColor4ui -typedef void (APIENTRYP PFNGLCOLOR4UIVPROC)(const GLuint *v); -GLAPI PFNGLCOLOR4UIVPROC glad_glColor4uiv; -#define glColor4uiv glad_glColor4uiv -typedef void (APIENTRYP PFNGLCOLOR4USPROC)(GLushort red, GLushort green, GLushort blue, GLushort alpha); -GLAPI PFNGLCOLOR4USPROC glad_glColor4us; -#define glColor4us glad_glColor4us -typedef void (APIENTRYP PFNGLCOLOR4USVPROC)(const GLushort *v); -GLAPI PFNGLCOLOR4USVPROC glad_glColor4usv; -#define glColor4usv glad_glColor4usv -typedef void (APIENTRYP PFNGLEDGEFLAGPROC)(GLboolean flag); -GLAPI PFNGLEDGEFLAGPROC glad_glEdgeFlag; -#define glEdgeFlag glad_glEdgeFlag -typedef void (APIENTRYP PFNGLEDGEFLAGVPROC)(const GLboolean *flag); -GLAPI PFNGLEDGEFLAGVPROC glad_glEdgeFlagv; -#define glEdgeFlagv glad_glEdgeFlagv -typedef void (APIENTRYP PFNGLENDPROC)(); -GLAPI PFNGLENDPROC glad_glEnd; -#define glEnd glad_glEnd -typedef void (APIENTRYP PFNGLINDEXDPROC)(GLdouble c); -GLAPI PFNGLINDEXDPROC glad_glIndexd; -#define glIndexd glad_glIndexd -typedef void (APIENTRYP PFNGLINDEXDVPROC)(const GLdouble *c); -GLAPI PFNGLINDEXDVPROC glad_glIndexdv; -#define glIndexdv glad_glIndexdv -typedef void (APIENTRYP PFNGLINDEXFPROC)(GLfloat c); -GLAPI PFNGLINDEXFPROC glad_glIndexf; -#define glIndexf glad_glIndexf -typedef void (APIENTRYP PFNGLINDEXFVPROC)(const GLfloat *c); -GLAPI PFNGLINDEXFVPROC glad_glIndexfv; -#define glIndexfv glad_glIndexfv -typedef void (APIENTRYP PFNGLINDEXIPROC)(GLint c); -GLAPI PFNGLINDEXIPROC glad_glIndexi; -#define glIndexi glad_glIndexi -typedef void (APIENTRYP PFNGLINDEXIVPROC)(const GLint *c); -GLAPI PFNGLINDEXIVPROC glad_glIndexiv; -#define glIndexiv glad_glIndexiv -typedef void (APIENTRYP PFNGLINDEXSPROC)(GLshort c); -GLAPI PFNGLINDEXSPROC glad_glIndexs; -#define glIndexs glad_glIndexs -typedef void (APIENTRYP PFNGLINDEXSVPROC)(const GLshort *c); -GLAPI PFNGLINDEXSVPROC glad_glIndexsv; -#define glIndexsv glad_glIndexsv -typedef void (APIENTRYP PFNGLNORMAL3BPROC)(GLbyte nx, GLbyte ny, GLbyte nz); -GLAPI PFNGLNORMAL3BPROC glad_glNormal3b; -#define glNormal3b glad_glNormal3b -typedef void (APIENTRYP PFNGLNORMAL3BVPROC)(const GLbyte *v); -GLAPI PFNGLNORMAL3BVPROC glad_glNormal3bv; -#define glNormal3bv glad_glNormal3bv -typedef void (APIENTRYP PFNGLNORMAL3DPROC)(GLdouble nx, GLdouble ny, GLdouble nz); -GLAPI PFNGLNORMAL3DPROC glad_glNormal3d; -#define glNormal3d glad_glNormal3d -typedef void (APIENTRYP PFNGLNORMAL3DVPROC)(const GLdouble *v); -GLAPI PFNGLNORMAL3DVPROC glad_glNormal3dv; -#define glNormal3dv glad_glNormal3dv -typedef void (APIENTRYP PFNGLNORMAL3FPROC)(GLfloat nx, GLfloat ny, GLfloat nz); -GLAPI PFNGLNORMAL3FPROC glad_glNormal3f; -#define glNormal3f glad_glNormal3f -typedef void (APIENTRYP PFNGLNORMAL3FVPROC)(const GLfloat *v); -GLAPI PFNGLNORMAL3FVPROC glad_glNormal3fv; -#define glNormal3fv glad_glNormal3fv -typedef void (APIENTRYP PFNGLNORMAL3IPROC)(GLint nx, GLint ny, GLint nz); -GLAPI PFNGLNORMAL3IPROC glad_glNormal3i; -#define glNormal3i glad_glNormal3i -typedef void (APIENTRYP PFNGLNORMAL3IVPROC)(const GLint *v); -GLAPI PFNGLNORMAL3IVPROC glad_glNormal3iv; -#define glNormal3iv glad_glNormal3iv -typedef void (APIENTRYP PFNGLNORMAL3SPROC)(GLshort nx, GLshort ny, GLshort nz); -GLAPI PFNGLNORMAL3SPROC glad_glNormal3s; -#define glNormal3s glad_glNormal3s -typedef void (APIENTRYP PFNGLNORMAL3SVPROC)(const GLshort *v); -GLAPI PFNGLNORMAL3SVPROC glad_glNormal3sv; -#define glNormal3sv glad_glNormal3sv -typedef void (APIENTRYP PFNGLRASTERPOS2DPROC)(GLdouble x, GLdouble y); -GLAPI PFNGLRASTERPOS2DPROC glad_glRasterPos2d; -#define glRasterPos2d glad_glRasterPos2d -typedef void (APIENTRYP PFNGLRASTERPOS2DVPROC)(const GLdouble *v); -GLAPI PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv; -#define glRasterPos2dv glad_glRasterPos2dv -typedef void (APIENTRYP PFNGLRASTERPOS2FPROC)(GLfloat x, GLfloat y); -GLAPI PFNGLRASTERPOS2FPROC glad_glRasterPos2f; -#define glRasterPos2f glad_glRasterPos2f -typedef void (APIENTRYP PFNGLRASTERPOS2FVPROC)(const GLfloat *v); -GLAPI PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv; -#define glRasterPos2fv glad_glRasterPos2fv -typedef void (APIENTRYP PFNGLRASTERPOS2IPROC)(GLint x, GLint y); -GLAPI PFNGLRASTERPOS2IPROC glad_glRasterPos2i; -#define glRasterPos2i glad_glRasterPos2i -typedef void (APIENTRYP PFNGLRASTERPOS2IVPROC)(const GLint *v); -GLAPI PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv; -#define glRasterPos2iv glad_glRasterPos2iv -typedef void (APIENTRYP PFNGLRASTERPOS2SPROC)(GLshort x, GLshort y); -GLAPI PFNGLRASTERPOS2SPROC glad_glRasterPos2s; -#define glRasterPos2s glad_glRasterPos2s -typedef void (APIENTRYP PFNGLRASTERPOS2SVPROC)(const GLshort *v); -GLAPI PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv; -#define glRasterPos2sv glad_glRasterPos2sv -typedef void (APIENTRYP PFNGLRASTERPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); -GLAPI PFNGLRASTERPOS3DPROC glad_glRasterPos3d; -#define glRasterPos3d glad_glRasterPos3d -typedef void (APIENTRYP PFNGLRASTERPOS3DVPROC)(const GLdouble *v); -GLAPI PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv; -#define glRasterPos3dv glad_glRasterPos3dv -typedef void (APIENTRYP PFNGLRASTERPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); -GLAPI PFNGLRASTERPOS3FPROC glad_glRasterPos3f; -#define glRasterPos3f glad_glRasterPos3f -typedef void (APIENTRYP PFNGLRASTERPOS3FVPROC)(const GLfloat *v); -GLAPI PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv; -#define glRasterPos3fv glad_glRasterPos3fv -typedef void (APIENTRYP PFNGLRASTERPOS3IPROC)(GLint x, GLint y, GLint z); -GLAPI PFNGLRASTERPOS3IPROC glad_glRasterPos3i; -#define glRasterPos3i glad_glRasterPos3i -typedef void (APIENTRYP PFNGLRASTERPOS3IVPROC)(const GLint *v); -GLAPI PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv; -#define glRasterPos3iv glad_glRasterPos3iv -typedef void (APIENTRYP PFNGLRASTERPOS3SPROC)(GLshort x, GLshort y, GLshort z); -GLAPI PFNGLRASTERPOS3SPROC glad_glRasterPos3s; -#define glRasterPos3s glad_glRasterPos3s -typedef void (APIENTRYP PFNGLRASTERPOS3SVPROC)(const GLshort *v); -GLAPI PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv; -#define glRasterPos3sv glad_glRasterPos3sv -typedef void (APIENTRYP PFNGLRASTERPOS4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI PFNGLRASTERPOS4DPROC glad_glRasterPos4d; -#define glRasterPos4d glad_glRasterPos4d -typedef void (APIENTRYP PFNGLRASTERPOS4DVPROC)(const GLdouble *v); -GLAPI PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv; -#define glRasterPos4dv glad_glRasterPos4dv -typedef void (APIENTRYP PFNGLRASTERPOS4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI PFNGLRASTERPOS4FPROC glad_glRasterPos4f; -#define glRasterPos4f glad_glRasterPos4f -typedef void (APIENTRYP PFNGLRASTERPOS4FVPROC)(const GLfloat *v); -GLAPI PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv; -#define glRasterPos4fv glad_glRasterPos4fv -typedef void (APIENTRYP PFNGLRASTERPOS4IPROC)(GLint x, GLint y, GLint z, GLint w); -GLAPI PFNGLRASTERPOS4IPROC glad_glRasterPos4i; -#define glRasterPos4i glad_glRasterPos4i -typedef void (APIENTRYP PFNGLRASTERPOS4IVPROC)(const GLint *v); -GLAPI PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv; -#define glRasterPos4iv glad_glRasterPos4iv -typedef void (APIENTRYP PFNGLRASTERPOS4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI PFNGLRASTERPOS4SPROC glad_glRasterPos4s; -#define glRasterPos4s glad_glRasterPos4s -typedef void (APIENTRYP PFNGLRASTERPOS4SVPROC)(const GLshort *v); -GLAPI PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv; -#define glRasterPos4sv glad_glRasterPos4sv -typedef void (APIENTRYP PFNGLRECTDPROC)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); -GLAPI PFNGLRECTDPROC glad_glRectd; -#define glRectd glad_glRectd -typedef void (APIENTRYP PFNGLRECTDVPROC)(const GLdouble *v1, const GLdouble *v2); -GLAPI PFNGLRECTDVPROC glad_glRectdv; -#define glRectdv glad_glRectdv -typedef void (APIENTRYP PFNGLRECTFPROC)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); -GLAPI PFNGLRECTFPROC glad_glRectf; -#define glRectf glad_glRectf -typedef void (APIENTRYP PFNGLRECTFVPROC)(const GLfloat *v1, const GLfloat *v2); -GLAPI PFNGLRECTFVPROC glad_glRectfv; -#define glRectfv glad_glRectfv -typedef void (APIENTRYP PFNGLRECTIPROC)(GLint x1, GLint y1, GLint x2, GLint y2); -GLAPI PFNGLRECTIPROC glad_glRecti; -#define glRecti glad_glRecti -typedef void (APIENTRYP PFNGLRECTIVPROC)(const GLint *v1, const GLint *v2); -GLAPI PFNGLRECTIVPROC glad_glRectiv; -#define glRectiv glad_glRectiv -typedef void (APIENTRYP PFNGLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); -GLAPI PFNGLRECTSPROC glad_glRects; -#define glRects glad_glRects -typedef void (APIENTRYP PFNGLRECTSVPROC)(const GLshort *v1, const GLshort *v2); -GLAPI PFNGLRECTSVPROC glad_glRectsv; -#define glRectsv glad_glRectsv -typedef void (APIENTRYP PFNGLTEXCOORD1DPROC)(GLdouble s); -GLAPI PFNGLTEXCOORD1DPROC glad_glTexCoord1d; -#define glTexCoord1d glad_glTexCoord1d -typedef void (APIENTRYP PFNGLTEXCOORD1DVPROC)(const GLdouble *v); -GLAPI PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv; -#define glTexCoord1dv glad_glTexCoord1dv -typedef void (APIENTRYP PFNGLTEXCOORD1FPROC)(GLfloat s); -GLAPI PFNGLTEXCOORD1FPROC glad_glTexCoord1f; -#define glTexCoord1f glad_glTexCoord1f -typedef void (APIENTRYP PFNGLTEXCOORD1FVPROC)(const GLfloat *v); -GLAPI PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv; -#define glTexCoord1fv glad_glTexCoord1fv -typedef void (APIENTRYP PFNGLTEXCOORD1IPROC)(GLint s); -GLAPI PFNGLTEXCOORD1IPROC glad_glTexCoord1i; -#define glTexCoord1i glad_glTexCoord1i -typedef void (APIENTRYP PFNGLTEXCOORD1IVPROC)(const GLint *v); -GLAPI PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv; -#define glTexCoord1iv glad_glTexCoord1iv -typedef void (APIENTRYP PFNGLTEXCOORD1SPROC)(GLshort s); -GLAPI PFNGLTEXCOORD1SPROC glad_glTexCoord1s; -#define glTexCoord1s glad_glTexCoord1s -typedef void (APIENTRYP PFNGLTEXCOORD1SVPROC)(const GLshort *v); -GLAPI PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv; -#define glTexCoord1sv glad_glTexCoord1sv -typedef void (APIENTRYP PFNGLTEXCOORD2DPROC)(GLdouble s, GLdouble t); -GLAPI PFNGLTEXCOORD2DPROC glad_glTexCoord2d; -#define glTexCoord2d glad_glTexCoord2d -typedef void (APIENTRYP PFNGLTEXCOORD2DVPROC)(const GLdouble *v); -GLAPI PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv; -#define glTexCoord2dv glad_glTexCoord2dv -typedef void (APIENTRYP PFNGLTEXCOORD2FPROC)(GLfloat s, GLfloat t); -GLAPI PFNGLTEXCOORD2FPROC glad_glTexCoord2f; -#define glTexCoord2f glad_glTexCoord2f -typedef void (APIENTRYP PFNGLTEXCOORD2FVPROC)(const GLfloat *v); -GLAPI PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv; -#define glTexCoord2fv glad_glTexCoord2fv -typedef void (APIENTRYP PFNGLTEXCOORD2IPROC)(GLint s, GLint t); -GLAPI PFNGLTEXCOORD2IPROC glad_glTexCoord2i; -#define glTexCoord2i glad_glTexCoord2i -typedef void (APIENTRYP PFNGLTEXCOORD2IVPROC)(const GLint *v); -GLAPI PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv; -#define glTexCoord2iv glad_glTexCoord2iv -typedef void (APIENTRYP PFNGLTEXCOORD2SPROC)(GLshort s, GLshort t); -GLAPI PFNGLTEXCOORD2SPROC glad_glTexCoord2s; -#define glTexCoord2s glad_glTexCoord2s -typedef void (APIENTRYP PFNGLTEXCOORD2SVPROC)(const GLshort *v); -GLAPI PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv; -#define glTexCoord2sv glad_glTexCoord2sv -typedef void (APIENTRYP PFNGLTEXCOORD3DPROC)(GLdouble s, GLdouble t, GLdouble r); -GLAPI PFNGLTEXCOORD3DPROC glad_glTexCoord3d; -#define glTexCoord3d glad_glTexCoord3d -typedef void (APIENTRYP PFNGLTEXCOORD3DVPROC)(const GLdouble *v); -GLAPI PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv; -#define glTexCoord3dv glad_glTexCoord3dv -typedef void (APIENTRYP PFNGLTEXCOORD3FPROC)(GLfloat s, GLfloat t, GLfloat r); -GLAPI PFNGLTEXCOORD3FPROC glad_glTexCoord3f; -#define glTexCoord3f glad_glTexCoord3f -typedef void (APIENTRYP PFNGLTEXCOORD3FVPROC)(const GLfloat *v); -GLAPI PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv; -#define glTexCoord3fv glad_glTexCoord3fv -typedef void (APIENTRYP PFNGLTEXCOORD3IPROC)(GLint s, GLint t, GLint r); -GLAPI PFNGLTEXCOORD3IPROC glad_glTexCoord3i; -#define glTexCoord3i glad_glTexCoord3i -typedef void (APIENTRYP PFNGLTEXCOORD3IVPROC)(const GLint *v); -GLAPI PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv; -#define glTexCoord3iv glad_glTexCoord3iv -typedef void (APIENTRYP PFNGLTEXCOORD3SPROC)(GLshort s, GLshort t, GLshort r); -GLAPI PFNGLTEXCOORD3SPROC glad_glTexCoord3s; -#define glTexCoord3s glad_glTexCoord3s -typedef void (APIENTRYP PFNGLTEXCOORD3SVPROC)(const GLshort *v); -GLAPI PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv; -#define glTexCoord3sv glad_glTexCoord3sv -typedef void (APIENTRYP PFNGLTEXCOORD4DPROC)(GLdouble s, GLdouble t, GLdouble r, GLdouble q); -GLAPI PFNGLTEXCOORD4DPROC glad_glTexCoord4d; -#define glTexCoord4d glad_glTexCoord4d -typedef void (APIENTRYP PFNGLTEXCOORD4DVPROC)(const GLdouble *v); -GLAPI PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv; -#define glTexCoord4dv glad_glTexCoord4dv -typedef void (APIENTRYP PFNGLTEXCOORD4FPROC)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); -GLAPI PFNGLTEXCOORD4FPROC glad_glTexCoord4f; -#define glTexCoord4f glad_glTexCoord4f -typedef void (APIENTRYP PFNGLTEXCOORD4FVPROC)(const GLfloat *v); -GLAPI PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv; -#define glTexCoord4fv glad_glTexCoord4fv -typedef void (APIENTRYP PFNGLTEXCOORD4IPROC)(GLint s, GLint t, GLint r, GLint q); -GLAPI PFNGLTEXCOORD4IPROC glad_glTexCoord4i; -#define glTexCoord4i glad_glTexCoord4i -typedef void (APIENTRYP PFNGLTEXCOORD4IVPROC)(const GLint *v); -GLAPI PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv; -#define glTexCoord4iv glad_glTexCoord4iv -typedef void (APIENTRYP PFNGLTEXCOORD4SPROC)(GLshort s, GLshort t, GLshort r, GLshort q); -GLAPI PFNGLTEXCOORD4SPROC glad_glTexCoord4s; -#define glTexCoord4s glad_glTexCoord4s -typedef void (APIENTRYP PFNGLTEXCOORD4SVPROC)(const GLshort *v); -GLAPI PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv; -#define glTexCoord4sv glad_glTexCoord4sv -typedef void (APIENTRYP PFNGLVERTEX2DPROC)(GLdouble x, GLdouble y); -GLAPI PFNGLVERTEX2DPROC glad_glVertex2d; -#define glVertex2d glad_glVertex2d -typedef void (APIENTRYP PFNGLVERTEX2DVPROC)(const GLdouble *v); -GLAPI PFNGLVERTEX2DVPROC glad_glVertex2dv; -#define glVertex2dv glad_glVertex2dv -typedef void (APIENTRYP PFNGLVERTEX2FPROC)(GLfloat x, GLfloat y); -GLAPI PFNGLVERTEX2FPROC glad_glVertex2f; -#define glVertex2f glad_glVertex2f -typedef void (APIENTRYP PFNGLVERTEX2FVPROC)(const GLfloat *v); -GLAPI PFNGLVERTEX2FVPROC glad_glVertex2fv; -#define glVertex2fv glad_glVertex2fv -typedef void (APIENTRYP PFNGLVERTEX2IPROC)(GLint x, GLint y); -GLAPI PFNGLVERTEX2IPROC glad_glVertex2i; -#define glVertex2i glad_glVertex2i -typedef void (APIENTRYP PFNGLVERTEX2IVPROC)(const GLint *v); -GLAPI PFNGLVERTEX2IVPROC glad_glVertex2iv; -#define glVertex2iv glad_glVertex2iv -typedef void (APIENTRYP PFNGLVERTEX2SPROC)(GLshort x, GLshort y); -GLAPI PFNGLVERTEX2SPROC glad_glVertex2s; -#define glVertex2s glad_glVertex2s -typedef void (APIENTRYP PFNGLVERTEX2SVPROC)(const GLshort *v); -GLAPI PFNGLVERTEX2SVPROC glad_glVertex2sv; -#define glVertex2sv glad_glVertex2sv -typedef void (APIENTRYP PFNGLVERTEX3DPROC)(GLdouble x, GLdouble y, GLdouble z); -GLAPI PFNGLVERTEX3DPROC glad_glVertex3d; -#define glVertex3d glad_glVertex3d -typedef void (APIENTRYP PFNGLVERTEX3DVPROC)(const GLdouble *v); -GLAPI PFNGLVERTEX3DVPROC glad_glVertex3dv; -#define glVertex3dv glad_glVertex3dv -typedef void (APIENTRYP PFNGLVERTEX3FPROC)(GLfloat x, GLfloat y, GLfloat z); -GLAPI PFNGLVERTEX3FPROC glad_glVertex3f; -#define glVertex3f glad_glVertex3f -typedef void (APIENTRYP PFNGLVERTEX3FVPROC)(const GLfloat *v); -GLAPI PFNGLVERTEX3FVPROC glad_glVertex3fv; -#define glVertex3fv glad_glVertex3fv -typedef void (APIENTRYP PFNGLVERTEX3IPROC)(GLint x, GLint y, GLint z); -GLAPI PFNGLVERTEX3IPROC glad_glVertex3i; -#define glVertex3i glad_glVertex3i -typedef void (APIENTRYP PFNGLVERTEX3IVPROC)(const GLint *v); -GLAPI PFNGLVERTEX3IVPROC glad_glVertex3iv; -#define glVertex3iv glad_glVertex3iv -typedef void (APIENTRYP PFNGLVERTEX3SPROC)(GLshort x, GLshort y, GLshort z); -GLAPI PFNGLVERTEX3SPROC glad_glVertex3s; -#define glVertex3s glad_glVertex3s -typedef void (APIENTRYP PFNGLVERTEX3SVPROC)(const GLshort *v); -GLAPI PFNGLVERTEX3SVPROC glad_glVertex3sv; -#define glVertex3sv glad_glVertex3sv -typedef void (APIENTRYP PFNGLVERTEX4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI PFNGLVERTEX4DPROC glad_glVertex4d; -#define glVertex4d glad_glVertex4d -typedef void (APIENTRYP PFNGLVERTEX4DVPROC)(const GLdouble *v); -GLAPI PFNGLVERTEX4DVPROC glad_glVertex4dv; -#define glVertex4dv glad_glVertex4dv -typedef void (APIENTRYP PFNGLVERTEX4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI PFNGLVERTEX4FPROC glad_glVertex4f; -#define glVertex4f glad_glVertex4f -typedef void (APIENTRYP PFNGLVERTEX4FVPROC)(const GLfloat *v); -GLAPI PFNGLVERTEX4FVPROC glad_glVertex4fv; -#define glVertex4fv glad_glVertex4fv -typedef void (APIENTRYP PFNGLVERTEX4IPROC)(GLint x, GLint y, GLint z, GLint w); -GLAPI PFNGLVERTEX4IPROC glad_glVertex4i; -#define glVertex4i glad_glVertex4i -typedef void (APIENTRYP PFNGLVERTEX4IVPROC)(const GLint *v); -GLAPI PFNGLVERTEX4IVPROC glad_glVertex4iv; -#define glVertex4iv glad_glVertex4iv -typedef void (APIENTRYP PFNGLVERTEX4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI PFNGLVERTEX4SPROC glad_glVertex4s; -#define glVertex4s glad_glVertex4s -typedef void (APIENTRYP PFNGLVERTEX4SVPROC)(const GLshort *v); -GLAPI PFNGLVERTEX4SVPROC glad_glVertex4sv; -#define glVertex4sv glad_glVertex4sv -typedef void (APIENTRYP PFNGLCLIPPLANEPROC)(GLenum plane, const GLdouble *equation); -GLAPI PFNGLCLIPPLANEPROC glad_glClipPlane; -#define glClipPlane glad_glClipPlane -typedef void (APIENTRYP PFNGLCOLORMATERIALPROC)(GLenum face, GLenum mode); -GLAPI PFNGLCOLORMATERIALPROC glad_glColorMaterial; -#define glColorMaterial glad_glColorMaterial -typedef void (APIENTRYP PFNGLFOGFPROC)(GLenum pname, GLfloat param); -GLAPI PFNGLFOGFPROC glad_glFogf; -#define glFogf glad_glFogf -typedef void (APIENTRYP PFNGLFOGFVPROC)(GLenum pname, const GLfloat *params); -GLAPI PFNGLFOGFVPROC glad_glFogfv; -#define glFogfv glad_glFogfv -typedef void (APIENTRYP PFNGLFOGIPROC)(GLenum pname, GLint param); -GLAPI PFNGLFOGIPROC glad_glFogi; -#define glFogi glad_glFogi -typedef void (APIENTRYP PFNGLFOGIVPROC)(GLenum pname, const GLint *params); -GLAPI PFNGLFOGIVPROC glad_glFogiv; -#define glFogiv glad_glFogiv -typedef void (APIENTRYP PFNGLLIGHTFPROC)(GLenum light, GLenum pname, GLfloat param); -GLAPI PFNGLLIGHTFPROC glad_glLightf; -#define glLightf glad_glLightf -typedef void (APIENTRYP PFNGLLIGHTFVPROC)(GLenum light, GLenum pname, const GLfloat *params); -GLAPI PFNGLLIGHTFVPROC glad_glLightfv; -#define glLightfv glad_glLightfv -typedef void (APIENTRYP PFNGLLIGHTIPROC)(GLenum light, GLenum pname, GLint param); -GLAPI PFNGLLIGHTIPROC glad_glLighti; -#define glLighti glad_glLighti -typedef void (APIENTRYP PFNGLLIGHTIVPROC)(GLenum light, GLenum pname, const GLint *params); -GLAPI PFNGLLIGHTIVPROC glad_glLightiv; -#define glLightiv glad_glLightiv -typedef void (APIENTRYP PFNGLLIGHTMODELFPROC)(GLenum pname, GLfloat param); -GLAPI PFNGLLIGHTMODELFPROC glad_glLightModelf; -#define glLightModelf glad_glLightModelf -typedef void (APIENTRYP PFNGLLIGHTMODELFVPROC)(GLenum pname, const GLfloat *params); -GLAPI PFNGLLIGHTMODELFVPROC glad_glLightModelfv; -#define glLightModelfv glad_glLightModelfv -typedef void (APIENTRYP PFNGLLIGHTMODELIPROC)(GLenum pname, GLint param); -GLAPI PFNGLLIGHTMODELIPROC glad_glLightModeli; -#define glLightModeli glad_glLightModeli -typedef void (APIENTRYP PFNGLLIGHTMODELIVPROC)(GLenum pname, const GLint *params); -GLAPI PFNGLLIGHTMODELIVPROC glad_glLightModeliv; -#define glLightModeliv glad_glLightModeliv -typedef void (APIENTRYP PFNGLLINESTIPPLEPROC)(GLint factor, GLushort pattern); -GLAPI PFNGLLINESTIPPLEPROC glad_glLineStipple; -#define glLineStipple glad_glLineStipple -typedef void (APIENTRYP PFNGLMATERIALFPROC)(GLenum face, GLenum pname, GLfloat param); -GLAPI PFNGLMATERIALFPROC glad_glMaterialf; -#define glMaterialf glad_glMaterialf -typedef void (APIENTRYP PFNGLMATERIALFVPROC)(GLenum face, GLenum pname, const GLfloat *params); -GLAPI PFNGLMATERIALFVPROC glad_glMaterialfv; -#define glMaterialfv glad_glMaterialfv -typedef void (APIENTRYP PFNGLMATERIALIPROC)(GLenum face, GLenum pname, GLint param); -GLAPI PFNGLMATERIALIPROC glad_glMateriali; -#define glMateriali glad_glMateriali -typedef void (APIENTRYP PFNGLMATERIALIVPROC)(GLenum face, GLenum pname, const GLint *params); -GLAPI PFNGLMATERIALIVPROC glad_glMaterialiv; -#define glMaterialiv glad_glMaterialiv -typedef void (APIENTRYP PFNGLPOLYGONSTIPPLEPROC)(const GLubyte *mask); -GLAPI PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple; -#define glPolygonStipple glad_glPolygonStipple -typedef void (APIENTRYP PFNGLSHADEMODELPROC)(GLenum mode); -GLAPI PFNGLSHADEMODELPROC glad_glShadeModel; -#define glShadeModel glad_glShadeModel -typedef void (APIENTRYP PFNGLTEXENVFPROC)(GLenum target, GLenum pname, GLfloat param); -GLAPI PFNGLTEXENVFPROC glad_glTexEnvf; -#define glTexEnvf glad_glTexEnvf -typedef void (APIENTRYP PFNGLTEXENVFVPROC)(GLenum target, GLenum pname, const GLfloat *params); -GLAPI PFNGLTEXENVFVPROC glad_glTexEnvfv; -#define glTexEnvfv glad_glTexEnvfv -typedef void (APIENTRYP PFNGLTEXENVIPROC)(GLenum target, GLenum pname, GLint param); -GLAPI PFNGLTEXENVIPROC glad_glTexEnvi; -#define glTexEnvi glad_glTexEnvi -typedef void (APIENTRYP PFNGLTEXENVIVPROC)(GLenum target, GLenum pname, const GLint *params); -GLAPI PFNGLTEXENVIVPROC glad_glTexEnviv; -#define glTexEnviv glad_glTexEnviv -typedef void (APIENTRYP PFNGLTEXGENDPROC)(GLenum coord, GLenum pname, GLdouble param); -GLAPI PFNGLTEXGENDPROC glad_glTexGend; -#define glTexGend glad_glTexGend -typedef void (APIENTRYP PFNGLTEXGENDVPROC)(GLenum coord, GLenum pname, const GLdouble *params); -GLAPI PFNGLTEXGENDVPROC glad_glTexGendv; -#define glTexGendv glad_glTexGendv -typedef void (APIENTRYP PFNGLTEXGENFPROC)(GLenum coord, GLenum pname, GLfloat param); -GLAPI PFNGLTEXGENFPROC glad_glTexGenf; -#define glTexGenf glad_glTexGenf -typedef void (APIENTRYP PFNGLTEXGENFVPROC)(GLenum coord, GLenum pname, const GLfloat *params); -GLAPI PFNGLTEXGENFVPROC glad_glTexGenfv; -#define glTexGenfv glad_glTexGenfv -typedef void (APIENTRYP PFNGLTEXGENIPROC)(GLenum coord, GLenum pname, GLint param); -GLAPI PFNGLTEXGENIPROC glad_glTexGeni; -#define glTexGeni glad_glTexGeni -typedef void (APIENTRYP PFNGLTEXGENIVPROC)(GLenum coord, GLenum pname, const GLint *params); -GLAPI PFNGLTEXGENIVPROC glad_glTexGeniv; -#define glTexGeniv glad_glTexGeniv -typedef void (APIENTRYP PFNGLFEEDBACKBUFFERPROC)(GLsizei size, GLenum type, GLfloat *buffer); -GLAPI PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer; -#define glFeedbackBuffer glad_glFeedbackBuffer -typedef void (APIENTRYP PFNGLSELECTBUFFERPROC)(GLsizei size, GLuint *buffer); -GLAPI PFNGLSELECTBUFFERPROC glad_glSelectBuffer; -#define glSelectBuffer glad_glSelectBuffer -typedef GLint (APIENTRYP PFNGLRENDERMODEPROC)(GLenum mode); -GLAPI PFNGLRENDERMODEPROC glad_glRenderMode; -#define glRenderMode glad_glRenderMode -typedef void (APIENTRYP PFNGLINITNAMESPROC)(); -GLAPI PFNGLINITNAMESPROC glad_glInitNames; -#define glInitNames glad_glInitNames -typedef void (APIENTRYP PFNGLLOADNAMEPROC)(GLuint name); -GLAPI PFNGLLOADNAMEPROC glad_glLoadName; -#define glLoadName glad_glLoadName -typedef void (APIENTRYP PFNGLPASSTHROUGHPROC)(GLfloat token); -GLAPI PFNGLPASSTHROUGHPROC glad_glPassThrough; -#define glPassThrough glad_glPassThrough -typedef void (APIENTRYP PFNGLPOPNAMEPROC)(); -GLAPI PFNGLPOPNAMEPROC glad_glPopName; -#define glPopName glad_glPopName -typedef void (APIENTRYP PFNGLPUSHNAMEPROC)(GLuint name); -GLAPI PFNGLPUSHNAMEPROC glad_glPushName; -#define glPushName glad_glPushName -typedef void (APIENTRYP PFNGLCLEARACCUMPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI PFNGLCLEARACCUMPROC glad_glClearAccum; -#define glClearAccum glad_glClearAccum -typedef void (APIENTRYP PFNGLCLEARINDEXPROC)(GLfloat c); -GLAPI PFNGLCLEARINDEXPROC glad_glClearIndex; -#define glClearIndex glad_glClearIndex -typedef void (APIENTRYP PFNGLINDEXMASKPROC)(GLuint mask); -GLAPI PFNGLINDEXMASKPROC glad_glIndexMask; -#define glIndexMask glad_glIndexMask -typedef void (APIENTRYP PFNGLACCUMPROC)(GLenum op, GLfloat value); -GLAPI PFNGLACCUMPROC glad_glAccum; -#define glAccum glad_glAccum -typedef void (APIENTRYP PFNGLPOPATTRIBPROC)(); -GLAPI PFNGLPOPATTRIBPROC glad_glPopAttrib; -#define glPopAttrib glad_glPopAttrib -typedef void (APIENTRYP PFNGLPUSHATTRIBPROC)(GLbitfield mask); -GLAPI PFNGLPUSHATTRIBPROC glad_glPushAttrib; -#define glPushAttrib glad_glPushAttrib -typedef void (APIENTRYP PFNGLMAP1DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); -GLAPI PFNGLMAP1DPROC glad_glMap1d; -#define glMap1d glad_glMap1d -typedef void (APIENTRYP PFNGLMAP1FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); -GLAPI PFNGLMAP1FPROC glad_glMap1f; -#define glMap1f glad_glMap1f -typedef void (APIENTRYP PFNGLMAP2DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); -GLAPI PFNGLMAP2DPROC glad_glMap2d; -#define glMap2d glad_glMap2d -typedef void (APIENTRYP PFNGLMAP2FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); -GLAPI PFNGLMAP2FPROC glad_glMap2f; -#define glMap2f glad_glMap2f -typedef void (APIENTRYP PFNGLMAPGRID1DPROC)(GLint un, GLdouble u1, GLdouble u2); -GLAPI PFNGLMAPGRID1DPROC glad_glMapGrid1d; -#define glMapGrid1d glad_glMapGrid1d -typedef void (APIENTRYP PFNGLMAPGRID1FPROC)(GLint un, GLfloat u1, GLfloat u2); -GLAPI PFNGLMAPGRID1FPROC glad_glMapGrid1f; -#define glMapGrid1f glad_glMapGrid1f -typedef void (APIENTRYP PFNGLMAPGRID2DPROC)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); -GLAPI PFNGLMAPGRID2DPROC glad_glMapGrid2d; -#define glMapGrid2d glad_glMapGrid2d -typedef void (APIENTRYP PFNGLMAPGRID2FPROC)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); -GLAPI PFNGLMAPGRID2FPROC glad_glMapGrid2f; -#define glMapGrid2f glad_glMapGrid2f -typedef void (APIENTRYP PFNGLEVALCOORD1DPROC)(GLdouble u); -GLAPI PFNGLEVALCOORD1DPROC glad_glEvalCoord1d; -#define glEvalCoord1d glad_glEvalCoord1d -typedef void (APIENTRYP PFNGLEVALCOORD1DVPROC)(const GLdouble *u); -GLAPI PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv; -#define glEvalCoord1dv glad_glEvalCoord1dv -typedef void (APIENTRYP PFNGLEVALCOORD1FPROC)(GLfloat u); -GLAPI PFNGLEVALCOORD1FPROC glad_glEvalCoord1f; -#define glEvalCoord1f glad_glEvalCoord1f -typedef void (APIENTRYP PFNGLEVALCOORD1FVPROC)(const GLfloat *u); -GLAPI PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv; -#define glEvalCoord1fv glad_glEvalCoord1fv -typedef void (APIENTRYP PFNGLEVALCOORD2DPROC)(GLdouble u, GLdouble v); -GLAPI PFNGLEVALCOORD2DPROC glad_glEvalCoord2d; -#define glEvalCoord2d glad_glEvalCoord2d -typedef void (APIENTRYP PFNGLEVALCOORD2DVPROC)(const GLdouble *u); -GLAPI PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv; -#define glEvalCoord2dv glad_glEvalCoord2dv -typedef void (APIENTRYP PFNGLEVALCOORD2FPROC)(GLfloat u, GLfloat v); -GLAPI PFNGLEVALCOORD2FPROC glad_glEvalCoord2f; -#define glEvalCoord2f glad_glEvalCoord2f -typedef void (APIENTRYP PFNGLEVALCOORD2FVPROC)(const GLfloat *u); -GLAPI PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv; -#define glEvalCoord2fv glad_glEvalCoord2fv -typedef void (APIENTRYP PFNGLEVALMESH1PROC)(GLenum mode, GLint i1, GLint i2); -GLAPI PFNGLEVALMESH1PROC glad_glEvalMesh1; -#define glEvalMesh1 glad_glEvalMesh1 -typedef void (APIENTRYP PFNGLEVALPOINT1PROC)(GLint i); -GLAPI PFNGLEVALPOINT1PROC glad_glEvalPoint1; -#define glEvalPoint1 glad_glEvalPoint1 -typedef void (APIENTRYP PFNGLEVALMESH2PROC)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); -GLAPI PFNGLEVALMESH2PROC glad_glEvalMesh2; -#define glEvalMesh2 glad_glEvalMesh2 -typedef void (APIENTRYP PFNGLEVALPOINT2PROC)(GLint i, GLint j); -GLAPI PFNGLEVALPOINT2PROC glad_glEvalPoint2; -#define glEvalPoint2 glad_glEvalPoint2 -typedef void (APIENTRYP PFNGLALPHAFUNCPROC)(GLenum func, GLfloat ref); -GLAPI PFNGLALPHAFUNCPROC glad_glAlphaFunc; -#define glAlphaFunc glad_glAlphaFunc -typedef void (APIENTRYP PFNGLPIXELZOOMPROC)(GLfloat xfactor, GLfloat yfactor); -GLAPI PFNGLPIXELZOOMPROC glad_glPixelZoom; -#define glPixelZoom glad_glPixelZoom -typedef void (APIENTRYP PFNGLPIXELTRANSFERFPROC)(GLenum pname, GLfloat param); -GLAPI PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf; -#define glPixelTransferf glad_glPixelTransferf -typedef void (APIENTRYP PFNGLPIXELTRANSFERIPROC)(GLenum pname, GLint param); -GLAPI PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi; -#define glPixelTransferi glad_glPixelTransferi -typedef void (APIENTRYP PFNGLPIXELMAPFVPROC)(GLenum map, GLsizei mapsize, const GLfloat *values); -GLAPI PFNGLPIXELMAPFVPROC glad_glPixelMapfv; -#define glPixelMapfv glad_glPixelMapfv -typedef void (APIENTRYP PFNGLPIXELMAPUIVPROC)(GLenum map, GLsizei mapsize, const GLuint *values); -GLAPI PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv; -#define glPixelMapuiv glad_glPixelMapuiv -typedef void (APIENTRYP PFNGLPIXELMAPUSVPROC)(GLenum map, GLsizei mapsize, const GLushort *values); -GLAPI PFNGLPIXELMAPUSVPROC glad_glPixelMapusv; -#define glPixelMapusv glad_glPixelMapusv -typedef void (APIENTRYP PFNGLCOPYPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); -GLAPI PFNGLCOPYPIXELSPROC glad_glCopyPixels; -#define glCopyPixels glad_glCopyPixels -typedef void (APIENTRYP PFNGLDRAWPIXELSPROC)(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLDRAWPIXELSPROC glad_glDrawPixels; -#define glDrawPixels glad_glDrawPixels -typedef void (APIENTRYP PFNGLGETCLIPPLANEPROC)(GLenum plane, GLdouble *equation); -GLAPI PFNGLGETCLIPPLANEPROC glad_glGetClipPlane; -#define glGetClipPlane glad_glGetClipPlane -typedef void (APIENTRYP PFNGLGETLIGHTFVPROC)(GLenum light, GLenum pname, GLfloat *params); -GLAPI PFNGLGETLIGHTFVPROC glad_glGetLightfv; -#define glGetLightfv glad_glGetLightfv -typedef void (APIENTRYP PFNGLGETLIGHTIVPROC)(GLenum light, GLenum pname, GLint *params); -GLAPI PFNGLGETLIGHTIVPROC glad_glGetLightiv; -#define glGetLightiv glad_glGetLightiv -typedef void (APIENTRYP PFNGLGETMAPDVPROC)(GLenum target, GLenum query, GLdouble *v); -GLAPI PFNGLGETMAPDVPROC glad_glGetMapdv; -#define glGetMapdv glad_glGetMapdv -typedef void (APIENTRYP PFNGLGETMAPFVPROC)(GLenum target, GLenum query, GLfloat *v); -GLAPI PFNGLGETMAPFVPROC glad_glGetMapfv; -#define glGetMapfv glad_glGetMapfv -typedef void (APIENTRYP PFNGLGETMAPIVPROC)(GLenum target, GLenum query, GLint *v); -GLAPI PFNGLGETMAPIVPROC glad_glGetMapiv; -#define glGetMapiv glad_glGetMapiv -typedef void (APIENTRYP PFNGLGETMATERIALFVPROC)(GLenum face, GLenum pname, GLfloat *params); -GLAPI PFNGLGETMATERIALFVPROC glad_glGetMaterialfv; -#define glGetMaterialfv glad_glGetMaterialfv -typedef void (APIENTRYP PFNGLGETMATERIALIVPROC)(GLenum face, GLenum pname, GLint *params); -GLAPI PFNGLGETMATERIALIVPROC glad_glGetMaterialiv; -#define glGetMaterialiv glad_glGetMaterialiv -typedef void (APIENTRYP PFNGLGETPIXELMAPFVPROC)(GLenum map, GLfloat *values); -GLAPI PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv; -#define glGetPixelMapfv glad_glGetPixelMapfv -typedef void (APIENTRYP PFNGLGETPIXELMAPUIVPROC)(GLenum map, GLuint *values); -GLAPI PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv; -#define glGetPixelMapuiv glad_glGetPixelMapuiv -typedef void (APIENTRYP PFNGLGETPIXELMAPUSVPROC)(GLenum map, GLushort *values); -GLAPI PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv; -#define glGetPixelMapusv glad_glGetPixelMapusv -typedef void (APIENTRYP PFNGLGETPOLYGONSTIPPLEPROC)(GLubyte *mask); -GLAPI PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; -#define glGetPolygonStipple glad_glGetPolygonStipple -typedef void (APIENTRYP PFNGLGETTEXENVFVPROC)(GLenum target, GLenum pname, GLfloat *params); -GLAPI PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv; -#define glGetTexEnvfv glad_glGetTexEnvfv -typedef void (APIENTRYP PFNGLGETTEXENVIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETTEXENVIVPROC glad_glGetTexEnviv; -#define glGetTexEnviv glad_glGetTexEnviv -typedef void (APIENTRYP PFNGLGETTEXGENDVPROC)(GLenum coord, GLenum pname, GLdouble *params); -GLAPI PFNGLGETTEXGENDVPROC glad_glGetTexGendv; -#define glGetTexGendv glad_glGetTexGendv -typedef void (APIENTRYP PFNGLGETTEXGENFVPROC)(GLenum coord, GLenum pname, GLfloat *params); -GLAPI PFNGLGETTEXGENFVPROC glad_glGetTexGenfv; -#define glGetTexGenfv glad_glGetTexGenfv -typedef void (APIENTRYP PFNGLGETTEXGENIVPROC)(GLenum coord, GLenum pname, GLint *params); -GLAPI PFNGLGETTEXGENIVPROC glad_glGetTexGeniv; -#define glGetTexGeniv glad_glGetTexGeniv -typedef GLboolean (APIENTRYP PFNGLISLISTPROC)(GLuint list); -GLAPI PFNGLISLISTPROC glad_glIsList; -#define glIsList glad_glIsList -typedef void (APIENTRYP PFNGLFRUSTUMPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -GLAPI PFNGLFRUSTUMPROC glad_glFrustum; -#define glFrustum glad_glFrustum -typedef void (APIENTRYP PFNGLLOADIDENTITYPROC)(); -GLAPI PFNGLLOADIDENTITYPROC glad_glLoadIdentity; -#define glLoadIdentity glad_glLoadIdentity -typedef void (APIENTRYP PFNGLLOADMATRIXFPROC)(const GLfloat *m); -GLAPI PFNGLLOADMATRIXFPROC glad_glLoadMatrixf; -#define glLoadMatrixf glad_glLoadMatrixf -typedef void (APIENTRYP PFNGLLOADMATRIXDPROC)(const GLdouble *m); -GLAPI PFNGLLOADMATRIXDPROC glad_glLoadMatrixd; -#define glLoadMatrixd glad_glLoadMatrixd -typedef void (APIENTRYP PFNGLMATRIXMODEPROC)(GLenum mode); -GLAPI PFNGLMATRIXMODEPROC glad_glMatrixMode; -#define glMatrixMode glad_glMatrixMode -typedef void (APIENTRYP PFNGLMULTMATRIXFPROC)(const GLfloat *m); -GLAPI PFNGLMULTMATRIXFPROC glad_glMultMatrixf; -#define glMultMatrixf glad_glMultMatrixf -typedef void (APIENTRYP PFNGLMULTMATRIXDPROC)(const GLdouble *m); -GLAPI PFNGLMULTMATRIXDPROC glad_glMultMatrixd; -#define glMultMatrixd glad_glMultMatrixd -typedef void (APIENTRYP PFNGLORTHOPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -GLAPI PFNGLORTHOPROC glad_glOrtho; -#define glOrtho glad_glOrtho -typedef void (APIENTRYP PFNGLPOPMATRIXPROC)(); -GLAPI PFNGLPOPMATRIXPROC glad_glPopMatrix; -#define glPopMatrix glad_glPopMatrix -typedef void (APIENTRYP PFNGLPUSHMATRIXPROC)(); -GLAPI PFNGLPUSHMATRIXPROC glad_glPushMatrix; -#define glPushMatrix glad_glPushMatrix -typedef void (APIENTRYP PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -GLAPI PFNGLROTATEDPROC glad_glRotated; -#define glRotated glad_glRotated -typedef void (APIENTRYP PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -GLAPI PFNGLROTATEFPROC glad_glRotatef; -#define glRotatef glad_glRotatef -typedef void (APIENTRYP PFNGLSCALEDPROC)(GLdouble x, GLdouble y, GLdouble z); -GLAPI PFNGLSCALEDPROC glad_glScaled; -#define glScaled glad_glScaled -typedef void (APIENTRYP PFNGLSCALEFPROC)(GLfloat x, GLfloat y, GLfloat z); -GLAPI PFNGLSCALEFPROC glad_glScalef; -#define glScalef glad_glScalef -typedef void (APIENTRYP PFNGLTRANSLATEDPROC)(GLdouble x, GLdouble y, GLdouble z); -GLAPI PFNGLTRANSLATEDPROC glad_glTranslated; -#define glTranslated glad_glTranslated -typedef void (APIENTRYP PFNGLTRANSLATEFPROC)(GLfloat x, GLfloat y, GLfloat z); -GLAPI PFNGLTRANSLATEFPROC glad_glTranslatef; -#define glTranslatef glad_glTranslatef -#endif -#ifndef GL_VERSION_1_1 -#define GL_VERSION_1_1 1 -GLAPI int GLAD_GL_VERSION_1_1; -typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); -GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; -#define glDrawArrays glad_glDrawArrays -typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices); -GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; -#define glDrawElements glad_glDrawElements -typedef void (APIENTRYP PFNGLGETPOINTERVPROC)(GLenum pname, void **params); -GLAPI PFNGLGETPOINTERVPROC glad_glGetPointerv; -#define glGetPointerv glad_glGetPointerv -typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); -GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; -#define glPolygonOffset glad_glPolygonOffset -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; -#define glCopyTexImage1D glad_glCopyTexImage1D -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; -#define glCopyTexImage2D glad_glCopyTexImage2D -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; -#define glCopyTexSubImage1D glad_glCopyTexSubImage1D -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; -#define glCopyTexSubImage2D glad_glCopyTexSubImage2D -typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; -#define glTexSubImage1D glad_glTexSubImage1D -typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; -#define glTexSubImage2D glad_glTexSubImage2D -typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); -GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; -#define glBindTexture glad_glBindTexture -typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures); -GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; -#define glDeleteTextures glad_glDeleteTextures -typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures); -GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; -#define glGenTextures glad_glGenTextures -typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); -GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; -#define glIsTexture glad_glIsTexture -typedef void (APIENTRYP PFNGLARRAYELEMENTPROC)(GLint i); -GLAPI PFNGLARRAYELEMENTPROC glad_glArrayElement; -#define glArrayElement glad_glArrayElement -typedef void (APIENTRYP PFNGLCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI PFNGLCOLORPOINTERPROC glad_glColorPointer; -#define glColorPointer glad_glColorPointer -typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEPROC)(GLenum array); -GLAPI PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState; -#define glDisableClientState glad_glDisableClientState -typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERPROC)(GLsizei stride, const void *pointer); -GLAPI PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer; -#define glEdgeFlagPointer glad_glEdgeFlagPointer -typedef void (APIENTRYP PFNGLENABLECLIENTSTATEPROC)(GLenum array); -GLAPI PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState; -#define glEnableClientState glad_glEnableClientState -typedef void (APIENTRYP PFNGLINDEXPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); -GLAPI PFNGLINDEXPOINTERPROC glad_glIndexPointer; -#define glIndexPointer glad_glIndexPointer -typedef void (APIENTRYP PFNGLINTERLEAVEDARRAYSPROC)(GLenum format, GLsizei stride, const void *pointer); -GLAPI PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays; -#define glInterleavedArrays glad_glInterleavedArrays -typedef void (APIENTRYP PFNGLNORMALPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); -GLAPI PFNGLNORMALPOINTERPROC glad_glNormalPointer; -#define glNormalPointer glad_glNormalPointer -typedef void (APIENTRYP PFNGLTEXCOORDPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer; -#define glTexCoordPointer glad_glTexCoordPointer -typedef void (APIENTRYP PFNGLVERTEXPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI PFNGLVERTEXPOINTERPROC glad_glVertexPointer; -#define glVertexPointer glad_glVertexPointer -typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTPROC)(GLsizei n, const GLuint *textures, GLboolean *residences); -GLAPI PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident; -#define glAreTexturesResident glad_glAreTexturesResident -typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint *textures, const GLfloat *priorities); -GLAPI PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; -#define glPrioritizeTextures glad_glPrioritizeTextures -typedef void (APIENTRYP PFNGLINDEXUBPROC)(GLubyte c); -GLAPI PFNGLINDEXUBPROC glad_glIndexub; -#define glIndexub glad_glIndexub -typedef void (APIENTRYP PFNGLINDEXUBVPROC)(const GLubyte *c); -GLAPI PFNGLINDEXUBVPROC glad_glIndexubv; -#define glIndexubv glad_glIndexubv -typedef void (APIENTRYP PFNGLPOPCLIENTATTRIBPROC)(); -GLAPI PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib; -#define glPopClientAttrib glad_glPopClientAttrib -typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBPROC)(GLbitfield mask); -GLAPI PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib; -#define glPushClientAttrib glad_glPushClientAttrib -#endif -#ifndef GL_VERSION_1_2 -#define GL_VERSION_1_2 1 -GLAPI int GLAD_GL_VERSION_1_2; -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); -GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; -#define glDrawRangeElements glad_glDrawRangeElements -typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D; -#define glTexImage3D glad_glTexImage3D -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; -#define glTexSubImage3D glad_glTexSubImage3D -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; -#define glCopyTexSubImage3D glad_glCopyTexSubImage3D -#endif -#ifndef GL_VERSION_1_3 -#define GL_VERSION_1_3 1 -GLAPI int GLAD_GL_VERSION_1_3; -typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); -GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; -#define glActiveTexture glad_glActiveTexture -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); -GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; -#define glSampleCoverage glad_glSampleCoverage -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; -#define glCompressedTexImage3D glad_glCompressedTexImage3D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; -#define glCompressedTexImage2D glad_glCompressedTexImage2D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; -#define glCompressedTexImage1D glad_glCompressedTexImage1D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; -#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; -#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; -#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void *img); -GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; -#define glGetCompressedTexImage glad_glGetCompressedTexImage -typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC)(GLenum texture); -GLAPI PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture; -#define glClientActiveTexture glad_glClientActiveTexture -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC)(GLenum target, GLdouble s); -GLAPI PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d; -#define glMultiTexCoord1d glad_glMultiTexCoord1d -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC)(GLenum target, const GLdouble *v); -GLAPI PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv; -#define glMultiTexCoord1dv glad_glMultiTexCoord1dv -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC)(GLenum target, GLfloat s); -GLAPI PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f; -#define glMultiTexCoord1f glad_glMultiTexCoord1f -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC)(GLenum target, const GLfloat *v); -GLAPI PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv; -#define glMultiTexCoord1fv glad_glMultiTexCoord1fv -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC)(GLenum target, GLint s); -GLAPI PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i; -#define glMultiTexCoord1i glad_glMultiTexCoord1i -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC)(GLenum target, const GLint *v); -GLAPI PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv; -#define glMultiTexCoord1iv glad_glMultiTexCoord1iv -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC)(GLenum target, GLshort s); -GLAPI PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s; -#define glMultiTexCoord1s glad_glMultiTexCoord1s -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC)(GLenum target, const GLshort *v); -GLAPI PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv; -#define glMultiTexCoord1sv glad_glMultiTexCoord1sv -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC)(GLenum target, GLdouble s, GLdouble t); -GLAPI PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d; -#define glMultiTexCoord2d glad_glMultiTexCoord2d -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC)(GLenum target, const GLdouble *v); -GLAPI PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv; -#define glMultiTexCoord2dv glad_glMultiTexCoord2dv -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC)(GLenum target, GLfloat s, GLfloat t); -GLAPI PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f; -#define glMultiTexCoord2f glad_glMultiTexCoord2f -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC)(GLenum target, const GLfloat *v); -GLAPI PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv; -#define glMultiTexCoord2fv glad_glMultiTexCoord2fv -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC)(GLenum target, GLint s, GLint t); -GLAPI PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i; -#define glMultiTexCoord2i glad_glMultiTexCoord2i -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC)(GLenum target, const GLint *v); -GLAPI PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv; -#define glMultiTexCoord2iv glad_glMultiTexCoord2iv -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC)(GLenum target, GLshort s, GLshort t); -GLAPI PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s; -#define glMultiTexCoord2s glad_glMultiTexCoord2s -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC)(GLenum target, const GLshort *v); -GLAPI PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv; -#define glMultiTexCoord2sv glad_glMultiTexCoord2sv -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r); -GLAPI PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d; -#define glMultiTexCoord3d glad_glMultiTexCoord3d -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC)(GLenum target, const GLdouble *v); -GLAPI PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv; -#define glMultiTexCoord3dv glad_glMultiTexCoord3dv -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r); -GLAPI PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f; -#define glMultiTexCoord3f glad_glMultiTexCoord3f -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC)(GLenum target, const GLfloat *v); -GLAPI PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv; -#define glMultiTexCoord3fv glad_glMultiTexCoord3fv -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC)(GLenum target, GLint s, GLint t, GLint r); -GLAPI PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i; -#define glMultiTexCoord3i glad_glMultiTexCoord3i -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC)(GLenum target, const GLint *v); -GLAPI PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv; -#define glMultiTexCoord3iv glad_glMultiTexCoord3iv -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC)(GLenum target, GLshort s, GLshort t, GLshort r); -GLAPI PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s; -#define glMultiTexCoord3s glad_glMultiTexCoord3s -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC)(GLenum target, const GLshort *v); -GLAPI PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv; -#define glMultiTexCoord3sv glad_glMultiTexCoord3sv -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -GLAPI PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d; -#define glMultiTexCoord4d glad_glMultiTexCoord4d -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC)(GLenum target, const GLdouble *v); -GLAPI PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv; -#define glMultiTexCoord4dv glad_glMultiTexCoord4dv -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -GLAPI PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f; -#define glMultiTexCoord4f glad_glMultiTexCoord4f -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC)(GLenum target, const GLfloat *v); -GLAPI PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv; -#define glMultiTexCoord4fv glad_glMultiTexCoord4fv -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q); -GLAPI PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i; -#define glMultiTexCoord4i glad_glMultiTexCoord4i -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC)(GLenum target, const GLint *v); -GLAPI PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv; -#define glMultiTexCoord4iv glad_glMultiTexCoord4iv -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -GLAPI PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s; -#define glMultiTexCoord4s glad_glMultiTexCoord4s -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC)(GLenum target, const GLshort *v); -GLAPI PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv; -#define glMultiTexCoord4sv glad_glMultiTexCoord4sv -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC)(const GLfloat *m); -GLAPI PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf; -#define glLoadTransposeMatrixf glad_glLoadTransposeMatrixf -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC)(const GLdouble *m); -GLAPI PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd; -#define glLoadTransposeMatrixd glad_glLoadTransposeMatrixd -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC)(const GLfloat *m); -GLAPI PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf; -#define glMultTransposeMatrixf glad_glMultTransposeMatrixf -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC)(const GLdouble *m); -GLAPI PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd; -#define glMultTransposeMatrixd glad_glMultTransposeMatrixd -#endif -#ifndef GL_VERSION_1_4 -#define GL_VERSION_1_4 1 -GLAPI int GLAD_GL_VERSION_1_4; -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; -#define glBlendFuncSeparate glad_glBlendFuncSeparate -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); -GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; -#define glMultiDrawArrays glad_glMultiDrawArrays -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); -GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; -#define glMultiDrawElements glad_glMultiDrawElements -typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); -GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; -#define glPointParameterf glad_glPointParameterf -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat *params); -GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; -#define glPointParameterfv glad_glPointParameterfv -typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); -GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; -#define glPointParameteri glad_glPointParameteri -typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint *params); -GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; -#define glPointParameteriv glad_glPointParameteriv -typedef void (APIENTRYP PFNGLFOGCOORDFPROC)(GLfloat coord); -GLAPI PFNGLFOGCOORDFPROC glad_glFogCoordf; -#define glFogCoordf glad_glFogCoordf -typedef void (APIENTRYP PFNGLFOGCOORDFVPROC)(const GLfloat *coord); -GLAPI PFNGLFOGCOORDFVPROC glad_glFogCoordfv; -#define glFogCoordfv glad_glFogCoordfv -typedef void (APIENTRYP PFNGLFOGCOORDDPROC)(GLdouble coord); -GLAPI PFNGLFOGCOORDDPROC glad_glFogCoordd; -#define glFogCoordd glad_glFogCoordd -typedef void (APIENTRYP PFNGLFOGCOORDDVPROC)(const GLdouble *coord); -GLAPI PFNGLFOGCOORDDVPROC glad_glFogCoorddv; -#define glFogCoorddv glad_glFogCoorddv -typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); -GLAPI PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer; -#define glFogCoordPointer glad_glFogCoordPointer -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); -GLAPI PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b; -#define glSecondaryColor3b glad_glSecondaryColor3b -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC)(const GLbyte *v); -GLAPI PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv; -#define glSecondaryColor3bv glad_glSecondaryColor3bv -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); -GLAPI PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d; -#define glSecondaryColor3d glad_glSecondaryColor3d -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC)(const GLdouble *v); -GLAPI PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv; -#define glSecondaryColor3dv glad_glSecondaryColor3dv -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); -GLAPI PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f; -#define glSecondaryColor3f glad_glSecondaryColor3f -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC)(const GLfloat *v); -GLAPI PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv; -#define glSecondaryColor3fv glad_glSecondaryColor3fv -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC)(GLint red, GLint green, GLint blue); -GLAPI PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i; -#define glSecondaryColor3i glad_glSecondaryColor3i -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC)(const GLint *v); -GLAPI PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv; -#define glSecondaryColor3iv glad_glSecondaryColor3iv -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); -GLAPI PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s; -#define glSecondaryColor3s glad_glSecondaryColor3s -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC)(const GLshort *v); -GLAPI PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv; -#define glSecondaryColor3sv glad_glSecondaryColor3sv -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); -GLAPI PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub; -#define glSecondaryColor3ub glad_glSecondaryColor3ub -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC)(const GLubyte *v); -GLAPI PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv; -#define glSecondaryColor3ubv glad_glSecondaryColor3ubv -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); -GLAPI PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui; -#define glSecondaryColor3ui glad_glSecondaryColor3ui -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC)(const GLuint *v); -GLAPI PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv; -#define glSecondaryColor3uiv glad_glSecondaryColor3uiv -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); -GLAPI PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us; -#define glSecondaryColor3us glad_glSecondaryColor3us -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC)(const GLushort *v); -GLAPI PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv; -#define glSecondaryColor3usv glad_glSecondaryColor3usv -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer; -#define glSecondaryColorPointer glad_glSecondaryColorPointer -typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC)(GLdouble x, GLdouble y); -GLAPI PFNGLWINDOWPOS2DPROC glad_glWindowPos2d; -#define glWindowPos2d glad_glWindowPos2d -typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC)(const GLdouble *v); -GLAPI PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv; -#define glWindowPos2dv glad_glWindowPos2dv -typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC)(GLfloat x, GLfloat y); -GLAPI PFNGLWINDOWPOS2FPROC glad_glWindowPos2f; -#define glWindowPos2f glad_glWindowPos2f -typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC)(const GLfloat *v); -GLAPI PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv; -#define glWindowPos2fv glad_glWindowPos2fv -typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC)(GLint x, GLint y); -GLAPI PFNGLWINDOWPOS2IPROC glad_glWindowPos2i; -#define glWindowPos2i glad_glWindowPos2i -typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC)(const GLint *v); -GLAPI PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv; -#define glWindowPos2iv glad_glWindowPos2iv -typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC)(GLshort x, GLshort y); -GLAPI PFNGLWINDOWPOS2SPROC glad_glWindowPos2s; -#define glWindowPos2s glad_glWindowPos2s -typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC)(const GLshort *v); -GLAPI PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv; -#define glWindowPos2sv glad_glWindowPos2sv -typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); -GLAPI PFNGLWINDOWPOS3DPROC glad_glWindowPos3d; -#define glWindowPos3d glad_glWindowPos3d -typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC)(const GLdouble *v); -GLAPI PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv; -#define glWindowPos3dv glad_glWindowPos3dv -typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); -GLAPI PFNGLWINDOWPOS3FPROC glad_glWindowPos3f; -#define glWindowPos3f glad_glWindowPos3f -typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC)(const GLfloat *v); -GLAPI PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv; -#define glWindowPos3fv glad_glWindowPos3fv -typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z); -GLAPI PFNGLWINDOWPOS3IPROC glad_glWindowPos3i; -#define glWindowPos3i glad_glWindowPos3i -typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC)(const GLint *v); -GLAPI PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv; -#define glWindowPos3iv glad_glWindowPos3iv -typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z); -GLAPI PFNGLWINDOWPOS3SPROC glad_glWindowPos3s; -#define glWindowPos3s glad_glWindowPos3s -typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC)(const GLshort *v); -GLAPI PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv; -#define glWindowPos3sv glad_glWindowPos3sv -typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; -#define glBlendColor glad_glBlendColor -typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); -GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; -#define glBlendEquation glad_glBlendEquation -#endif -#ifndef GL_VERSION_1_5 -#define GL_VERSION_1_5 1 -GLAPI int GLAD_GL_VERSION_1_5; -typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint *ids); -GLAPI PFNGLGENQUERIESPROC glad_glGenQueries; -#define glGenQueries glad_glGenQueries -typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint *ids); -GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries; -#define glDeleteQueries glad_glDeleteQueries -typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id); -GLAPI PFNGLISQUERYPROC glad_glIsQuery; -#define glIsQuery glad_glIsQuery -typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); -GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery; -#define glBeginQuery glad_glBeginQuery -typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target); -GLAPI PFNGLENDQUERYPROC glad_glEndQuery; -#define glEndQuery glad_glEndQuery -typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv; -#define glGetQueryiv glad_glGetQueryiv -typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint *params); -GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; -#define glGetQueryObjectiv glad_glGetQueryObjectiv -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint *params); -GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; -#define glGetQueryObjectuiv glad_glGetQueryObjectuiv -typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); -GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; -#define glBindBuffer glad_glBindBuffer -typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers); -GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; -#define glDeleteBuffers glad_glDeleteBuffers -typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers); -GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; -#define glGenBuffers glad_glGenBuffers -typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); -GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; -#define glIsBuffer glad_glIsBuffer -typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); -GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; -#define glBufferData glad_glBufferData -typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); -GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; -#define glBufferSubData glad_glBufferSubData -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void *data); -GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; -#define glGetBufferSubData glad_glGetBufferSubData -typedef void * (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); -GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer; -#define glMapBuffer glad_glMapBuffer -typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target); -GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; -#define glUnmapBuffer glad_glUnmapBuffer -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; -#define glGetBufferParameteriv glad_glGetBufferParameteriv -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void **params); -GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; -#define glGetBufferPointerv glad_glGetBufferPointerv -#endif -#ifndef GL_VERSION_2_0 -#define GL_VERSION_2_0 1 -GLAPI int GLAD_GL_VERSION_2_0; -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); -GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; -#define glBlendEquationSeparate glad_glBlendEquationSeparate -typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs); -GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; -#define glDrawBuffers glad_glDrawBuffers -typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; -#define glStencilOpSeparate glad_glStencilOpSeparate -typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); -GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; -#define glStencilFuncSeparate glad_glStencilFuncSeparate -typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); -GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; -#define glStencilMaskSeparate glad_glStencilMaskSeparate -typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); -GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; -#define glAttachShader glad_glAttachShader -typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name); -GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; -#define glBindAttribLocation glad_glBindAttribLocation -typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); -GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; -#define glCompileShader glad_glCompileShader -typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(); -GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; -#define glCreateProgram glad_glCreateProgram -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); -GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; -#define glCreateShader glad_glCreateShader -typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); -GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; -#define glDeleteProgram glad_glDeleteProgram -typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); -GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; -#define glDeleteShader glad_glDeleteShader -typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); -GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; -#define glDetachShader glad_glDetachShader -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); -GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; -#define glDisableVertexAttribArray glad_glDisableVertexAttribArray -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); -GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; -#define glEnableVertexAttribArray glad_glEnableVertexAttribArray -typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; -#define glGetActiveAttrib glad_glGetActiveAttrib -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; -#define glGetActiveUniform glad_glGetActiveUniform -typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); -GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; -#define glGetAttachedShaders glad_glGetAttachedShaders -typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name); -GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; -#define glGetAttribLocation glad_glGetAttribLocation -typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params); -GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; -#define glGetProgramiv glad_glGetProgramiv -typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; -#define glGetProgramInfoLog glad_glGetProgramInfoLog -typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params); -GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; -#define glGetShaderiv glad_glGetShaderiv -typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; -#define glGetShaderInfoLog glad_glGetShaderInfoLog -typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; -#define glGetShaderSource glad_glGetShaderSource -typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name); -GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; -#define glGetUniformLocation glad_glGetUniformLocation -typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params); -GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; -#define glGetUniformfv glad_glGetUniformfv -typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params); -GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; -#define glGetUniformiv glad_glGetUniformiv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble *params); -GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; -#define glGetVertexAttribdv glad_glGetVertexAttribdv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params); -GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; -#define glGetVertexAttribfv glad_glGetVertexAttribfv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params); -GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; -#define glGetVertexAttribiv glad_glGetVertexAttribiv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer); -GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; -#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv -typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); -GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; -#define glIsProgram glad_glIsProgram -typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); -GLAPI PFNGLISSHADERPROC glad_glIsShader; -#define glIsShader glad_glIsShader -typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); -GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; -#define glLinkProgram glad_glLinkProgram -typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); -GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; -#define glShaderSource glad_glShaderSource -typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); -GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; -#define glUseProgram glad_glUseProgram -typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); -GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; -#define glUniform1f glad_glUniform1f -typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); -GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; -#define glUniform2f glad_glUniform2f -typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; -#define glUniform3f glad_glUniform3f -typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; -#define glUniform4f glad_glUniform4f -typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); -GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; -#define glUniform1i glad_glUniform1i -typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); -GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; -#define glUniform2i glad_glUniform2i -typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); -GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; -#define glUniform3i glad_glUniform3i -typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; -#define glUniform4i glad_glUniform4i -typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; -#define glUniform1fv glad_glUniform1fv -typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; -#define glUniform2fv glad_glUniform2fv -typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; -#define glUniform3fv glad_glUniform3fv -typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; -#define glUniform4fv glad_glUniform4fv -typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; -#define glUniform1iv glad_glUniform1iv -typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; -#define glUniform2iv glad_glUniform2iv -typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; -#define glUniform3iv glad_glUniform3iv -typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; -#define glUniform4iv glad_glUniform4iv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; -#define glUniformMatrix2fv glad_glUniformMatrix2fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; -#define glUniformMatrix3fv glad_glUniformMatrix3fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; -#define glUniformMatrix4fv glad_glUniformMatrix4fv -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); -GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; -#define glValidateProgram glad_glValidateProgram -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); -GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; -#define glVertexAttrib1d glad_glVertexAttrib1d -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; -#define glVertexAttrib1dv glad_glVertexAttrib1dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); -GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; -#define glVertexAttrib1f glad_glVertexAttrib1f -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; -#define glVertexAttrib1fv glad_glVertexAttrib1fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); -GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; -#define glVertexAttrib1s glad_glVertexAttrib1s -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; -#define glVertexAttrib1sv glad_glVertexAttrib1sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); -GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; -#define glVertexAttrib2d glad_glVertexAttrib2d -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; -#define glVertexAttrib2dv glad_glVertexAttrib2dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); -GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; -#define glVertexAttrib2f glad_glVertexAttrib2f -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; -#define glVertexAttrib2fv glad_glVertexAttrib2fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); -GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; -#define glVertexAttrib2s glad_glVertexAttrib2s -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; -#define glVertexAttrib2sv glad_glVertexAttrib2sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; -#define glVertexAttrib3d glad_glVertexAttrib3d -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; -#define glVertexAttrib3dv glad_glVertexAttrib3dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; -#define glVertexAttrib3f glad_glVertexAttrib3f -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; -#define glVertexAttrib3fv glad_glVertexAttrib3fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; -#define glVertexAttrib3s glad_glVertexAttrib3s -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; -#define glVertexAttrib3sv glad_glVertexAttrib3sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte *v); -GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; -#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; -#define glVertexAttrib4Niv glad_glVertexAttrib4Niv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; -#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; -#define glVertexAttrib4Nub glad_glVertexAttrib4Nub -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte *v); -GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; -#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; -#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort *v); -GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; -#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte *v); -GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; -#define glVertexAttrib4bv glad_glVertexAttrib4bv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; -#define glVertexAttrib4d glad_glVertexAttrib4d -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; -#define glVertexAttrib4dv glad_glVertexAttrib4dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; -#define glVertexAttrib4f glad_glVertexAttrib4f -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; -#define glVertexAttrib4fv glad_glVertexAttrib4fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; -#define glVertexAttrib4iv glad_glVertexAttrib4iv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; -#define glVertexAttrib4s glad_glVertexAttrib4s -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; -#define glVertexAttrib4sv glad_glVertexAttrib4sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte *v); -GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; -#define glVertexAttrib4ubv glad_glVertexAttrib4ubv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; -#define glVertexAttrib4uiv glad_glVertexAttrib4uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort *v); -GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; -#define glVertexAttrib4usv glad_glVertexAttrib4usv -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); -GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; -#define glVertexAttribPointer glad_glVertexAttribPointer -#endif -#ifndef GL_VERSION_2_1 -#define GL_VERSION_2_1 1 -GLAPI int GLAD_GL_VERSION_2_1; -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; -#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; -#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; -#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; -#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; -#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; -#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv -#endif -#ifndef GL_VERSION_3_0 -#define GL_VERSION_3_0 1 -GLAPI int GLAD_GL_VERSION_3_0; -typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski; -#define glColorMaski glad_glColorMaski -typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean *data); -GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; -#define glGetBooleani_v glad_glGetBooleani_v -typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint *data); -GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; -#define glGetIntegeri_v glad_glGetIntegeri_v -typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index); -GLAPI PFNGLENABLEIPROC glad_glEnablei; -#define glEnablei glad_glEnablei -typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index); -GLAPI PFNGLDISABLEIPROC glad_glDisablei; -#define glDisablei glad_glDisablei -typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index); -GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi; -#define glIsEnabledi glad_glIsEnabledi -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); -GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; -#define glBeginTransformFeedback glad_glBeginTransformFeedback -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(); -GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; -#define glEndTransformFeedback glad_glEndTransformFeedback -typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; -#define glBindBufferRange glad_glBindBufferRange -typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); -GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; -#define glBindBufferBase glad_glBindBufferBase -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); -GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; -#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; -#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying -typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); -GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor; -#define glClampColor glad_glClampColor -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); -GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; -#define glBeginConditionalRender glad_glBeginConditionalRender -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(); -GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; -#define glEndConditionalRender glad_glEndConditionalRender -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; -#define glVertexAttribIPointer glad_glVertexAttribIPointer -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint *params); -GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; -#define glGetVertexAttribIiv glad_glGetVertexAttribIiv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint *params); -GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; -#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); -GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; -#define glVertexAttribI1i glad_glVertexAttribI1i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); -GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; -#define glVertexAttribI2i glad_glVertexAttribI2i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); -GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; -#define glVertexAttribI3i glad_glVertexAttribI3i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; -#define glVertexAttribI4i glad_glVertexAttribI4i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); -GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; -#define glVertexAttribI1ui glad_glVertexAttribI1ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); -GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; -#define glVertexAttribI2ui glad_glVertexAttribI2ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); -GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; -#define glVertexAttribI3ui glad_glVertexAttribI3ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; -#define glVertexAttribI4ui glad_glVertexAttribI4ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; -#define glVertexAttribI1iv glad_glVertexAttribI1iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; -#define glVertexAttribI2iv glad_glVertexAttribI2iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; -#define glVertexAttribI3iv glad_glVertexAttribI3iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; -#define glVertexAttribI4iv glad_glVertexAttribI4iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; -#define glVertexAttribI1uiv glad_glVertexAttribI1uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; -#define glVertexAttribI2uiv glad_glVertexAttribI2uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; -#define glVertexAttribI3uiv glad_glVertexAttribI3uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; -#define glVertexAttribI4uiv glad_glVertexAttribI4uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte *v); -GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; -#define glVertexAttribI4bv glad_glVertexAttribI4bv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; -#define glVertexAttribI4sv glad_glVertexAttribI4sv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte *v); -GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; -#define glVertexAttribI4ubv glad_glVertexAttribI4ubv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort *v); -GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; -#define glVertexAttribI4usv glad_glVertexAttribI4usv -typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint *params); -GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; -#define glGetUniformuiv glad_glGetUniformuiv -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar *name); -GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; -#define glBindFragDataLocation glad_glBindFragDataLocation -typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar *name); -GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; -#define glGetFragDataLocation glad_glGetFragDataLocation -typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); -GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui; -#define glUniform1ui glad_glUniform1ui -typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); -GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui; -#define glUniform2ui glad_glUniform2ui -typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui; -#define glUniform3ui glad_glUniform3ui -typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui; -#define glUniform4ui glad_glUniform4ui -typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; -#define glUniform1uiv glad_glUniform1uiv -typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; -#define glUniform2uiv glad_glUniform2uiv -typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; -#define glUniform3uiv glad_glUniform3uiv -typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; -#define glUniform4uiv glad_glUniform4uiv -typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint *params); -GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; -#define glTexParameterIiv glad_glTexParameterIiv -typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint *params); -GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; -#define glTexParameterIuiv glad_glTexParameterIuiv -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; -#define glGetTexParameterIiv glad_glGetTexParameterIiv -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint *params); -GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; -#define glGetTexParameterIuiv glad_glGetTexParameterIuiv -typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint *value); -GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; -#define glClearBufferiv glad_glClearBufferiv -typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint *value); -GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; -#define glClearBufferuiv glad_glClearBufferuiv -typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat *value); -GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; -#define glClearBufferfv glad_glClearBufferfv -typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; -#define glClearBufferfi glad_glClearBufferfi -typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); -GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi; -#define glGetStringi glad_glGetStringi -typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); -GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; -#define glIsRenderbuffer glad_glIsRenderbuffer -typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); -GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; -#define glBindRenderbuffer glad_glBindRenderbuffer -typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers); -GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; -#define glDeleteRenderbuffers glad_glDeleteRenderbuffers -typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers); -GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; -#define glGenRenderbuffers glad_glGenRenderbuffers -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; -#define glRenderbufferStorage glad_glRenderbufferStorage -typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; -#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv -typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); -GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; -#define glIsFramebuffer glad_glIsFramebuffer -typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); -GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; -#define glBindFramebuffer glad_glBindFramebuffer -typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers); -GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; -#define glDeleteFramebuffers glad_glDeleteFramebuffers -typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); -GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; -#define glGenFramebuffers glad_glGenFramebuffers -typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); -GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; -#define glCheckFramebufferStatus glad_glCheckFramebufferStatus -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; -#define glFramebufferTexture1D glad_glFramebufferTexture1D -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; -#define glFramebufferTexture2D glad_glFramebufferTexture2D -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; -#define glFramebufferTexture3D glad_glFramebufferTexture3D -typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; -#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params); -GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; -#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv -typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); -GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; -#define glGenerateMipmap glad_glGenerateMipmap -typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; -#define glBlitFramebuffer glad_glBlitFramebuffer -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; -#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; -#define glFramebufferTextureLayer glad_glFramebufferTextureLayer -typedef void * (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; -#define glMapBufferRange glad_glMapBufferRange -typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); -GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; -#define glFlushMappedBufferRange glad_glFlushMappedBufferRange -typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array); -GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; -#define glBindVertexArray glad_glBindVertexArray -typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint *arrays); -GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; -#define glDeleteVertexArrays glad_glDeleteVertexArrays -typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays); -GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; -#define glGenVertexArrays glad_glGenVertexArrays -typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array); -GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; -#define glIsVertexArray glad_glIsVertexArray -#endif -#ifndef GL_VERSION_3_1 -#define GL_VERSION_3_1 1 -GLAPI int GLAD_GL_VERSION_3_1; -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); -GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; -#define glDrawArraysInstanced glad_glDrawArraysInstanced -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); -GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; -#define glDrawElementsInstanced glad_glDrawElementsInstanced -typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); -GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer; -#define glTexBuffer glad_glTexBuffer -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); -GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; -#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex -typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; -#define glCopyBufferSubData glad_glCopyBufferSubData -typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); -GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; -#define glGetUniformIndices glad_glGetUniformIndices -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; -#define glGetActiveUniformsiv glad_glGetActiveUniformsiv -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; -#define glGetActiveUniformName glad_glGetActiveUniformName -typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar *uniformBlockName); -GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; -#define glGetUniformBlockIndex glad_glGetUniformBlockIndex -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; -#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; -#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName -typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); -GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; -#define glUniformBlockBinding glad_glUniformBlockBinding -#endif -#ifndef GL_VERSION_3_2 -#define GL_VERSION_3_2 1 -GLAPI int GLAD_GL_VERSION_3_2; -typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); -GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; -#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); -GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; -#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); -GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; -#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); -GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; -#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex -typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode); -GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; -#define glProvokingVertex glad_glProvokingVertex -typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); -GLAPI PFNGLFENCESYNCPROC glad_glFenceSync; -#define glFenceSync glad_glFenceSync -typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync); -GLAPI PFNGLISSYNCPROC glad_glIsSync; -#define glIsSync glad_glIsSync -typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); -GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync; -#define glDeleteSync glad_glDeleteSync -typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; -#define glClientWaitSync glad_glClientWaitSync -typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI PFNGLWAITSYNCPROC glad_glWaitSync; -#define glWaitSync glad_glWaitSync -typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 *data); -GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v; -#define glGetInteger64v glad_glGetInteger64v -typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv; -#define glGetSynciv glad_glGetSynciv -typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 *data); -GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; -#define glGetInteger64i_v glad_glGetInteger64i_v -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 *params); -GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; -#define glGetBufferParameteri64v glad_glGetBufferParameteri64v -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; -#define glFramebufferTexture glad_glFramebufferTexture -typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; -#define glTexImage2DMultisample glad_glTexImage2DMultisample -typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; -#define glTexImage3DMultisample glad_glTexImage3DMultisample -typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat *val); -GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; -#define glGetMultisamplefv glad_glGetMultisamplefv -typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); -GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski; -#define glSampleMaski glad_glSampleMaski -#endif -#define GL_MULTISAMPLE_ARB 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F -#define GL_SAMPLE_COVERAGE_ARB 0x80A0 -#define GL_SAMPLE_BUFFERS_ARB 0x80A8 -#define GL_SAMPLES_ARB 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB -#define GL_MULTISAMPLE_BIT_ARB 0x20000000 -#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 -#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 -#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 -#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 -#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 -#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 -#define GL_DEBUG_SOURCE_API 0x8246 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 -#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 -#define GL_DEBUG_SOURCE_APPLICATION 0x824A -#define GL_DEBUG_SOURCE_OTHER 0x824B -#define GL_DEBUG_TYPE_ERROR 0x824C -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E -#define GL_DEBUG_TYPE_PORTABILITY 0x824F -#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 -#define GL_DEBUG_TYPE_OTHER 0x8251 -#define GL_DEBUG_TYPE_MARKER 0x8268 -#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 -#define GL_DEBUG_TYPE_POP_GROUP 0x826A -#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B -#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C -#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D -#define GL_BUFFER 0x82E0 -#define GL_SHADER 0x82E1 -#define GL_PROGRAM 0x82E2 -#define GL_QUERY 0x82E3 -#define GL_PROGRAM_PIPELINE 0x82E4 -#define GL_SAMPLER 0x82E6 -#define GL_MAX_LABEL_LENGTH 0x82E8 -#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES 0x9145 -#define GL_DEBUG_SEVERITY_HIGH 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 -#define GL_DEBUG_SEVERITY_LOW 0x9148 -#define GL_DEBUG_OUTPUT 0x92E0 -#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 -#define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 -#define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245 -#define GL_DEBUG_SOURCE_API_KHR 0x8246 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247 -#define GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249 -#define GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A -#define GL_DEBUG_SOURCE_OTHER_KHR 0x824B -#define GL_DEBUG_TYPE_ERROR_KHR 0x824C -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E -#define GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F -#define GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250 -#define GL_DEBUG_TYPE_OTHER_KHR 0x8251 -#define GL_DEBUG_TYPE_MARKER_KHR 0x8268 -#define GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269 -#define GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A -#define GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B -#define GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C -#define GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D -#define GL_BUFFER_KHR 0x82E0 -#define GL_SHADER_KHR 0x82E1 -#define GL_PROGRAM_KHR 0x82E2 -#define GL_VERTEX_ARRAY_KHR 0x8074 -#define GL_QUERY_KHR 0x82E3 -#define GL_PROGRAM_PIPELINE_KHR 0x82E4 -#define GL_SAMPLER_KHR 0x82E6 -#define GL_MAX_LABEL_LENGTH_KHR 0x82E8 -#define GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145 -#define GL_DEBUG_SEVERITY_HIGH_KHR 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147 -#define GL_DEBUG_SEVERITY_LOW_KHR 0x9148 -#define GL_DEBUG_OUTPUT_KHR 0x92E0 -#define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 -#define GL_STACK_OVERFLOW_KHR 0x0503 -#define GL_STACK_UNDERFLOW_KHR 0x0504 -#define GL_DISPLAY_LIST 0x82E7 -#ifndef GL_ARB_multisample -#define GL_ARB_multisample 1 -GLAPI int GLAD_GL_ARB_multisample; -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC)(GLfloat value, GLboolean invert); -GLAPI PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB; -#define glSampleCoverageARB glad_glSampleCoverageARB -#endif -#ifndef GL_ARB_robustness -#define GL_ARB_robustness 1 -GLAPI int GLAD_GL_ARB_robustness; -typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC)(); -GLAPI PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB; -#define glGetGraphicsResetStatusARB glad_glGetGraphicsResetStatusARB -typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC)(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); -GLAPI PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB; -#define glGetnTexImageARB glad_glGetnTexImageARB -typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); -GLAPI PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB; -#define glReadnPixelsARB glad_glReadnPixelsARB -typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC)(GLenum target, GLint lod, GLsizei bufSize, void *img); -GLAPI PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB; -#define glGetnCompressedTexImageARB glad_glGetnCompressedTexImageARB -typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -GLAPI PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB; -#define glGetnUniformfvARB glad_glGetnUniformfvARB -typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLint *params); -GLAPI PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB; -#define glGetnUniformivARB glad_glGetnUniformivARB -typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint *params); -GLAPI PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB; -#define glGetnUniformuivARB glad_glGetnUniformuivARB -typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLdouble *params); -GLAPI PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB; -#define glGetnUniformdvARB glad_glGetnUniformdvARB -typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); -GLAPI PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB; -#define glGetnMapdvARB glad_glGetnMapdvARB -typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); -GLAPI PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB; -#define glGetnMapfvARB glad_glGetnMapfvARB -typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLint *v); -GLAPI PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB; -#define glGetnMapivARB glad_glGetnMapivARB -typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC)(GLenum map, GLsizei bufSize, GLfloat *values); -GLAPI PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB; -#define glGetnPixelMapfvARB glad_glGetnPixelMapfvARB -typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC)(GLenum map, GLsizei bufSize, GLuint *values); -GLAPI PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB; -#define glGetnPixelMapuivARB glad_glGetnPixelMapuivARB -typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC)(GLenum map, GLsizei bufSize, GLushort *values); -GLAPI PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB; -#define glGetnPixelMapusvARB glad_glGetnPixelMapusvARB -typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC)(GLsizei bufSize, GLubyte *pattern); -GLAPI PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB; -#define glGetnPolygonStippleARB glad_glGetnPolygonStippleARB -typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); -GLAPI PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB; -#define glGetnColorTableARB glad_glGetnColorTableARB -typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); -GLAPI PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB; -#define glGetnConvolutionFilterARB glad_glGetnConvolutionFilterARB -typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); -GLAPI PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB; -#define glGetnSeparableFilterARB glad_glGetnSeparableFilterARB -typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); -GLAPI PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB; -#define glGetnHistogramARB glad_glGetnHistogramARB -typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); -GLAPI PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB; -#define glGetnMinmaxARB glad_glGetnMinmaxARB -#endif -#ifndef GL_KHR_debug -#define GL_KHR_debug 1 -GLAPI int GLAD_GL_KHR_debug; -typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GLAPI PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl; -#define glDebugMessageControl glad_glDebugMessageControl -typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -GLAPI PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert; -#define glDebugMessageInsert glad_glDebugMessageInsert -typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void *userParam); -GLAPI PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback; -#define glDebugMessageCallback glad_glDebugMessageCallback -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -GLAPI PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog; -#define glGetDebugMessageLog glad_glGetDebugMessageLog -typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message); -GLAPI PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup; -#define glPushDebugGroup glad_glPushDebugGroup -typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC)(); -GLAPI PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup; -#define glPopDebugGroup glad_glPopDebugGroup -typedef void (APIENTRYP PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label); -GLAPI PFNGLOBJECTLABELPROC glad_glObjectLabel; -#define glObjectLabel glad_glObjectLabel -typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); -GLAPI PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel; -#define glGetObjectLabel glad_glGetObjectLabel -typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC)(const void *ptr, GLsizei length, const GLchar *label); -GLAPI PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel; -#define glObjectPtrLabel glad_glObjectPtrLabel -typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); -GLAPI PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel; -#define glGetObjectPtrLabel glad_glGetObjectPtrLabel -typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLKHRPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GLAPI PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR; -#define glDebugMessageControlKHR glad_glDebugMessageControlKHR -typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTKHRPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -GLAPI PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR; -#define glDebugMessageInsertKHR glad_glDebugMessageInsertKHR -typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKKHRPROC)(GLDEBUGPROCKHR callback, const void *userParam); -GLAPI PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR; -#define glDebugMessageCallbackKHR glad_glDebugMessageCallbackKHR -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGKHRPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -GLAPI PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR; -#define glGetDebugMessageLogKHR glad_glGetDebugMessageLogKHR -typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPKHRPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message); -GLAPI PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR; -#define glPushDebugGroupKHR glad_glPushDebugGroupKHR -typedef void (APIENTRYP PFNGLPOPDEBUGGROUPKHRPROC)(); -GLAPI PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR; -#define glPopDebugGroupKHR glad_glPopDebugGroupKHR -typedef void (APIENTRYP PFNGLOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label); -GLAPI PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR; -#define glObjectLabelKHR glad_glObjectLabelKHR -typedef void (APIENTRYP PFNGLGETOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); -GLAPI PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR; -#define glGetObjectLabelKHR glad_glGetObjectLabelKHR -typedef void (APIENTRYP PFNGLOBJECTPTRLABELKHRPROC)(const void *ptr, GLsizei length, const GLchar *label); -GLAPI PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR; -#define glObjectPtrLabelKHR glad_glObjectPtrLabelKHR -typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELKHRPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); -GLAPI PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR; -#define glGetObjectPtrLabelKHR glad_glGetObjectPtrLabelKHR -typedef void (APIENTRYP PFNGLGETPOINTERVKHRPROC)(GLenum pname, void **params); -GLAPI PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR; -#define glGetPointervKHR glad_glGetPointervKHR -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/external/glfw/deps/linmath.h b/src/external/glfw/deps/linmath.h deleted file mode 100644 index 9c2e2a0a..00000000 --- a/src/external/glfw/deps/linmath.h +++ /dev/null @@ -1,574 +0,0 @@ -#ifndef LINMATH_H -#define LINMATH_H - -#include - -#ifdef _MSC_VER -#define inline __inline -#endif - -#define LINMATH_H_DEFINE_VEC(n) \ -typedef float vec##n[n]; \ -static inline void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \ -{ \ - int i; \ - for(i=0; i 1e-4) { - mat4x4 T, C, S = {{0}}; - - vec3_norm(u, u); - mat4x4_from_vec3_mul_outer(T, u, u); - - S[1][2] = u[0]; - S[2][1] = -u[0]; - S[2][0] = u[1]; - S[0][2] = -u[1]; - S[0][1] = u[2]; - S[1][0] = -u[2]; - - mat4x4_scale(S, S, s); - - mat4x4_identity(C); - mat4x4_sub(C, C, T); - - mat4x4_scale(C, C, c); - - mat4x4_add(T, T, C); - mat4x4_add(T, T, S); - - T[3][3] = 1.; - mat4x4_mul(R, M, T); - } else { - mat4x4_dup(R, M); - } -} -static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle) -{ - float s = sinf(angle); - float c = cosf(angle); - mat4x4 R = { - {1.f, 0.f, 0.f, 0.f}, - {0.f, c, s, 0.f}, - {0.f, -s, c, 0.f}, - {0.f, 0.f, 0.f, 1.f} - }; - mat4x4_mul(Q, M, R); -} -static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle) -{ - float s = sinf(angle); - float c = cosf(angle); - mat4x4 R = { - { c, 0.f, s, 0.f}, - { 0.f, 1.f, 0.f, 0.f}, - { -s, 0.f, c, 0.f}, - { 0.f, 0.f, 0.f, 1.f} - }; - mat4x4_mul(Q, M, R); -} -static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle) -{ - float s = sinf(angle); - float c = cosf(angle); - mat4x4 R = { - { c, s, 0.f, 0.f}, - { -s, c, 0.f, 0.f}, - { 0.f, 0.f, 1.f, 0.f}, - { 0.f, 0.f, 0.f, 1.f} - }; - mat4x4_mul(Q, M, R); -} -static inline void mat4x4_invert(mat4x4 T, mat4x4 M) -{ - float idet; - float s[6]; - float c[6]; - s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1]; - s[1] = M[0][0]*M[1][2] - M[1][0]*M[0][2]; - s[2] = M[0][0]*M[1][3] - M[1][0]*M[0][3]; - s[3] = M[0][1]*M[1][2] - M[1][1]*M[0][2]; - s[4] = M[0][1]*M[1][3] - M[1][1]*M[0][3]; - s[5] = M[0][2]*M[1][3] - M[1][2]*M[0][3]; - - c[0] = M[2][0]*M[3][1] - M[3][0]*M[2][1]; - c[1] = M[2][0]*M[3][2] - M[3][0]*M[2][2]; - c[2] = M[2][0]*M[3][3] - M[3][0]*M[2][3]; - c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2]; - c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3]; - c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3]; - - /* Assumes it is invertible */ - idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] ); - - T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet; - T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet; - T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet; - T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet; - - T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet; - T[1][1] = ( M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet; - T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet; - T[1][3] = ( M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet; - - T[2][0] = ( M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet; - T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet; - T[2][2] = ( M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet; - T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet; - - T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet; - T[3][1] = ( M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet; - T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet; - T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet; -} -static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M) -{ - float s = 1.; - vec3 h; - - mat4x4_dup(R, M); - vec3_norm(R[2], R[2]); - - s = vec3_mul_inner(R[1], R[2]); - vec3_scale(h, R[2], s); - vec3_sub(R[1], R[1], h); - vec3_norm(R[2], R[2]); - - s = vec3_mul_inner(R[1], R[2]); - vec3_scale(h, R[2], s); - vec3_sub(R[1], R[1], h); - vec3_norm(R[1], R[1]); - - s = vec3_mul_inner(R[0], R[1]); - vec3_scale(h, R[1], s); - vec3_sub(R[0], R[0], h); - vec3_norm(R[0], R[0]); -} - -static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f) -{ - M[0][0] = 2.f*n/(r-l); - M[0][1] = M[0][2] = M[0][3] = 0.f; - - M[1][1] = 2.f*n/(t-b); - M[1][0] = M[1][2] = M[1][3] = 0.f; - - M[2][0] = (r+l)/(r-l); - M[2][1] = (t+b)/(t-b); - M[2][2] = -(f+n)/(f-n); - M[2][3] = -1.f; - - M[3][2] = -2.f*(f*n)/(f-n); - M[3][0] = M[3][1] = M[3][3] = 0.f; -} -static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f) -{ - M[0][0] = 2.f/(r-l); - M[0][1] = M[0][2] = M[0][3] = 0.f; - - M[1][1] = 2.f/(t-b); - M[1][0] = M[1][2] = M[1][3] = 0.f; - - M[2][2] = -2.f/(f-n); - M[2][0] = M[2][1] = M[2][3] = 0.f; - - M[3][0] = -(r+l)/(r-l); - M[3][1] = -(t+b)/(t-b); - M[3][2] = -(f+n)/(f-n); - M[3][3] = 1.f; -} -static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f) -{ - /* NOTE: Degrees are an unhandy unit to work with. - * linmath.h uses radians for everything! */ - float const a = 1.f / (float) tan(y_fov / 2.f); - - m[0][0] = a / aspect; - m[0][1] = 0.f; - m[0][2] = 0.f; - m[0][3] = 0.f; - - m[1][0] = 0.f; - m[1][1] = a; - m[1][2] = 0.f; - m[1][3] = 0.f; - - m[2][0] = 0.f; - m[2][1] = 0.f; - m[2][2] = -((f + n) / (f - n)); - m[2][3] = -1.f; - - m[3][0] = 0.f; - m[3][1] = 0.f; - m[3][2] = -((2.f * f * n) / (f - n)); - m[3][3] = 0.f; -} -static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up) -{ - /* Adapted from Android's OpenGL Matrix.java. */ - /* See the OpenGL GLUT documentation for gluLookAt for a description */ - /* of the algorithm. We implement it in a straightforward way: */ - - /* TODO: The negation of of can be spared by swapping the order of - * operands in the following cross products in the right way. */ - vec3 f; - vec3 s; - vec3 t; - - vec3_sub(f, center, eye); - vec3_norm(f, f); - - vec3_mul_cross(s, f, up); - vec3_norm(s, s); - - vec3_mul_cross(t, s, f); - - m[0][0] = s[0]; - m[0][1] = t[0]; - m[0][2] = -f[0]; - m[0][3] = 0.f; - - m[1][0] = s[1]; - m[1][1] = t[1]; - m[1][2] = -f[1]; - m[1][3] = 0.f; - - m[2][0] = s[2]; - m[2][1] = t[2]; - m[2][2] = -f[2]; - m[2][3] = 0.f; - - m[3][0] = 0.f; - m[3][1] = 0.f; - m[3][2] = 0.f; - m[3][3] = 1.f; - - mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]); -} - -typedef float quat[4]; -static inline void quat_identity(quat q) -{ - q[0] = q[1] = q[2] = 0.f; - q[3] = 1.f; -} -static inline void quat_add(quat r, quat a, quat b) -{ - int i; - for(i=0; i<4; ++i) - r[i] = a[i] + b[i]; -} -static inline void quat_sub(quat r, quat a, quat b) -{ - int i; - for(i=0; i<4; ++i) - r[i] = a[i] - b[i]; -} -static inline void quat_mul(quat r, quat p, quat q) -{ - vec3 w; - vec3_mul_cross(r, p, q); - vec3_scale(w, p, q[3]); - vec3_add(r, r, w); - vec3_scale(w, q, p[3]); - vec3_add(r, r, w); - r[3] = p[3]*q[3] - vec3_mul_inner(p, q); -} -static inline void quat_scale(quat r, quat v, float s) -{ - int i; - for(i=0; i<4; ++i) - r[i] = v[i] * s; -} -static inline float quat_inner_product(quat a, quat b) -{ - float p = 0.f; - int i; - for(i=0; i<4; ++i) - p += b[i]*a[i]; - return p; -} -static inline void quat_conj(quat r, quat q) -{ - int i; - for(i=0; i<3; ++i) - r[i] = -q[i]; - r[3] = q[3]; -} -static inline void quat_rotate(quat r, float angle, vec3 axis) { - int i; - vec3 v; - vec3_scale(v, axis, sinf(angle / 2)); - for(i=0; i<3; ++i) - r[i] = v[i]; - r[3] = cosf(angle / 2); -} -#define quat_norm vec4_norm -static inline void quat_mul_vec3(vec3 r, quat q, vec3 v) -{ -/* - * Method by Fabian 'ryg' Giessen (of Farbrausch) -t = 2 * cross(q.xyz, v) -v' = v + q.w * t + cross(q.xyz, t) - */ - vec3 t = {q[0], q[1], q[2]}; - vec3 u = {q[0], q[1], q[2]}; - - vec3_mul_cross(t, t, v); - vec3_scale(t, t, 2); - - vec3_mul_cross(u, u, t); - vec3_scale(t, t, q[3]); - - vec3_add(r, v, t); - vec3_add(r, r, u); -} -static inline void mat4x4_from_quat(mat4x4 M, quat q) -{ - float a = q[3]; - float b = q[0]; - float c = q[1]; - float d = q[2]; - float a2 = a*a; - float b2 = b*b; - float c2 = c*c; - float d2 = d*d; - - M[0][0] = a2 + b2 - c2 - d2; - M[0][1] = 2.f*(b*c + a*d); - M[0][2] = 2.f*(b*d - a*c); - M[0][3] = 0.f; - - M[1][0] = 2*(b*c - a*d); - M[1][1] = a2 - b2 + c2 - d2; - M[1][2] = 2.f*(c*d + a*b); - M[1][3] = 0.f; - - M[2][0] = 2.f*(b*d + a*c); - M[2][1] = 2.f*(c*d - a*b); - M[2][2] = a2 - b2 - c2 + d2; - M[2][3] = 0.f; - - M[3][0] = M[3][1] = M[3][2] = 0.f; - M[3][3] = 1.f; -} - -static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q) -{ -/* XXX: The way this is written only works for othogonal matrices. */ -/* TODO: Take care of non-orthogonal case. */ - quat_mul_vec3(R[0], q, M[0]); - quat_mul_vec3(R[1], q, M[1]); - quat_mul_vec3(R[2], q, M[2]); - - R[3][0] = R[3][1] = R[3][2] = 0.f; - R[3][3] = 1.f; -} -static inline void quat_from_mat4x4(quat q, mat4x4 M) -{ - float r=0.f; - int i; - - int perm[] = { 0, 1, 2, 0, 1 }; - int *p = perm; - - for(i = 0; i<3; i++) { - float m = M[i][i]; - if( m < r ) - continue; - m = r; - p = &perm[i]; - } - - r = (float) sqrt(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] ); - - if(r < 1e-6) { - q[0] = 1.f; - q[1] = q[2] = q[3] = 0.f; - return; - } - - q[0] = r/2.f; - q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]])/(2.f*r); - q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]])/(2.f*r); - q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r); -} - -#endif diff --git a/src/external/glfw/deps/nuklear.h b/src/external/glfw/deps/nuklear.h deleted file mode 100644 index 333acee7..00000000 --- a/src/external/glfw/deps/nuklear.h +++ /dev/null @@ -1,23590 +0,0 @@ -/* - Nuklear - 1.40.0 - public domain - no warrenty implied; use at your own risk. - authored from 2015-2017 by Micha Mettke - -ABOUT: - This is a minimal state graphical user interface single header toolkit - written in ANSI C and licensed under public domain. - It was designed as a simple embeddable user interface for application and does - not have any dependencies, a default renderbackend or OS window and input handling - but instead provides a very modular library approach by using simple input state - for input and draw commands describing primitive shapes as output. - So instead of providing a layered library that tries to abstract over a number - of platform and render backends it only focuses on the actual UI. - -VALUES: - - Graphical user interface toolkit - - Single header library - - Written in C89 (a.k.a. ANSI C or ISO C90) - - Small codebase (~17kLOC) - - Focus on portability, efficiency and simplicity - - No dependencies (not even the standard library if not wanted) - - Fully skinnable and customizable - - Low memory footprint with total memory control if needed or wanted - - UTF-8 support - - No global or hidden state - - Customizable library modules (you can compile and use only what you need) - - Optional font baker and vertex buffer output - -USAGE: - This library is self contained in one single header file and can be used either - in header only mode or in implementation mode. The header only mode is used - by default when included and allows including this header in other headers - and does not contain the actual implementation. - - The implementation mode requires to define the preprocessor macro - NK_IMPLEMENTATION in *one* .c/.cpp file before #includeing this file, e.g.: - - #define NK_IMPLEMENTATION - #include "nuklear.h" - - Also optionally define the symbols listed in the section "OPTIONAL DEFINES" - below in header and implementation mode if you want to use additional functionality - or need more control over the library. - IMPORTANT: Every time you include "nuklear.h" you have to define the same flags. - This is very important not doing it either leads to compiler errors - or even worse stack corruptions. - -FEATURES: - - Absolutely no platform dependend code - - Memory management control ranging from/to - - Ease of use by allocating everything from standard library - - Control every byte of memory inside the library - - Font handling control ranging from/to - - Use your own font implementation for everything - - Use this libraries internal font baking and handling API - - Drawing output control ranging from/to - - Simple shapes for more high level APIs which already have drawing capabilities - - Hardware accessible anti-aliased vertex buffer output - - Customizable colors and properties ranging from/to - - Simple changes to color by filling a simple color table - - Complete control with ability to use skinning to decorate widgets - - Bendable UI library with widget ranging from/to - - Basic widgets like buttons, checkboxes, slider, ... - - Advanced widget like abstract comboboxes, contextual menus,... - - Compile time configuration to only compile what you need - - Subset which can be used if you do not want to link or use the standard library - - Can be easily modified to only update on user input instead of frame updates - -OPTIONAL DEFINES: - NK_PRIVATE - If defined declares all functions as static, so they can only be accessed - inside the file that contains the implementation - - NK_INCLUDE_FIXED_TYPES - If defined it will include header for fixed sized types - otherwise nuklear tries to select the correct type. If that fails it will - throw a compiler error and you have to select the correct types yourself. - If used needs to be defined for implementation and header - - NK_INCLUDE_DEFAULT_ALLOCATOR - if defined it will include header and provide additional functions - to use this library without caring for memory allocation control and therefore - ease memory management. - Adds the standard library with malloc and free so don't define if you - don't want to link to the standard library - If used needs to be defined for implementation and header - - NK_INCLUDE_STANDARD_IO - if defined it will include header and provide - additional functions depending on file loading. - Adds the standard library with fopen, fclose,... so don't define this - if you don't want to link to the standard library - If used needs to be defined for implementation and header - - NK_INCLUDE_STANDARD_VARARGS - if defined it will include header and provide - additional functions depending on variable arguments - Adds the standard library with va_list and so don't define this if - you don't want to link to the standard library - If used needs to be defined for implementation and header - - NK_INCLUDE_VERTEX_BUFFER_OUTPUT - Defining this adds a vertex draw command list backend to this - library, which allows you to convert queue commands into vertex draw commands. - This is mainly if you need a hardware accessible format for OpenGL, DirectX, - Vulkan, Metal,... - If used needs to be defined for implementation and header - - NK_INCLUDE_FONT_BAKING - Defining this adds `stb_truetype` and `stb_rect_pack` implementation - to this library and provides font baking and rendering. - If you already have font handling or do not want to use this font handler - you don't have to define it. - If used needs to be defined for implementation and header - - NK_INCLUDE_DEFAULT_FONT - Defining this adds the default font: ProggyClean.ttf into this library - which can be loaded into a font atlas and allows using this library without - having a truetype font - Enabling this adds ~12kb to global stack memory - If used needs to be defined for implementation and header - - NK_INCLUDE_COMMAND_USERDATA - Defining this adds a userdata pointer into each command. Can be useful for - example if you want to provide custom shaders depending on the used widget. - Can be combined with the style structures. - If used needs to be defined for implementation and header - - NK_BUTTON_TRIGGER_ON_RELEASE - Different platforms require button clicks occuring either on buttons being - pressed (up to down) or released (down to up). - By default this library will react on buttons being pressed, but if you - define this it will only trigger if a button is released. - If used it is only required to be defined for the implementation part - - NK_ZERO_COMMAND_MEMORY - Defining this will zero out memory for each drawing command added to a - drawing queue (inside nk_command_buffer_push). Zeroing command memory - is very useful for fast checking (using memcmp) if command buffers are - equal and avoid drawing frames when nothing on screen has changed since - previous frame. - - NK_ASSERT - If you don't define this, nuklear will use with assert(). - Adds the standard library so define to nothing of not wanted - If used needs to be defined for implementation and header - - NK_BUFFER_DEFAULT_INITIAL_SIZE - Initial buffer size allocated by all buffers while using the default allocator - functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't - want to allocate the default 4k memory then redefine it. - If used needs to be defined for implementation and header - - NK_MAX_NUMBER_BUFFER - Maximum buffer size for the conversion buffer between float and string - Under normal circumstances this should be more than sufficient. - If used needs to be defined for implementation and header - - NK_INPUT_MAX - Defines the max number of bytes which can be added as text input in one frame. - Under normal circumstances this should be more than sufficient. - If used it is only required to be defined for the implementation part - - NK_MEMSET - You can define this to 'memset' or your own memset implementation - replacement. If not nuklear will use its own version. - If used it is only required to be defined for the implementation part - - NK_MEMCPY - You can define this to 'memcpy' or your own memcpy implementation - replacement. If not nuklear will use its own version. - If used it is only required to be defined for the implementation part - - NK_SQRT - You can define this to 'sqrt' or your own sqrt implementation - replacement. If not nuklear will use its own slow and not highly - accurate version. - If used it is only required to be defined for the implementation part - - NK_SIN - You can define this to 'sinf' or your own sine implementation - replacement. If not nuklear will use its own approximation implementation. - If used it is only required to be defined for the implementation part - - NK_COS - You can define this to 'cosf' or your own cosine implementation - replacement. If not nuklear will use its own approximation implementation. - If used it is only required to be defined for the implementation part - - NK_STRTOD - You can define this to `strtod` or your own string to double conversion - implementation replacement. If not defined nuklear will use its own - imprecise and possibly unsafe version (does not handle nan or infinity!). - If used it is only required to be defined for the implementation part - - NK_DTOA - You can define this to `dtoa` or your own double to string conversion - implementation replacement. If not defined nuklear will use its own - imprecise and possibly unsafe version (does not handle nan or infinity!). - If used it is only required to be defined for the implementation part - - NK_VSNPRINTF - If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` - and want to be safe define this to `vsnprintf` on compilers supporting - later versions of C or C++. By default nuklear will check for your stdlib version - in C as well as compiler version in C++. if `vsnprintf` is available - it will define it to `vsnprintf` directly. If not defined and if you have - older versions of C or C++ it will be defined to `vsprintf` which is unsafe. - If used it is only required to be defined for the implementation part - - NK_BYTE - NK_INT16 - NK_UINT16 - NK_INT32 - NK_UINT32 - NK_SIZE_TYPE - NK_POINTER_TYPE - If you compile without NK_USE_FIXED_TYPE then a number of standard types - will be selected and compile time validated. If they are incorrect you can - define the correct types by overloading these type defines. - -CREDITS: - Developed by Micha Mettke and every direct or indirect contributor. - - Embeds stb_texedit, stb_truetype and stb_rectpack by Sean Barret (public domain) - Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license). - - Big thank you to Omar Cornut (ocornut@github) for his imgui library and - giving me the inspiration for this library, Casey Muratori for handmade hero - and his original immediate mode graphical user interface idea and Sean - Barret for his amazing single header libraries which restored my faith - in libraries and brought me to create some of my own. - -LICENSE: - This software is dual-licensed to the public domain and under the following - license: you are granted a perpetual, irrevocable license to copy, modify, - publish and distribute this file as you see fit. -*/ -#ifndef NK_NUKLEAR_H_ -#define NK_NUKLEAR_H_ - -#ifdef __cplusplus -extern "C" { -#endif -/* - * ============================================================== - * - * CONSTANTS - * - * =============================================================== - */ -#define NK_UNDEFINED (-1.0f) -#define NK_UTF_INVALID 0xFFFD /* internal invalid utf8 rune */ -#define NK_UTF_SIZE 4 /* describes the number of bytes a glyph consists of*/ -#ifndef NK_INPUT_MAX -#define NK_INPUT_MAX 16 -#endif -#ifndef NK_MAX_NUMBER_BUFFER -#define NK_MAX_NUMBER_BUFFER 64 -#endif -#ifndef NK_SCROLLBAR_HIDING_TIMEOUT -#define NK_SCROLLBAR_HIDING_TIMEOUT 4.0f -#endif -/* - * ============================================================== - * - * HELPER - * - * =============================================================== - */ -#ifndef NK_API - #ifdef NK_PRIVATE - #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199409L)) - #define NK_API static inline - #elif defined(__cplusplus) - #define NK_API static inline - #else - #define NK_API static - #endif - #else - #define NK_API extern - #endif -#endif - -#define NK_INTERN static -#define NK_STORAGE static -#define NK_GLOBAL static - -#define NK_FLAG(x) (1 << (x)) -#define NK_STRINGIFY(x) #x -#define NK_MACRO_STRINGIFY(x) NK_STRINGIFY(x) -#define NK_STRING_JOIN_IMMEDIATE(arg1, arg2) arg1 ## arg2 -#define NK_STRING_JOIN_DELAY(arg1, arg2) NK_STRING_JOIN_IMMEDIATE(arg1, arg2) -#define NK_STRING_JOIN(arg1, arg2) NK_STRING_JOIN_DELAY(arg1, arg2) - -#ifdef _MSC_VER -#define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__COUNTER__) -#else -#define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__LINE__) -#endif - -#ifndef NK_STATIC_ASSERT -#define NK_STATIC_ASSERT(exp) typedef char NK_UNIQUE_NAME(_dummy_array)[(exp)?1:-1] -#endif - -#ifndef NK_FILE_LINE -#ifdef _MSC_VER -#define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__COUNTER__) -#else -#define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__LINE__) -#endif -#endif - -#define NK_MIN(a,b) ((a) < (b) ? (a) : (b)) -#define NK_MAX(a,b) ((a) < (b) ? (b) : (a)) -#define NK_CLAMP(i,v,x) (NK_MAX(NK_MIN(v,x), i)) -/* - * =============================================================== - * - * BASIC - * - * =============================================================== - */ -#ifdef NK_INCLUDE_FIXED_TYPES - #include - #define NK_INT8 int8_t - #define NK_UINT8 uint8_t - #define NK_INT16 int16_t - #define NK_UINT16 uint16_t - #define NK_INT32 int32_t - #define NK_UINT32 uint32_t - #define NK_SIZE_TYPE uintptr_t - #define NK_POINTER_TYPE uintptr_t -#else - #ifndef NK_INT8 - #define NK_INT8 char - #endif - #ifndef NK_UINT8 - #define NK_UINT8 unsigned char - #endif - #ifndef NK_INT16 - #define NK_INT16 signed short - #endif - #ifndef NK_UINT16 - #define NK_UINT16 unsigned short - #endif - #ifndef NK_INT32 - #if defined(_MSC_VER) - #define NK_INT32 __int32 - #else - #define NK_INT32 signed int - #endif - #endif - #ifndef NK_UINT32 - #if defined(_MSC_VER) - #define NK_UINT32 unsigned __int32 - #else - #define NK_UINT32 unsigned int - #endif - #endif - #ifndef NK_SIZE_TYPE - #if defined(_WIN64) && defined(_MSC_VER) - #define NK_SIZE_TYPE unsigned __int64 - #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) - #define NK_SIZE_TYPE unsigned __int32 - #elif defined(__GNUC__) || defined(__clang__) - #if defined(__x86_64__) || defined(__ppc64__) - #define NK_SIZE_TYPE unsigned long - #else - #define NK_SIZE_TYPE unsigned int - #endif - #else - #define NK_SIZE_TYPE unsigned long - #endif - #endif - #ifndef NK_POINTER_TYPE - #if defined(_WIN64) && defined(_MSC_VER) - #define NK_POINTER_TYPE unsigned __int64 - #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) - #define NK_POINTER_TYPE unsigned __int32 - #elif defined(__GNUC__) || defined(__clang__) - #if defined(__x86_64__) || defined(__ppc64__) - #define NK_POINTER_TYPE unsigned long - #else - #define NK_POINTER_TYPE unsigned int - #endif - #else - #define NK_POINTER_TYPE unsigned long - #endif - #endif -#endif - -typedef NK_INT8 nk_char; -typedef NK_UINT8 nk_uchar; -typedef NK_UINT8 nk_byte; -typedef NK_INT16 nk_short; -typedef NK_UINT16 nk_ushort; -typedef NK_INT32 nk_int; -typedef NK_UINT32 nk_uint; -typedef NK_SIZE_TYPE nk_size; -typedef NK_POINTER_TYPE nk_ptr; - -typedef nk_uint nk_hash; -typedef nk_uint nk_flags; -typedef nk_uint nk_rune; - -/* Make sure correct type size: - * This will fire with a negative subscript error if the type sizes - * are set incorrectly by the compiler, and compile out if not */ -NK_STATIC_ASSERT(sizeof(nk_short) == 2); -NK_STATIC_ASSERT(sizeof(nk_ushort) == 2); -NK_STATIC_ASSERT(sizeof(nk_uint) == 4); -NK_STATIC_ASSERT(sizeof(nk_int) == 4); -NK_STATIC_ASSERT(sizeof(nk_byte) == 1); -NK_STATIC_ASSERT(sizeof(nk_flags) >= 4); -NK_STATIC_ASSERT(sizeof(nk_rune) >= 4); -NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*)); -NK_STATIC_ASSERT(sizeof(nk_ptr) >= sizeof(void*)); - -/* ============================================================================ - * - * API - * - * =========================================================================== */ -struct nk_buffer; -struct nk_allocator; -struct nk_command_buffer; -struct nk_draw_command; -struct nk_convert_config; -struct nk_style_item; -struct nk_text_edit; -struct nk_draw_list; -struct nk_user_font; -struct nk_panel; -struct nk_context; -struct nk_draw_vertex_layout_element; -struct nk_style_button; -struct nk_style_toggle; -struct nk_style_selectable; -struct nk_style_slide; -struct nk_style_progress; -struct nk_style_scrollbar; -struct nk_style_edit; -struct nk_style_property; -struct nk_style_chart; -struct nk_style_combo; -struct nk_style_tab; -struct nk_style_window_header; -struct nk_style_window; - -enum {nk_false, nk_true}; -struct nk_color {nk_byte r,g,b,a;}; -struct nk_colorf {float r,g,b,a;}; -struct nk_vec2 {float x,y;}; -struct nk_vec2i {short x, y;}; -struct nk_rect {float x,y,w,h;}; -struct nk_recti {short x,y,w,h;}; -typedef char nk_glyph[NK_UTF_SIZE]; -typedef union {void *ptr; int id;} nk_handle; -struct nk_image {nk_handle handle;unsigned short w,h;unsigned short region[4];}; -struct nk_cursor {struct nk_image img; struct nk_vec2 size, offset;}; -struct nk_scroll {nk_uint x, y;}; - -enum nk_heading {NK_UP, NK_RIGHT, NK_DOWN, NK_LEFT}; -enum nk_button_behavior {NK_BUTTON_DEFAULT, NK_BUTTON_REPEATER}; -enum nk_modify {NK_FIXED = nk_false, NK_MODIFIABLE = nk_true}; -enum nk_orientation {NK_VERTICAL, NK_HORIZONTAL}; -enum nk_collapse_states {NK_MINIMIZED = nk_false, NK_MAXIMIZED = nk_true}; -enum nk_show_states {NK_HIDDEN = nk_false, NK_SHOWN = nk_true}; -enum nk_chart_type {NK_CHART_LINES, NK_CHART_COLUMN, NK_CHART_MAX}; -enum nk_chart_event {NK_CHART_HOVERING = 0x01, NK_CHART_CLICKED = 0x02}; -enum nk_color_format {NK_RGB, NK_RGBA}; -enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC}; -enum nk_layout_format {NK_DYNAMIC, NK_STATIC}; -enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB}; - -typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size); -typedef void (*nk_plugin_free)(nk_handle, void *old); -typedef int(*nk_plugin_filter)(const struct nk_text_edit*, nk_rune unicode); -typedef void(*nk_plugin_paste)(nk_handle, struct nk_text_edit*); -typedef void(*nk_plugin_copy)(nk_handle, const char*, int len); - -struct nk_allocator { - nk_handle userdata; - nk_plugin_alloc alloc; - nk_plugin_free free; -}; -enum nk_symbol_type { - NK_SYMBOL_NONE, - NK_SYMBOL_X, - NK_SYMBOL_UNDERSCORE, - NK_SYMBOL_CIRCLE_SOLID, - NK_SYMBOL_CIRCLE_OUTLINE, - NK_SYMBOL_RECT_SOLID, - NK_SYMBOL_RECT_OUTLINE, - NK_SYMBOL_TRIANGLE_UP, - NK_SYMBOL_TRIANGLE_DOWN, - NK_SYMBOL_TRIANGLE_LEFT, - NK_SYMBOL_TRIANGLE_RIGHT, - NK_SYMBOL_PLUS, - NK_SYMBOL_MINUS, - NK_SYMBOL_MAX -}; -/* ============================================================================= - * - * CONTEXT - * - * =============================================================================*/ -/* Contexts are the main entry point and the majestro of nuklear and contain all required state. - * They are used for window, memory, input, style, stack, commands and time management and need - * to be passed into all nuklear GUI specific functions. - * - * Usage - * ------------------- - * To use a context it first has to be initialized which can be achieved by calling - * one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`. - * Each takes in a font handle and a specific way of handling memory. Memory control - * hereby ranges from standard library to just specifing a fixed sized block of memory - * which nuklear has to manage itself from. - * - * struct nk_context ctx; - * nk_init_xxx(&ctx, ...); - * while (1) { - * [...] - * nk_clear(&ctx); - * } - * nk_free(&ctx); - * - * Reference - * ------------------- - * nk_init_default - Initializes context with standard library memory alloction (malloc,free) - * nk_init_fixed - Initializes context from single fixed size memory block - * nk_init - Initializes context with memory allocator callbacks for alloc and free - * nk_init_custom - Initializes context from two buffers. One for draw commands the other for window/panel/table allocations - * nk_clear - Called at the end of the frame to reset and prepare the context for the next frame - * nk_free - Shutdown and free all memory allocated inside the context - * nk_set_user_data - Utility function to pass user data to draw command - */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -/* nk_init_default - Initializes a `nk_context` struct with a default standard library allocator. - * Should be used if you don't want to be bothered with memory management in nuklear. - * Parameters: - * @ctx must point to an either stack or heap allocated `nk_context` struct - * @font must point to a previously initialized font handle for more info look at font documentation - * Return values: - * true(1) on success - * false(0) on failure */ -NK_API int nk_init_default(struct nk_context*, const struct nk_user_font*); -#endif -/* nk_init_fixed - Initializes a `nk_context` struct from a single fixed size memory block - * Should be used if you want complete control over nuklears memory management. - * Especially recommended for system with little memory or systems with virtual memory. - * For the later case you can just allocate for example 16MB of virtual memory - * and only the required amount of memory will actually be commited. - * IMPORTANT: make sure the passed memory block is aligned correctly for `nk_draw_commands` - * Parameters: - * @ctx must point to an either stack or heap allocated `nk_context` struct - * @memory must point to a previously allocated memory block - * @size must contain the total size of @memory - * @font must point to a previously initialized font handle for more info look at font documentation - * Return values: - * true(1) on success - * false(0) on failure */ -NK_API int nk_init_fixed(struct nk_context*, void *memory, nk_size size, const struct nk_user_font*); -/* nk_init - Initializes a `nk_context` struct with memory allocation callbacks for nuklear to allocate - * memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation - * interface to nuklear. Can be useful for cases like monitoring memory consumption. - * Parameters: - * @ctx must point to an either stack or heap allocated `nk_context` struct - * @alloc must point to a previously allocated memory allocator - * @font must point to a previously initialized font handle for more info look at font documentation - * Return values: - * true(1) on success - * false(0) on failure */ -NK_API int nk_init(struct nk_context*, struct nk_allocator*, const struct nk_user_font*); -/* nk_init_custom - Initializes a `nk_context` struct from two different either fixed or growing - * buffers. The first buffer is for allocating draw commands while the second buffer is - * used for allocating windows, panels and state tables. - * Parameters: - * @ctx must point to an either stack or heap allocated `nk_context` struct - * @cmds must point to a previously initialized memory buffer either fixed or dynamic to store draw commands into - * @pool must point to a previously initialized memory buffer either fixed or dynamic to store windows, panels and tables - * @font must point to a previously initialized font handle for more info look at font documentation - * Return values: - * true(1) on success - * false(0) on failure */ -NK_API int nk_init_custom(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font*); -/* nk_clear - Resets the context state at the end of the frame. This includes mostly - * garbage collector tasks like removing windows or table not called and therefore - * used anymore. - * Parameters: - * @ctx must point to a previously initialized `nk_context` struct */ -NK_API void nk_clear(struct nk_context*); -/* nk_free - Frees all memory allocated by nuklear. Not needed if context was - * initialized with `nk_init_fixed`. - * Parameters: - * @ctx must point to a previously initialized `nk_context` struct */ -NK_API void nk_free(struct nk_context*); -#ifdef NK_INCLUDE_COMMAND_USERDATA -/* nk_set_user_data - Sets the currently passed userdata passed down into each draw command. - * Parameters: - * @ctx must point to a previously initialized `nk_context` struct - * @data handle with either pointer or index to be passed into every draw commands */ -NK_API void nk_set_user_data(struct nk_context*, nk_handle handle); -#endif -/* ============================================================================= - * - * INPUT - * - * =============================================================================*/ -/* The input API is responsible for holding the current input state composed of - * mouse, key and text input states. - * It is worth noting that no direct os or window handling is done in nuklear. - * Instead all input state has to be provided by platform specific code. This in one hand - * expects more work from the user and complicates usage but on the other hand - * provides simple abstraction over a big number of platforms, libraries and other - * already provided functionality. - * - * Usage - * ------------------- - * Input state needs to be provided to nuklear by first calling `nk_input_begin` - * which resets internal state like delta mouse position and button transistions. - * After `nk_input_begin` all current input state needs to be provided. This includes - * mouse motion, button and key pressed and released, text input and scrolling. - * Both event- or state-based input handling are supported by this API - * and should work without problems. Finally after all input state has been - * mirrored `nk_input_end` needs to be called to finish input process. - * - * struct nk_context ctx; - * nk_init_xxx(&ctx, ...); - * while (1) { - * Event evt; - * nk_input_begin(&ctx); - * while (GetEvent(&evt)) { - * if (evt.type == MOUSE_MOVE) - * nk_input_motion(&ctx, evt.motion.x, evt.motion.y); - * else if (evt.type == ...) { - * ... - * } - * } - * nk_input_end(&ctx); - * [...] - * nk_clear(&ctx); - * } - * nk_free(&ctx); - * - * Reference - * ------------------- - * nk_input_begin - Begins the input mirroring process. Needs to be called before all other `nk_input_xxx` calls - * nk_input_motion - Mirrors mouse cursor position - * nk_input_key - Mirrors key state with either pressed or released - * nk_input_button - Mirrors mouse button state with either pressed or released - * nk_input_scroll - Mirrors mouse scroll values - * nk_input_char - Adds a single ASCII text character into an internal text buffer - * nk_input_glyph - Adds a single multi-byte UTF-8 character into an internal text buffer - * nk_input_unicode - Adds a single unicode rune into an internal text buffer - * nk_input_end - Ends the input mirroring process by calculating state changes. Don't call any `nk_input_xxx` function referenced above after this call - */ -enum nk_keys { - NK_KEY_NONE, - NK_KEY_SHIFT, - NK_KEY_CTRL, - NK_KEY_DEL, - NK_KEY_ENTER, - NK_KEY_TAB, - NK_KEY_BACKSPACE, - NK_KEY_COPY, - NK_KEY_CUT, - NK_KEY_PASTE, - NK_KEY_UP, - NK_KEY_DOWN, - NK_KEY_LEFT, - NK_KEY_RIGHT, - /* Shortcuts: text field */ - NK_KEY_TEXT_INSERT_MODE, - NK_KEY_TEXT_REPLACE_MODE, - NK_KEY_TEXT_RESET_MODE, - NK_KEY_TEXT_LINE_START, - NK_KEY_TEXT_LINE_END, - NK_KEY_TEXT_START, - NK_KEY_TEXT_END, - NK_KEY_TEXT_UNDO, - NK_KEY_TEXT_REDO, - NK_KEY_TEXT_SELECT_ALL, - NK_KEY_TEXT_WORD_LEFT, - NK_KEY_TEXT_WORD_RIGHT, - /* Shortcuts: scrollbar */ - NK_KEY_SCROLL_START, - NK_KEY_SCROLL_END, - NK_KEY_SCROLL_DOWN, - NK_KEY_SCROLL_UP, - NK_KEY_MAX -}; -enum nk_buttons { - NK_BUTTON_LEFT, - NK_BUTTON_MIDDLE, - NK_BUTTON_RIGHT, - NK_BUTTON_DOUBLE, - NK_BUTTON_MAX -}; -/* nk_input_begin - Begins the input mirroring process by resetting text, scroll - * mouse previous mouse position and movement as well as key state transistions, - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct */ -NK_API void nk_input_begin(struct nk_context*); -/* nk_input_motion - Mirros current mouse position to nuklear - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @x must constain an integer describing the current mouse cursor x-position - * @y must constain an integer describing the current mouse cursor y-position */ -NK_API void nk_input_motion(struct nk_context*, int x, int y); -/* nk_input_key - Mirros state of a specific key to nuklear - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @key must be any value specified in enum `nk_keys` that needs to be mirrored - * @down must be 0 for key is up and 1 for key is down */ -NK_API void nk_input_key(struct nk_context*, enum nk_keys, int down); -/* nk_input_button - Mirros the state of a specific mouse button to nuklear - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @nk_buttons must be any value specified in enum `nk_buttons` that needs to be mirrored - * @x must constain an integer describing mouse cursor x-position on click up/down - * @y must constain an integer describing mouse cursor y-position on click up/down - * @down must be 0 for key is up and 1 for key is down */ -NK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, int down); -/* nk_input_char - Copies a single ASCII character into an internal text buffer - * This is basically a helper function to quickly push ASCII characters into - * nuklear. Note that you can only push up to NK_INPUT_MAX bytes into - * struct `nk_input` between `nk_input_begin` and `nk_input_end`. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @c must be a single ASCII character preferable one that can be printed */ -NK_API void nk_input_scroll(struct nk_context*, struct nk_vec2 val); -/* nk_input_char - Copies a single ASCII character into an internal text buffer - * This is basically a helper function to quickly push ASCII characters into - * nuklear. Note that you can only push up to NK_INPUT_MAX bytes into - * struct `nk_input` between `nk_input_begin` and `nk_input_end`. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @c must be a single ASCII character preferable one that can be printed */ -NK_API void nk_input_char(struct nk_context*, char); -/* nk_input_unicode - Converts a encoded unicode rune into UTF-8 and copies the result - * into an internal text buffer. - * Note that you can only push up to NK_INPUT_MAX bytes into - * struct `nk_input` between `nk_input_begin` and `nk_input_end`. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @glyph UTF-32 uncode codepoint */ -NK_API void nk_input_glyph(struct nk_context*, const nk_glyph); -/* nk_input_unicode - Converts a unicode rune into UTF-8 and copies the result - * into an internal text buffer. - * Note that you can only push up to NK_INPUT_MAX bytes into - * struct `nk_input` between `nk_input_begin` and `nk_input_end`. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @glyph UTF-32 uncode codepoint */ -NK_API void nk_input_unicode(struct nk_context*, nk_rune); -/* nk_input_end - End the input mirroring process by resetting mouse grabbing - * state to ensure the mouse cursor is not grabbed indefinitely. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct */ -NK_API void nk_input_end(struct nk_context*); -/* ============================================================================= - * - * DRAWING - * - * =============================================================================*/ -/* This library was designed to be render backend agnostic so it does - * not draw anything to screen directly. Instead all drawn shapes, widgets - * are made of, are buffered into memory and make up a command queue. - * Each frame therefore fills the command buffer with draw commands - * that then need to be executed by the user and his own render backend. - * After that the command buffer needs to be cleared and a new frame can be - * started. It is probably important to note that the command buffer is the main - * drawing API and the optional vertex buffer API only takes this format and - * converts it into a hardware accessible format. - * - * Usage - * ------------------- - * To draw all draw commands accumulated over a frame you need your own render - * backend able to draw a number of 2D primitives. This includes at least - * filled and stroked rectangles, circles, text, lines, triangles and scissors. - * As soon as this criterion is met you can iterate over each draw command - * and execute each draw command in a interpreter like fashion: - * - * const struct nk_command *cmd = 0; - * nk_foreach(cmd, &ctx) { - * switch (cmd->type) { - * case NK_COMMAND_LINE: - * your_draw_line_function(...) - * break; - * case NK_COMMAND_RECT - * your_draw_rect_function(...) - * break; - * case ...: - * [...] - * } - * - * In program flow context draw commands need to be executed after input has been - * gathered and the complete UI with windows and their contained widgets have - * been executed and before calling `nk_clear` which frees all previously - * allocated draw commands. - * - * struct nk_context ctx; - * nk_init_xxx(&ctx, ...); - * while (1) { - * Event evt; - * nk_input_begin(&ctx); - * while (GetEvent(&evt)) { - * if (evt.type == MOUSE_MOVE) - * nk_input_motion(&ctx, evt.motion.x, evt.motion.y); - * else if (evt.type == [...]) { - * [...] - * } - * } - * nk_input_end(&ctx); - * - * [...] - * - * const struct nk_command *cmd = 0; - * nk_foreach(cmd, &ctx) { - * switch (cmd->type) { - * case NK_COMMAND_LINE: - * your_draw_line_function(...) - * break; - * case NK_COMMAND_RECT - * your_draw_rect_function(...) - * break; - * case ...: - * [...] - * } - * nk_clear(&ctx); - * } - * nk_free(&ctx); - * - * You probably noticed that you have to draw all of the UI each frame which is - * quite wasteful. While the actual UI updating loop is quite fast rendering - * without actually needing it is not. So there are multiple things you could do. - * - * First is only update on input. This of course is only an option if your - * application only depends on the UI and does not require any outside calculations. - * If you actually only update on input make sure to update the UI two times each - * frame and call `nk_clear` directly after the first pass and only draw in - * the second pass. In addition it is recommended to also add additional timers - * to make sure the UI is not drawn more than a fixed number of frames per second. - * - * struct nk_context ctx; - * nk_init_xxx(&ctx, ...); - * while (1) { - * [...wait for input ] - * - * [...do two UI passes ...] - * do_ui(...) - * nk_clear(&ctx); - * do_ui(...) - * - * const struct nk_command *cmd = 0; - * nk_foreach(cmd, &ctx) { - * switch (cmd->type) { - * case NK_COMMAND_LINE: - * your_draw_line_function(...) - * break; - * case NK_COMMAND_RECT - * your_draw_rect_function(...) - * break; - * case ...: - * [...] - * } - * nk_clear(&ctx); - * } - * nk_free(&ctx); - * - * The second probably more applicable trick is to only draw if anything changed. - * It is not really useful for applications with continous draw loop but - * quite useful for desktop applications. To actually get nuklear to only - * draw on changes you first have to define `NK_ZERO_COMMAND_MEMORY` and - * allocate a memory buffer that will store each unique drawing output. - * After each frame you compare the draw command memory inside the library - * with your allocated buffer by memcmp. If memcmp detects differences - * you have to copy the command buffer into the allocated buffer - * and then draw like usual (this example uses fixed memory but you could - * use dynamically allocated memory). - * - * [... other defines ...] - * #define NK_ZERO_COMMAND_MEMORY - * #include "nuklear.h" - * - * struct nk_context ctx; - * void *last = calloc(1,64*1024); - * void *buf = calloc(1,64*1024); - * nk_init_fixed(&ctx, buf, 64*1024); - * while (1) { - * [...input...] - * [...ui...] - * - * void *cmds = nk_buffer_memory(&ctx.memory); - * if (memcmp(cmds, last, ctx.memory.allocated)) { - * memcpy(last,cmds,ctx.memory.allocated); - * const struct nk_command *cmd = 0; - * nk_foreach(cmd, &ctx) { - * switch (cmd->type) { - * case NK_COMMAND_LINE: - * your_draw_line_function(...) - * break; - * case NK_COMMAND_RECT - * your_draw_rect_function(...) - * break; - * case ...: - * [...] - * } - * } - * } - * nk_clear(&ctx); - * } - * nk_free(&ctx); - * - * Finally while using draw commands makes sense for higher abstracted platforms like - * X11 and Win32 or drawing libraries it is often desirable to use graphics - * hardware directly. Therefore it is possible to just define - * `NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output. - * To access the vertex output you first have to convert all draw commands into - * vertexes by calling `nk_convert` which takes in your prefered vertex format. - * After successfully converting all draw commands just iterate over and execute all - * vertex draw commands: - * - * struct nk_convert_config cfg = {}; - * static const struct nk_draw_vertex_layout_element vertex_layout[] = { - * {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, pos)}, - * {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, uv)}, - * {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct your_vertex, col)}, - * {NK_VERTEX_LAYOUT_END} - * }; - * cfg.shape_AA = NK_ANTI_ALIASING_ON; - * cfg.line_AA = NK_ANTI_ALIASING_ON; - * cfg.vertex_layout = vertex_layout; - * cfg.vertex_size = sizeof(struct your_vertex); - * cfg.vertex_alignment = NK_ALIGNOF(struct your_vertex); - * cfg.circle_segment_count = 22; - * cfg.curve_segment_count = 22; - * cfg.arc_segment_count = 22; - * cfg.global_alpha = 1.0f; - * cfg.null = dev->null; - * - * struct nk_buffer cmds, verts, idx; - * nk_buffer_init_default(&cmds); - * nk_buffer_init_default(&verts); - * nk_buffer_init_default(&idx); - * nk_convert(&ctx, &cmds, &verts, &idx, &cfg); - * nk_draw_foreach(cmd, &ctx, &cmds) { - * if (!cmd->elem_count) continue; - * [...] - * } - * nk_buffer_free(&cms); - * nk_buffer_free(&verts); - * nk_buffer_free(&idx); - * - * Reference - * ------------------- - * nk__begin - Returns the first draw command in the context draw command list to be drawn - * nk__next - Increments the draw command iterator to the next command inside the context draw command list - * nk_foreach - Iteratates over each draw command inside the context draw command list - * - * nk_convert - Converts from the abstract draw commands list into a hardware accessable vertex format - * nk__draw_begin - Returns the first vertex command in the context vertex draw list to be executed - * nk__draw_next - Increments the vertex command iterator to the next command inside the context vertex command list - * nk__draw_end - Returns the end of the vertex draw list - * nk_draw_foreach - Iterates over each vertex draw command inside the vertex draw list - */ -enum nk_anti_aliasing {NK_ANTI_ALIASING_OFF, NK_ANTI_ALIASING_ON}; -enum nk_convert_result { - NK_CONVERT_SUCCESS = 0, - NK_CONVERT_INVALID_PARAM = 1, - NK_CONVERT_COMMAND_BUFFER_FULL = NK_FLAG(1), - NK_CONVERT_VERTEX_BUFFER_FULL = NK_FLAG(2), - NK_CONVERT_ELEMENT_BUFFER_FULL = NK_FLAG(3) -}; -struct nk_draw_null_texture { - nk_handle texture; /* texture handle to a texture with a white pixel */ - struct nk_vec2 uv; /* coordinates to a white pixel in the texture */ -}; -struct nk_convert_config { - float global_alpha; /* global alpha value */ - enum nk_anti_aliasing line_AA; /* line anti-aliasing flag can be turned off if you are tight on memory */ - enum nk_anti_aliasing shape_AA; /* shape anti-aliasing flag can be turned off if you are tight on memory */ - unsigned circle_segment_count; /* number of segments used for circles: default to 22 */ - unsigned arc_segment_count; /* number of segments used for arcs: default to 22 */ - unsigned curve_segment_count; /* number of segments used for curves: default to 22 */ - struct nk_draw_null_texture null; /* handle to texture with a white pixel for shape drawing */ - const struct nk_draw_vertex_layout_element *vertex_layout; /* describes the vertex output format and packing */ - nk_size vertex_size; /* sizeof one vertex for vertex packing */ - nk_size vertex_alignment; /* vertex alignment: Can be optained by NK_ALIGNOF */ -}; -/* nk__begin - Returns a draw command list iterator to iterate all draw - * commands accumulated over one frame. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct at the end of a frame - * Return values: - * draw command pointer pointing to the first command inside the draw command list */ -NK_API const struct nk_command* nk__begin(struct nk_context*); -/* nk__next - Returns a draw command list iterator to iterate all draw - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct at the end of a frame - * @cmd must point to an previously a draw command either returned by `nk__begin` or `nk__next` - * Return values: - * draw command pointer pointing to the next command inside the draw command list */ -NK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_command*); -/* nk_foreach - Iterates over each draw command inside the context draw command list - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct at the end of a frame - * @cmd pointer initialized to NULL */ -#define nk_foreach(c, ctx) for((c) = nk__begin(ctx); (c) != 0; (c) = nk__next(ctx,c)) -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -/* nk_convert - converts all internal draw command into vertex draw commands and fills - * three buffers with vertexes, vertex draw commands and vertex indicies. The vertex format - * as well as some other configuration values have to be configurated by filling out a - * `nk_convert_config` struct. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct at the end of a frame - * @cmds must point to a previously initialized buffer to hold converted vertex draw commands - * @vertices must point to a previously initialized buffer to hold all produced verticies - * @elements must point to a previously initialized buffer to hold all procudes vertex indicies - * @config must point to a filled out `nk_config` struct to configure the conversion process - * Returns: - * returns NK_CONVERT_SUCCESS on success and a enum nk_convert_result error values if not */ -NK_API nk_flags nk_convert(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*); -/* nk__draw_begin - Returns a draw vertex command buffer iterator to iterate each the vertex draw command buffer - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct at the end of a frame - * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer - * Return values: - * vertex draw command pointer pointing to the first command inside the vertex draw command buffer */ -NK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*); -/* nk__draw_end - Returns the vertex draw command at the end of the vertex draw command buffer - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct at the end of a frame - * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer - * Return values: - * vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer */ -NK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*); -/* nk__draw_next - Increments the the vertex draw command buffer iterator - * Parameters: - * @cmd must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command - * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer - * @ctx must point to an previously initialized `nk_context` struct at the end of a frame - * Return values: - * vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer */ -NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*); -/* nk_draw_foreach - Iterates over each vertex draw command inside a vertex draw command buffer - * Parameters: - * @cmd nk_draw_command pointer set to NULL - * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer - * @ctx must point to an previously initialized `nk_context` struct at the end of a frame */ -#define nk_draw_foreach(cmd,ctx, b) for((cmd)=nk__draw_begin(ctx, b); (cmd)!=0; (cmd)=nk__draw_next(cmd, b, ctx)) -#endif -/* ============================================================================= - * - * WINDOW - * - * ============================================================================= - * Windows are the main persistent state used inside nuklear and are life time - * controlled by simply "retouching" (i.e. calling) each window each frame. - * All widgets inside nuklear can only be added inside function pair `nk_begin_xxx` - * and `nk_end`. Calling any widgets outside these two functions will result in an - * assert in debug or no state change in release mode. - * - * Each window holds frame persistent state like position, size, flags, state tables, - * and some garbage collected internal persistent widget state. Each window - * is linked into a window stack list which determines the drawing and overlapping - * order. The topmost window thereby is the currently active window. - * - * To change window position inside the stack occurs either automatically by - * user input by being clicked on or programatically by calling `nk_window_focus`. - * Windows by default are visible unless explicitly being defined with flag - * `NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag - * `NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling - * `nk_window_show`. To explicitly close and destroy a window call `nk_window_close`. - * - * Usage - * ------------------- - * To create and keep a window you have to call one of the two `nk_begin_xxx` - * functions to start window declarations and `nk_end` at the end. Furthermore it - * is recommended to check the return value of `nk_begin_xxx` and only process - * widgets inside the window if the value is not 0. Either way you have to call - * `nk_end` at the end of window declarations. Furthmore do not attempt to - * nest `nk_begin_xxx` calls which will hopefully result in an assert or if not - * in a segmation fault. - * - * if (nk_begin_xxx(...) { - * [... widgets ...] - * } - * nk_end(ctx); - * - * In the grand concept window and widget declarations need to occur after input - * handling and before drawing to screen. Not doing so can result in higher - * latency or at worst invalid behavior. Furthermore make sure that `nk_clear` - * is called at the end of the frame. While nuklears default platform backends - * already call `nk_clear` for you if you write your own backend not calling - * `nk_clear` can cause asserts or even worse undefined behavior. - * - * struct nk_context ctx; - * nk_init_xxx(&ctx, ...); - * while (1) { - * Event evt; - * nk_input_begin(&ctx); - * while (GetEvent(&evt)) { - * if (evt.type == MOUSE_MOVE) - * nk_input_motion(&ctx, evt.motion.x, evt.motion.y); - * else if (evt.type == [...]) { - * nk_input_xxx(...); - * } - * } - * nk_input_end(&ctx); - * - * if (nk_begin_xxx(...) { - * [...] - * } - * nk_end(ctx); - * - * const struct nk_command *cmd = 0; - * nk_foreach(cmd, &ctx) { - * case NK_COMMAND_LINE: - * your_draw_line_function(...) - * break; - * case NK_COMMAND_RECT - * your_draw_rect_function(...) - * break; - * case ...: - * [...] - * } - * nk_clear(&ctx); - * } - * nk_free(&ctx); - * - * Reference - * ------------------- - * nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed - * nk_begin_titled - extended window start with seperated title and identifier to allow multiple windows with same name but not title - * nk_end - needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup - * - * nk_window_find - finds and returns the window with give name - * nk_window_get_bounds - returns a rectangle with screen position and size of the currently processed window. - * nk_window_get_position - returns the position of the currently processed window - * nk_window_get_size - returns the size with width and height of the currently processed window - * nk_window_get_width - returns the width of the currently processed window - * nk_window_get_height - returns the height of the currently processed window - * nk_window_get_panel - returns the underlying panel which contains all processing state of the currnet window - * nk_window_get_content_region - returns the position and size of the currently visible and non-clipped space inside the currently processed window - * nk_window_get_content_region_min - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window - * nk_window_get_content_region_max - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window - * nk_window_get_content_region_size - returns the size of the currently visible and non-clipped space inside the currently processed window - * nk_window_get_canvas - returns the draw command buffer. Can be used to draw custom widgets - * - * nk_window_has_focus - returns if the currently processed window is currently active - * nk_window_is_collapsed - returns if the window with given name is currently minimized/collapsed - * nk_window_is_closed - returns if the currently processed window was closed - * nk_window_is_hidden - returns if the currently processed window was hidden - * nk_window_is_active - same as nk_window_has_focus for some reason - * nk_window_is_hovered - returns if the currently processed window is currently being hovered by mouse - * nk_window_is_any_hovered - return if any wndow currently hovered - * nk_item_is_any_active - returns if any window or widgets is currently hovered or active - * - * nk_window_set_bounds - updates position and size of the currently processed window - * nk_window_set_position - updates position of the currently process window - * nk_window_set_size - updates the size of the currently processed window - * nk_window_set_focus - set the currently processed window as active window - * - * nk_window_close - closes the window with given window name which deletes the window at the end of the frame - * nk_window_collapse - collapses the window with given window name - * nk_window_collapse_if - collapses the window with given window name if the given condition was met - * nk_window_show - hides a visible or reshows a hidden window - * nk_window_show_if - hides/shows a window depending on condition - */ -enum nk_panel_flags { - NK_WINDOW_BORDER = NK_FLAG(0), /* Draws a border around the window to visually separate window from the background */ - NK_WINDOW_MOVABLE = NK_FLAG(1), /* The movable flag indicates that a window can be moved by user input or by dragging the window header */ - NK_WINDOW_SCALABLE = NK_FLAG(2), /* The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window */ - NK_WINDOW_CLOSABLE = NK_FLAG(3), /* adds a closable icon into the header */ - NK_WINDOW_MINIMIZABLE = NK_FLAG(4), /* adds a minimize icon into the header */ - NK_WINDOW_NO_SCROLLBAR = NK_FLAG(5), /* Removes the scrollbar from the window */ - NK_WINDOW_TITLE = NK_FLAG(6), /* Forces a header at the top at the window showing the title */ - NK_WINDOW_SCROLL_AUTO_HIDE = NK_FLAG(7), /* Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame */ - NK_WINDOW_BACKGROUND = NK_FLAG(8), /* Always keep window in the background */ - NK_WINDOW_SCALE_LEFT = NK_FLAG(9), /* Puts window scaler in the left-ottom corner instead right-bottom*/ - NK_WINDOW_NO_INPUT = NK_FLAG(10) /* Prevents window of scaling, moving or getting focus */ -}; -/* nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @title window title and identifier. Needs to be persitent over frames to identify the window - * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame - * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors - * Return values: - * returns 1 if the window can be filled up with widgets from this point until `nk_end or 0 otherwise for example if minimized `*/ -NK_API int nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags); -/* nk_begin_titled - extended window start with seperated title and identifier to allow multiple windows with same name but not title - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name window identifier. Needs to be persitent over frames to identify the window - * @title window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set - * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame - * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors - * Return values: - * returns 1 if the window can be filled up with widgets from this point until `nk_end or 0 otherwise `*/ -NK_API int nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags); -/* nk_end - needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup. - * All widget calls after this functions will result in asserts or no state changes - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct */ -NK_API void nk_end(struct nk_context *ctx); -/* nk_window_find - finds and returns the window with give name - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name window identifier - * Return values: - * returns a `nk_window` struct pointing to the idified window or 0 if no window with given name was found */ -NK_API struct nk_window *nk_window_find(struct nk_context *ctx, const char *name); -/* nk_window_get_bounds - returns a rectangle with screen position and size of the currently processed window. - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns a `nk_rect` struct with window upper left position and size */ -NK_API struct nk_rect nk_window_get_bounds(const struct nk_context *ctx); -/* nk_window_get_position - returns the position of the currently processed window. - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns a `nk_vec2` struct with window upper left position */ -NK_API struct nk_vec2 nk_window_get_position(const struct nk_context *ctx); -/* nk_window_get_size - returns the size with width and height of the currently processed window. - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns a `nk_vec2` struct with window size */ -NK_API struct nk_vec2 nk_window_get_size(const struct nk_context*); -/* nk_window_get_width - returns the width of the currently processed window. - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns the window width */ -NK_API float nk_window_get_width(const struct nk_context*); -/* nk_window_get_height - returns the height of the currently processed window. - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns the window height */ -NK_API float nk_window_get_height(const struct nk_context*); -/* nk_window_get_panel - returns the underlying panel which contains all processing state of the currnet window. - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns a pointer to window internal `nk_panel` state. DO NOT keep this pointer around it is only valid until `nk_end` */ -NK_API struct nk_panel* nk_window_get_panel(struct nk_context*); -/* nk_window_get_content_region - returns the position and size of the currently visible and non-clipped space inside the currently processed window. - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns `nk_rect` struct with screen position and size (no scrollbar offset) of the visible space inside the current window */ -NK_API struct nk_rect nk_window_get_content_region(struct nk_context*); -/* nk_window_get_content_region_min - returns the upper left position of the currently visible and non-clipped space inside the currently processed window. - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns `nk_vec2` struct with upper left screen position (no scrollbar offset) of the visible space inside the current window */ -NK_API struct nk_vec2 nk_window_get_content_region_min(struct nk_context*); -/* nk_window_get_content_region_max - returns the lower right screen position of the currently visible and non-clipped space inside the currently processed window. - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns `nk_vec2` struct with lower right screen position (no scrollbar offset) of the visible space inside the current window */ -NK_API struct nk_vec2 nk_window_get_content_region_max(struct nk_context*); -/* nk_window_get_content_region_size - returns the size of the currently visible and non-clipped space inside the currently processed window - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns `nk_vec2` struct with size the visible space inside the current window */ -NK_API struct nk_vec2 nk_window_get_content_region_size(struct nk_context*); -/* nk_window_get_canvas - returns the draw command buffer. Can be used to draw custom widgets - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns a pointer to window internal `nk_command_buffer` struct used as drawing canvas. Can be used to do custom drawing */ -NK_API struct nk_command_buffer* nk_window_get_canvas(struct nk_context*); -/* nk_window_has_focus - returns if the currently processed window is currently active - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns 0 if current window is not active or 1 if it is */ -NK_API int nk_window_has_focus(const struct nk_context*); -/* nk_window_is_collapsed - returns if the window with given name is currently minimized/collapsed - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name of window you want to check is collapsed - * Return values: - * returns 1 if current window is minimized and 0 if window not found or is not minimized */ -NK_API int nk_window_is_collapsed(struct nk_context *ctx, const char *name); -/* nk_window_is_closed - returns if the window with given name was closed by calling `nk_close` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name of window you want to check is closed - * Return values: - * returns 1 if current window was closed or 0 window not found or not closed */ -NK_API int nk_window_is_closed(struct nk_context*, const char*); -/* nk_window_is_hidden - returns if the window with given name is hidden - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name of window you want to check is hidden - * Return values: - * returns 1 if current window is hidden or 0 window not found or visible */ -NK_API int nk_window_is_hidden(struct nk_context*, const char*); -/* nk_window_is_active - same as nk_window_has_focus for some reason - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name of window you want to check is hidden - * Return values: - * returns 1 if current window is active or 0 window not found or not active */ -NK_API int nk_window_is_active(struct nk_context*, const char*); -/* nk_window_is_hovered - return if the current window is being hovered - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns 1 if current window is hovered or 0 otherwise */ -NK_API int nk_window_is_hovered(struct nk_context*); -/* nk_window_is_any_hovered - returns if the any window is being hovered - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns 1 if any window is hovered or 0 otherwise */ -NK_API int nk_window_is_any_hovered(struct nk_context*); -/* nk_item_is_any_active - returns if the any window is being hovered or any widget is currently active. - * Can be used to decide if input should be processed by UI or your specific input handling. - * Example could be UI and 3D camera to move inside a 3D space. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * Return values: - * returns 1 if any window is hovered or any item is active or 0 otherwise */ -NK_API int nk_item_is_any_active(struct nk_context*); -/* nk_window_set_bounds - updates position and size of the currently processed window - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @bounds points to a `nk_rect` struct with the new position and size of currently active window */ -NK_API void nk_window_set_bounds(struct nk_context*, struct nk_rect bounds); -/* nk_window_set_position - updates position of the currently processed window - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @pos points to a `nk_vec2` struct with the new position of currently active window */ -NK_API void nk_window_set_position(struct nk_context*, struct nk_vec2 pos); -/* nk_window_set_size - updates size of the currently processed window - * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @bounds points to a `nk_vec2` struct with the new size of currently active window */ -NK_API void nk_window_set_size(struct nk_context*, struct nk_vec2); -/* nk_window_set_focus - sets the window with given name as active - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name of the window to be set active */ -NK_API void nk_window_set_focus(struct nk_context*, const char *name); -/* nk_window_close - closed a window and marks it for being freed at the end of the frame - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name of the window to be closed */ -NK_API void nk_window_close(struct nk_context *ctx, const char *name); -/* nk_window_collapse - updates collapse state of a window with given name - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name of the window to be either collapse or maximize */ -NK_API void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state); -/* nk_window_collapse - updates collapse state of a window with given name if given condition is met - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name of the window to be either collapse or maximize - * @state the window should be put into - * @condition that has to be true to actually commit the collsage state change */ -NK_API void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond); -/* nk_window_show - updates visibility state of a window with given name - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name of the window to be either collapse or maximize - * @state with either visible or hidden to modify the window with */ -NK_API void nk_window_show(struct nk_context*, const char *name, enum nk_show_states); -/* nk_window_show_if - updates visibility state of a window with given name if a given condition is met - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @name of the window to be either collapse or maximize - * @state with either visible or hidden to modify the window with - * @condition that has to be true to actually commit the visible state change */ -NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond); -/* ============================================================================= - * - * LAYOUT - * - * ============================================================================= */ -/* Layouting in general describes placing widget inside a window with position and size. - * While in this particular implementation there are five different APIs for layouting - * each with different trade offs between control and ease of use. - * - * All layouting methodes in this library are based around the concept of a row. - * A row has a height the window content grows by and a number of columns and each - * layouting method specifies how each widget is placed inside the row. - * After a row has been allocated by calling a layouting functions and then - * filled with widgets will advance an internal pointer over the allocated row. - * - * To acually define a layout you just call the appropriate layouting function - * and each subsequnetial widget call will place the widget as specified. Important - * here is that if you define more widgets then columns defined inside the layout - * functions it will allocate the next row without you having to make another layouting - * call. - * - * Biggest limitation with using all these APIs outside the `nk_layout_space_xxx` API - * is that you have to define the row height for each. However the row height - * often depends on the height of the font. - * - * To fix that internally nuklear uses a minimum row height that is set to the - * height plus padding of currently active font and overwrites the row height - * value if zero. - * - * If you manually want to change the minimum row height then - * use nk_layout_set_min_row_height, and use nk_layout_reset_min_row_height to - * reset it back to be derived from font height. - * - * Also if you change the font in nuklear it will automatically change the minimum - * row height for you and. This means if you change the font but still want - * a minimum row height smaller than the font you have to repush your value. - * - * For actually more advanced UI I would even recommend using the `nk_layout_space_xxx` - * layouting method in combination with a cassowary constraint solver (there are - * some versions on github with permissive license model) to take over all control over widget - * layouting yourself. However for quick and dirty layouting using all the other layouting - * functions should be fine. - * - * Usage - * ------------------- - * 1.) nk_layout_row_dynamic - * The easiest layouting function is `nk_layout_row_dynamic`. It provides each - * widgets with same horizontal space inside the row and dynamically grows - * if the owning window grows in width. So the number of columns dictates - * the size of each widget dynamically by formula: - * - * widget_width = (window_width - padding - spacing) * (1/colum_count) - * - * Just like all other layouting APIs if you define more widget than columns this - * library will allocate a new row and keep all layouting parameters previously - * defined. - * - * if (nk_begin_xxx(...) { - * // first row with height: 30 composed of two widgets - * nk_layout_row_dynamic(&ctx, 30, 2); - * nk_widget(...); - * nk_widget(...); - * - * // second row with same parameter as defined above - * nk_widget(...); - * nk_widget(...); - * - * // third row uses 0 for height which will use auto layouting - * nk_layout_row_dynamic(&ctx, 0, 2); - * nk_widget(...); - * nk_widget(...); - * } - * nk_end(...); - * - * 2.) nk_layout_row_static - * Another easy layouting function is `nk_layout_row_static`. It provides each - * widget with same horizontal pixel width inside the row and does not grow - * if the owning window scales smaller or bigger. - * - * if (nk_begin_xxx(...) { - * // first row with height: 30 composed of two widgets with width: 80 - * nk_layout_row_static(&ctx, 30, 80, 2); - * nk_widget(...); - * nk_widget(...); - * - * // second row with same parameter as defined above - * nk_widget(...); - * nk_widget(...); - * - * // third row uses 0 for height which will use auto layouting - * nk_layout_row_static(&ctx, 0, 80, 2); - * nk_widget(...); - * nk_widget(...); - * } - * nk_end(...); - * - * 3.) nk_layout_row_xxx - * A little bit more advanced layouting API are functions `nk_layout_row_begin`, - * `nk_layout_row_push` and `nk_layout_row_end`. They allow to directly - * specify each column pixel or window ratio in a row. It supports either - * directly setting per column pixel width or widget window ratio but not - * both. Furthermore it is a immediate mode API so each value is directly - * pushed before calling a widget. Therefore the layout is not automatically - * repeating like the last two layouting functions. - * - * if (nk_begin_xxx(...) { - * // first row with height: 25 composed of two widgets with width 60 and 40 - * nk_layout_row_begin(ctx, NK_STATIC, 25, 2); - * nk_layout_row_push(ctx, 60); - * nk_widget(...); - * nk_layout_row_push(ctx, 40); - * nk_widget(...); - * nk_layout_row_end(ctx); - * - * // second row with height: 25 composed of two widgets with window ratio 0.25 and 0.75 - * nk_layout_row_begin(ctx, NK_DYNAMIC, 25, 2); - * nk_layout_row_push(ctx, 0.25f); - * nk_widget(...); - * nk_layout_row_push(ctx, 0.75f); - * nk_widget(...); - * nk_layout_row_end(ctx); - * - * // third row with auto generated height: composed of two widgets with window ratio 0.25 and 0.75 - * nk_layout_row_begin(ctx, NK_DYNAMIC, 0, 2); - * nk_layout_row_push(ctx, 0.25f); - * nk_widget(...); - * nk_layout_row_push(ctx, 0.75f); - * nk_widget(...); - * nk_layout_row_end(ctx); - * } - * nk_end(...); - * - * 4.) nk_layout_row - * The array counterpart to API nk_layout_row_xxx is the single nk_layout_row - * functions. Instead of pushing either pixel or window ratio for every widget - * it allows to define it by array. The trade of for less control is that - * `nk_layout_row` is automatically repeating. Otherwise the behavior is the - * same. - * - * if (nk_begin_xxx(...) { - * // two rows with height: 30 composed of two widgets with width 60 and 40 - * const float size[] = {60,40}; - * nk_layout_row(ctx, NK_STATIC, 30, 2, ratio); - * nk_widget(...); - * nk_widget(...); - * nk_widget(...); - * nk_widget(...); - * - * // two rows with height: 30 composed of two widgets with window ratio 0.25 and 0.75 - * const float ratio[] = {0.25, 0.75}; - * nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); - * nk_widget(...); - * nk_widget(...); - * nk_widget(...); - * nk_widget(...); - * - * // two rows with auto generated height composed of two widgets with window ratio 0.25 and 0.75 - * const float ratio[] = {0.25, 0.75}; - * nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); - * nk_widget(...); - * nk_widget(...); - * nk_widget(...); - * nk_widget(...); - * } - * nk_end(...); - * - * 5.) nk_layout_row_template_xxx - * The most complex and second most flexible API is a simplified flexbox version without - * line wrapping and weights for dynamic widgets. It is an immediate mode API but - * unlike `nk_layout_row_xxx` it has auto repeat behavior and needs to be called - * before calling the templated widgets. - * The row template layout has three different per widget size specifier. The first - * one is the static widget size specifier with fixed widget pixel width. They do - * not grow if the row grows and will always stay the same. The second size - * specifier is nk_layout_row_template_push_variable which defines a - * minumum widget size but it also can grow if more space is available not taken - * by other widgets. Finally there are dynamic widgets which are completly flexible - * and unlike variable widgets can even shrink to zero if not enough space - * is provided. - * - * if (nk_begin_xxx(...) { - * // two rows with height: 30 composed of three widgets - * nk_layout_row_template_begin(ctx, 30); - * nk_layout_row_template_push_dynamic(ctx); - * nk_layout_row_template_push_variable(ctx, 80); - * nk_layout_row_template_push_static(ctx, 80); - * nk_layout_row_template_end(ctx); - * - * nk_widget(...); // dynamic widget can go to zero if not enough space - * nk_widget(...); // variable widget with min 80 pixel but can grow bigger if enough space - * nk_widget(...); // static widget with fixed 80 pixel width - * - * // second row same layout - * nk_widget(...); - * nk_widget(...); - * nk_widget(...); - * } - * nk_end(...); - * - * 6.) nk_layout_space_xxx - * Finally the most flexible API directly allows you to place widgets inside the - * window. The space layout API is an immediate mode API which does not support - * row auto repeat and directly sets position and size of a widget. Position - * and size hereby can be either specified as ratio of alloated space or - * allocated space local position and pixel size. Since this API is quite - * powerfull there are a number of utility functions to get the available space - * and convert between local allocated space and screen space. - * - * if (nk_begin_xxx(...) { - * // static row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) - * nk_layout_space_begin(ctx, NK_STATIC, 500, INT_MAX); - * nk_layout_space_push(ctx, nk_rect(0,0,150,200)); - * nk_widget(...); - * nk_layout_space_push(ctx, nk_rect(200,200,100,200)); - * nk_widget(...); - * nk_layout_space_end(ctx); - * - * // dynamic row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) - * nk_layout_space_begin(ctx, NK_DYNAMIC, 500, INT_MAX); - * nk_layout_space_push(ctx, nk_rect(0.5,0.5,0.1,0.1)); - * nk_widget(...); - * nk_layout_space_push(ctx, nk_rect(0.7,0.6,0.1,0.1)); - * nk_widget(...); - * } - * nk_end(...); - * - * Reference - * ------------------- - * nk_layout_set_min_row_height - set the currently used minimum row height to a specified value - * nk_layout_reset_min_row_height - resets the currently used minimum row height to font height - * - * nk_layout_widget_bounds - calculates current width a static layout row can fit inside a window - * nk_layout_ratio_from_pixel - utility functions to calculate window ratio from pixel size - * - * nk_layout_row_dynamic - current layout is divided into n same sized gowing columns - * nk_layout_row_static - current layout is divided into n same fixed sized columns - * nk_layout_row_begin - starts a new row with given height and number of columns - * nk_layout_row_push - pushes another column with given size or window ratio - * nk_layout_row_end - finished previously started row - * nk_layout_row - specifies row columns in array as either window ratio or size - * - * nk_layout_row_template_begin - begins the row template declaration - * nk_layout_row_template_push_dynamic - adds a dynamic column that dynamically grows and can go to zero if not enough space - * nk_layout_row_template_push_variable - adds a variable column that dynamically grows but does not shrink below specified pixel width - * nk_layout_row_template_push_static - adds a static column that does not grow and will always have the same size - * nk_layout_row_template_end - marks the end of the row template - * - * nk_layout_space_begin - begins a new layouting space that allows to specify each widgets position and size - * nk_layout_space_push - pushes position and size of the next widget in own coordiante space either as pixel or ratio - * nk_layout_space_end - marks the end of the layouting space - * - * nk_layout_space_bounds - callable after nk_layout_space_begin and returns total space allocated - * nk_layout_space_to_screen - convertes vector from nk_layout_space coordiant space into screen space - * nk_layout_space_to_local - convertes vector from screem space into nk_layout_space coordinates - * nk_layout_space_rect_to_screen - convertes rectangle from nk_layout_space coordiant space into screen space - * nk_layout_space_rect_to_local - convertes rectangle from screem space into nk_layout_space coordinates - */ -/* nk_layout_set_min_row_height - sets the currently used minimum row height. - * IMPORTANT: The passed height needs to include both your prefered row height - * as well as padding. No internal padding is added. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` - * @height new minimum row height to be used for auto generating the row height */ -NK_API void nk_layout_set_min_row_height(struct nk_context*, float height); -/* nk_layout_reset_min_row_height - Reset the currently used minimum row height - * back to font height + text padding + additional padding (style_window.min_row_height_padding) - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` */ -NK_API void nk_layout_reset_min_row_height(struct nk_context*); -/* nk_layout_widget_bounds - returns the width of the next row allocate by one of the layouting functions - * Parameters: - * @ctx must point to an previously initialized `nk_context` */ -NK_API struct nk_rect nk_layout_widget_bounds(struct nk_context*); -/* nk_layout_ratio_from_pixel - utility functions to calculate window ratio from pixel size - * Parameters: - * @ctx must point to an previously initialized `nk_context` - * @pixel_width to convert to window ratio */ -NK_API float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width); -/* nk_layout_row_dynamic - Sets current row layout to share horizontal space - * between @cols number of widgets evenly. Once called all subsequent widget - * calls greater than @cols will allocate a new row with same layout. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` - * @row_height holds height of each widget in row or zero for auto layouting - * @cols number of widget inside row */ -NK_API void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols); -/* nk_layout_row_static - Sets current row layout to fill @cols number of widgets - * in row with same @item_width horizontal size. Once called all subsequent widget - * calls greater than @cols will allocate a new row with same layout. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` - * @height holds row height to allocate from panel for widget height - * @item_width holds width of each widget in row - * @cols number of widget inside row */ -NK_API void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols); -/* nk_layout_row_begin - Starts a new dynamic or fixed row with given height and columns. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` - * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns - * @row_height holds height of each widget in row or zero for auto layouting - * @cols number of widget inside row */ -NK_API void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols); -/* nk_layout_row_push - Specifies either window ratio or width of a single column - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_begin` - * @value either a window ratio or fixed width depending on @fmt in previous `nk_layout_row_begin` call */ -NK_API void nk_layout_row_push(struct nk_context*, float value); -/* nk_layout_row_end - finished previously started row - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_begin` */ -NK_API void nk_layout_row_end(struct nk_context*); -/* nk_layout_row - specifies row columns in array as either window ratio or size - * Parameters: - * @ctx must point to an previously initialized `nk_context` - * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns - * @row_height holds height of each widget in row or zero for auto layouting - * @cols number of widget inside row */ -NK_API void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio); -/* nk_layout_row_template_begin - Begins the row template declaration - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @row_height holds height of each widget in row or zero for auto layouting */ -NK_API void nk_layout_row_template_begin(struct nk_context*, float row_height); -/* nk_layout_row_template_push_dynamic - adds a dynamic column that dynamically grows and can go to zero if not enough space - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` */ -NK_API void nk_layout_row_template_push_dynamic(struct nk_context*); -/* nk_layout_row_template_push_variable - adds a variable column that dynamically grows but does not shrink below specified pixel width - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` - * @min_width holds the minimum pixel width the next column must be */ -NK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_width); -/* nk_layout_row_template_push_static - adds a static column that does not grow and will always have the same size - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` - * @width holds the absolulte pixel width value the next column must be */ -NK_API void nk_layout_row_template_push_static(struct nk_context*, float width); -/* nk_layout_row_template_end - marks the end of the row template - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` */ -NK_API void nk_layout_row_template_end(struct nk_context*); -/* nk_layout_space_begin - begins a new layouting space that allows to specify each widgets position and size. - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct - * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns - * @row_height holds height of each widget in row or zero for auto layouting - * @widget_count number of widgets inside row */ -NK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count); -/* nk_layout_space_push - pushes position and size of the next widget in own coordiante space either as pixel or ratio - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` - * @bounds position and size in laoyut space local coordinates */ -NK_API void nk_layout_space_push(struct nk_context*, struct nk_rect); -/* nk_layout_space_end - marks the end of the layout space - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` */ -NK_API void nk_layout_space_end(struct nk_context*); -/* nk_layout_space_bounds - returns total space allocated for `nk_layout_space` - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` */ -NK_API struct nk_rect nk_layout_space_bounds(struct nk_context*); -/* nk_layout_space_to_screen - convertes vector from nk_layout_space coordiant space into screen space - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` - * @vec position to convert from layout space into screen coordinate space */ -NK_API struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2); -/* nk_layout_space_to_screen - convertes vector from layout space into screen space - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` - * @vec position to convert from screen space into layout coordinate space */ -NK_API struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2); -/* nk_layout_space_rect_to_screen - convertes rectangle from screen space into layout space - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` - * @bounds rectangle to convert from layout space into screen space */ -NK_API struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect); -/* nk_layout_space_rect_to_local - convertes rectangle from layout space into screen space - * Parameters: - * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` - * @bounds rectangle to convert from screen space into layout space */ -NK_API struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect); -/* ============================================================================= - * - * GROUP - * - * ============================================================================= */ -NK_API int nk_group_begin(struct nk_context*, const char *title, nk_flags); -NK_API int nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char*, nk_flags); -NK_API int nk_group_scrolled_begin(struct nk_context*, struct nk_scroll*, const char *title, nk_flags); -NK_API void nk_group_scrolled_end(struct nk_context*); -NK_API void nk_group_end(struct nk_context*); -/* ============================================================================= - * - * LIST VIEW - * - * ============================================================================= */ -struct nk_list_view { -/* public: */ - int begin, end, count; -/* private: */ - int total_height; - struct nk_context *ctx; - nk_uint *scroll_pointer; - nk_uint scroll_value; -}; -NK_API int nk_list_view_begin(struct nk_context*, struct nk_list_view *out, const char *id, nk_flags, int row_height, int row_count); -NK_API void nk_list_view_end(struct nk_list_view*); -/* ============================================================================= - * - * TREE - * - * ============================================================================= */ -#define nk_tree_push(ctx, type, title, state) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) -#define nk_tree_push_id(ctx, type, title, state, id) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) -NK_API int nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -#define nk_tree_image_push(ctx, type, img, title, state) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) -#define nk_tree_image_push_id(ctx, type, img, title, state, id) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) -NK_API int nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -NK_API void nk_tree_pop(struct nk_context*); -NK_API int nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state); -NK_API int nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state); -NK_API void nk_tree_state_pop(struct nk_context*); -/* ============================================================================= - * - * WIDGET - * - * ============================================================================= */ -enum nk_widget_layout_states { - NK_WIDGET_INVALID, /* The widget cannot be seen and is completely out of view */ - NK_WIDGET_VALID, /* The widget is completely inside the window and can be updated and drawn */ - NK_WIDGET_ROM /* The widget is partially visible and cannot be updated */ -}; -enum nk_widget_states { - NK_WIDGET_STATE_MODIFIED = NK_FLAG(1), - NK_WIDGET_STATE_INACTIVE = NK_FLAG(2), /* widget is neither active nor hovered */ - NK_WIDGET_STATE_ENTERED = NK_FLAG(3), /* widget has been hovered on the current frame */ - NK_WIDGET_STATE_HOVER = NK_FLAG(4), /* widget is being hovered */ - NK_WIDGET_STATE_ACTIVED = NK_FLAG(5),/* widget is currently activated */ - NK_WIDGET_STATE_LEFT = NK_FLAG(6), /* widget is from this frame on not hovered anymore */ - NK_WIDGET_STATE_HOVERED = NK_WIDGET_STATE_HOVER|NK_WIDGET_STATE_MODIFIED, /* widget is being hovered */ - NK_WIDGET_STATE_ACTIVE = NK_WIDGET_STATE_ACTIVED|NK_WIDGET_STATE_MODIFIED /* widget is currently activated */ -}; -NK_API enum nk_widget_layout_states nk_widget(struct nk_rect*, const struct nk_context*); -NK_API enum nk_widget_layout_states nk_widget_fitting(struct nk_rect*, struct nk_context*, struct nk_vec2); -NK_API struct nk_rect nk_widget_bounds(struct nk_context*); -NK_API struct nk_vec2 nk_widget_position(struct nk_context*); -NK_API struct nk_vec2 nk_widget_size(struct nk_context*); -NK_API float nk_widget_width(struct nk_context*); -NK_API float nk_widget_height(struct nk_context*); -NK_API int nk_widget_is_hovered(struct nk_context*); -NK_API int nk_widget_is_mouse_clicked(struct nk_context*, enum nk_buttons); -NK_API int nk_widget_has_mouse_click_down(struct nk_context*, enum nk_buttons, int down); -NK_API void nk_spacing(struct nk_context*, int cols); -/* ============================================================================= - * - * TEXT - * - * ============================================================================= */ -enum nk_text_align { - NK_TEXT_ALIGN_LEFT = 0x01, - NK_TEXT_ALIGN_CENTERED = 0x02, - NK_TEXT_ALIGN_RIGHT = 0x04, - NK_TEXT_ALIGN_TOP = 0x08, - NK_TEXT_ALIGN_MIDDLE = 0x10, - NK_TEXT_ALIGN_BOTTOM = 0x20 -}; -enum nk_text_alignment { - NK_TEXT_LEFT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_LEFT, - NK_TEXT_CENTERED = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_CENTERED, - NK_TEXT_RIGHT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_RIGHT -}; -NK_API void nk_text(struct nk_context*, const char*, int, nk_flags); -NK_API void nk_text_colored(struct nk_context*, const char*, int, nk_flags, struct nk_color); -NK_API void nk_text_wrap(struct nk_context*, const char*, int); -NK_API void nk_text_wrap_colored(struct nk_context*, const char*, int, struct nk_color); -NK_API void nk_label(struct nk_context*, const char*, nk_flags align); -NK_API void nk_label_colored(struct nk_context*, const char*, nk_flags align, struct nk_color); -NK_API void nk_label_wrap(struct nk_context*, const char*); -NK_API void nk_label_colored_wrap(struct nk_context*, const char*, struct nk_color); -NK_API void nk_image(struct nk_context*, struct nk_image); -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_API void nk_labelf(struct nk_context*, nk_flags, const char*, ...); -NK_API void nk_labelf_colored(struct nk_context*, nk_flags align, struct nk_color, const char*,...); -NK_API void nk_labelf_wrap(struct nk_context*, const char*,...); -NK_API void nk_labelf_colored_wrap(struct nk_context*, struct nk_color, const char*,...); -NK_API void nk_value_bool(struct nk_context*, const char *prefix, int); -NK_API void nk_value_int(struct nk_context*, const char *prefix, int); -NK_API void nk_value_uint(struct nk_context*, const char *prefix, unsigned int); -NK_API void nk_value_float(struct nk_context*, const char *prefix, float); -NK_API void nk_value_color_byte(struct nk_context*, const char *prefix, struct nk_color); -NK_API void nk_value_color_float(struct nk_context*, const char *prefix, struct nk_color); -NK_API void nk_value_color_hex(struct nk_context*, const char *prefix, struct nk_color); -#endif -/* ============================================================================= - * - * BUTTON - * - * ============================================================================= */ -NK_API int nk_button_text(struct nk_context*, const char *title, int len); -NK_API int nk_button_label(struct nk_context*, const char *title); -NK_API int nk_button_color(struct nk_context*, struct nk_color); -NK_API int nk_button_symbol(struct nk_context*, enum nk_symbol_type); -NK_API int nk_button_image(struct nk_context*, struct nk_image img); -NK_API int nk_button_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags text_alignment); -NK_API int nk_button_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API int nk_button_image_label(struct nk_context*, struct nk_image img, const char*, nk_flags text_alignment); -NK_API int nk_button_image_text(struct nk_context*, struct nk_image img, const char*, int, nk_flags alignment); -NK_API int nk_button_text_styled(struct nk_context*, const struct nk_style_button*, const char *title, int len); -NK_API int nk_button_label_styled(struct nk_context*, const struct nk_style_button*, const char *title); -NK_API int nk_button_symbol_styled(struct nk_context*, const struct nk_style_button*, enum nk_symbol_type); -NK_API int nk_button_image_styled(struct nk_context*, const struct nk_style_button*, struct nk_image img); -NK_API int nk_button_symbol_text_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API int nk_button_symbol_label_styled(struct nk_context *ctx, const struct nk_style_button *style, enum nk_symbol_type symbol, const char *title, nk_flags align); -NK_API int nk_button_image_label_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, nk_flags text_alignment); -NK_API int nk_button_image_text_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, int, nk_flags alignment); -NK_API void nk_button_set_behavior(struct nk_context*, enum nk_button_behavior); -NK_API int nk_button_push_behavior(struct nk_context*, enum nk_button_behavior); -NK_API int nk_button_pop_behavior(struct nk_context*); -/* ============================================================================= - * - * CHECKBOX - * - * ============================================================================= */ -NK_API int nk_check_label(struct nk_context*, const char*, int active); -NK_API int nk_check_text(struct nk_context*, const char*, int,int active); -NK_API unsigned nk_check_flags_label(struct nk_context*, const char*, unsigned int flags, unsigned int value); -NK_API unsigned nk_check_flags_text(struct nk_context*, const char*, int, unsigned int flags, unsigned int value); -NK_API int nk_checkbox_label(struct nk_context*, const char*, int *active); -NK_API int nk_checkbox_text(struct nk_context*, const char*, int, int *active); -NK_API int nk_checkbox_flags_label(struct nk_context*, const char*, unsigned int *flags, unsigned int value); -NK_API int nk_checkbox_flags_text(struct nk_context*, const char*, int, unsigned int *flags, unsigned int value); -/* ============================================================================= - * - * RADIO BUTTON - * - * ============================================================================= */ -NK_API int nk_radio_label(struct nk_context*, const char*, int *active); -NK_API int nk_radio_text(struct nk_context*, const char*, int, int *active); -NK_API int nk_option_label(struct nk_context*, const char*, int active); -NK_API int nk_option_text(struct nk_context*, const char*, int, int active); -/* ============================================================================= - * - * SELECTABLE - * - * ============================================================================= */ -NK_API int nk_selectable_label(struct nk_context*, const char*, nk_flags align, int *value); -NK_API int nk_selectable_text(struct nk_context*, const char*, int, nk_flags align, int *value); -NK_API int nk_selectable_image_label(struct nk_context*,struct nk_image, const char*, nk_flags align, int *value); -NK_API int nk_selectable_image_text(struct nk_context*,struct nk_image, const char*, int, nk_flags align, int *value); -NK_API int nk_select_label(struct nk_context*, const char*, nk_flags align, int value); -NK_API int nk_select_text(struct nk_context*, const char*, int, nk_flags align, int value); -NK_API int nk_select_image_label(struct nk_context*, struct nk_image,const char*, nk_flags align, int value); -NK_API int nk_select_image_text(struct nk_context*, struct nk_image,const char*, int, nk_flags align, int value); -/* ============================================================================= - * - * SLIDER - * - * ============================================================================= */ -NK_API float nk_slide_float(struct nk_context*, float min, float val, float max, float step); -NK_API int nk_slide_int(struct nk_context*, int min, int val, int max, int step); -NK_API int nk_slider_float(struct nk_context*, float min, float *val, float max, float step); -NK_API int nk_slider_int(struct nk_context*, int min, int *val, int max, int step); -/* ============================================================================= - * - * PROGRESSBAR - * - * ============================================================================= */ -NK_API int nk_progress(struct nk_context*, nk_size *cur, nk_size max, int modifyable); -NK_API nk_size nk_prog(struct nk_context*, nk_size cur, nk_size max, int modifyable); - -/* ============================================================================= - * - * COLOR PICKER - * - * ============================================================================= */ -NK_API struct nk_color nk_color_picker(struct nk_context*, struct nk_color, enum nk_color_format); -NK_API int nk_color_pick(struct nk_context*, struct nk_color*, enum nk_color_format); -/* ============================================================================= - * - * PROPERTIES - * - * ============================================================================= */ -NK_API void nk_property_int(struct nk_context*, const char *name, int min, int *val, int max, int step, float inc_per_pixel); -NK_API void nk_property_float(struct nk_context*, const char *name, float min, float *val, float max, float step, float inc_per_pixel); -NK_API void nk_property_double(struct nk_context*, const char *name, double min, double *val, double max, double step, float inc_per_pixel); -NK_API int nk_propertyi(struct nk_context*, const char *name, int min, int val, int max, int step, float inc_per_pixel); -NK_API float nk_propertyf(struct nk_context*, const char *name, float min, float val, float max, float step, float inc_per_pixel); -NK_API double nk_propertyd(struct nk_context*, const char *name, double min, double val, double max, double step, float inc_per_pixel); -/* ============================================================================= - * - * TEXT EDIT - * - * ============================================================================= */ -enum nk_edit_flags { - NK_EDIT_DEFAULT = 0, - NK_EDIT_READ_ONLY = NK_FLAG(0), - NK_EDIT_AUTO_SELECT = NK_FLAG(1), - NK_EDIT_SIG_ENTER = NK_FLAG(2), - NK_EDIT_ALLOW_TAB = NK_FLAG(3), - NK_EDIT_NO_CURSOR = NK_FLAG(4), - NK_EDIT_SELECTABLE = NK_FLAG(5), - NK_EDIT_CLIPBOARD = NK_FLAG(6), - NK_EDIT_CTRL_ENTER_NEWLINE = NK_FLAG(7), - NK_EDIT_NO_HORIZONTAL_SCROLL = NK_FLAG(8), - NK_EDIT_ALWAYS_INSERT_MODE = NK_FLAG(9), - NK_EDIT_MULTILINE = NK_FLAG(10), - NK_EDIT_GOTO_END_ON_ACTIVATE = NK_FLAG(11) -}; -enum nk_edit_types { - NK_EDIT_SIMPLE = NK_EDIT_ALWAYS_INSERT_MODE, - NK_EDIT_FIELD = NK_EDIT_SIMPLE|NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD, - NK_EDIT_BOX = NK_EDIT_ALWAYS_INSERT_MODE| NK_EDIT_SELECTABLE| NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB|NK_EDIT_CLIPBOARD, - NK_EDIT_EDITOR = NK_EDIT_SELECTABLE|NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB| NK_EDIT_CLIPBOARD -}; -enum nk_edit_events { - NK_EDIT_ACTIVE = NK_FLAG(0), /* edit widget is currently being modified */ - NK_EDIT_INACTIVE = NK_FLAG(1), /* edit widget is not active and is not being modified */ - NK_EDIT_ACTIVATED = NK_FLAG(2), /* edit widget went from state inactive to state active */ - NK_EDIT_DEACTIVATED = NK_FLAG(3), /* edit widget went from state active to state inactive */ - NK_EDIT_COMMITED = NK_FLAG(4) /* edit widget has received an enter and lost focus */ -}; -NK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter); -NK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter); -NK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter); -NK_API void nk_edit_focus(struct nk_context*, nk_flags flags); -NK_API void nk_edit_unfocus(struct nk_context*); -/* ============================================================================= - * - * CHART - * - * ============================================================================= */ -NK_API int nk_chart_begin(struct nk_context*, enum nk_chart_type, int num, float min, float max); -NK_API int nk_chart_begin_colored(struct nk_context*, enum nk_chart_type, struct nk_color, struct nk_color active, int num, float min, float max); -NK_API void nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type, int count, float min_value, float max_value); -NK_API void nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type, struct nk_color, struct nk_color active, int count, float min_value, float max_value); -NK_API nk_flags nk_chart_push(struct nk_context*, float); -NK_API nk_flags nk_chart_push_slot(struct nk_context*, float, int); -NK_API void nk_chart_end(struct nk_context*); -NK_API void nk_plot(struct nk_context*, enum nk_chart_type, const float *values, int count, int offset); -NK_API void nk_plot_function(struct nk_context*, enum nk_chart_type, void *userdata, float(*value_getter)(void* user, int index), int count, int offset); -/* ============================================================================= - * - * POPUP - * - * ============================================================================= */ -NK_API int nk_popup_begin(struct nk_context*, enum nk_popup_type, const char*, nk_flags, struct nk_rect bounds); -NK_API void nk_popup_close(struct nk_context*); -NK_API void nk_popup_end(struct nk_context*); -/* ============================================================================= - * - * COMBOBOX - * - * ============================================================================= */ -NK_API int nk_combo(struct nk_context*, const char **items, int count, int selected, int item_height, struct nk_vec2 size); -NK_API int nk_combo_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int selected, int count, int item_height, struct nk_vec2 size); -NK_API int nk_combo_string(struct nk_context*, const char *items_separated_by_zeros, int selected, int count, int item_height, struct nk_vec2 size); -NK_API int nk_combo_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void *userdata, int selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox(struct nk_context*, const char **items, int count, int *selected, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_string(struct nk_context*, const char *items_separated_by_zeros, int *selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_separator(struct nk_context*, const char *items_separated_by_separator, int separator,int *selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void*, int *selected, int count, int item_height, struct nk_vec2 size); -/* ============================================================================= - * - * ABSTRACT COMBOBOX - * - * ============================================================================= */ -NK_API int nk_combo_begin_text(struct nk_context*, const char *selected, int, struct nk_vec2 size); -NK_API int nk_combo_begin_label(struct nk_context*, const char *selected, struct nk_vec2 size); -NK_API int nk_combo_begin_color(struct nk_context*, struct nk_color color, struct nk_vec2 size); -NK_API int nk_combo_begin_symbol(struct nk_context*, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_combo_begin_symbol_label(struct nk_context*, const char *selected, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_combo_begin_symbol_text(struct nk_context*, const char *selected, int, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_combo_begin_image(struct nk_context*, struct nk_image img, struct nk_vec2 size); -NK_API int nk_combo_begin_image_label(struct nk_context*, const char *selected, struct nk_image, struct nk_vec2 size); -NK_API int nk_combo_begin_image_text(struct nk_context*, const char *selected, int, struct nk_image, struct nk_vec2 size); -NK_API int nk_combo_item_label(struct nk_context*, const char*, nk_flags alignment); -NK_API int nk_combo_item_text(struct nk_context*, const char*,int, nk_flags alignment); -NK_API int nk_combo_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API int nk_combo_item_image_text(struct nk_context*, struct nk_image, const char*, int,nk_flags alignment); -NK_API int nk_combo_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API int nk_combo_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API void nk_combo_close(struct nk_context*); -NK_API void nk_combo_end(struct nk_context*); -/* ============================================================================= - * - * CONTEXTUAL - * - * ============================================================================= */ -NK_API int nk_contextual_begin(struct nk_context*, nk_flags, struct nk_vec2, struct nk_rect trigger_bounds); -NK_API int nk_contextual_item_text(struct nk_context*, const char*, int,nk_flags align); -NK_API int nk_contextual_item_label(struct nk_context*, const char*, nk_flags align); -NK_API int nk_contextual_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API int nk_contextual_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); -NK_API int nk_contextual_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API int nk_contextual_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API void nk_contextual_close(struct nk_context*); -NK_API void nk_contextual_end(struct nk_context*); -/* ============================================================================= - * - * TOOLTIP - * - * ============================================================================= */ -NK_API void nk_tooltip(struct nk_context*, const char*); -NK_API int nk_tooltip_begin(struct nk_context*, float width); -NK_API void nk_tooltip_end(struct nk_context*); -/* ============================================================================= - * - * MENU - * - * ============================================================================= */ -NK_API void nk_menubar_begin(struct nk_context*); -NK_API void nk_menubar_end(struct nk_context*); -NK_API int nk_menu_begin_text(struct nk_context*, const char* title, int title_len, nk_flags align, struct nk_vec2 size); -NK_API int nk_menu_begin_label(struct nk_context*, const char*, nk_flags align, struct nk_vec2 size); -NK_API int nk_menu_begin_image(struct nk_context*, const char*, struct nk_image, struct nk_vec2 size); -NK_API int nk_menu_begin_image_text(struct nk_context*, const char*, int,nk_flags align,struct nk_image, struct nk_vec2 size); -NK_API int nk_menu_begin_image_label(struct nk_context*, const char*, nk_flags align,struct nk_image, struct nk_vec2 size); -NK_API int nk_menu_begin_symbol(struct nk_context*, const char*, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_menu_begin_symbol_text(struct nk_context*, const char*, int,nk_flags align,enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_menu_begin_symbol_label(struct nk_context*, const char*, nk_flags align,enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_menu_item_text(struct nk_context*, const char*, int,nk_flags align); -NK_API int nk_menu_item_label(struct nk_context*, const char*, nk_flags alignment); -NK_API int nk_menu_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API int nk_menu_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); -NK_API int nk_menu_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API int nk_menu_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API void nk_menu_close(struct nk_context*); -NK_API void nk_menu_end(struct nk_context*); -/* ============================================================================= - * - * STYLE - * - * ============================================================================= */ -enum nk_style_colors { - NK_COLOR_TEXT, - NK_COLOR_WINDOW, - NK_COLOR_HEADER, - NK_COLOR_BORDER, - NK_COLOR_BUTTON, - NK_COLOR_BUTTON_HOVER, - NK_COLOR_BUTTON_ACTIVE, - NK_COLOR_TOGGLE, - NK_COLOR_TOGGLE_HOVER, - NK_COLOR_TOGGLE_CURSOR, - NK_COLOR_SELECT, - NK_COLOR_SELECT_ACTIVE, - NK_COLOR_SLIDER, - NK_COLOR_SLIDER_CURSOR, - NK_COLOR_SLIDER_CURSOR_HOVER, - NK_COLOR_SLIDER_CURSOR_ACTIVE, - NK_COLOR_PROPERTY, - NK_COLOR_EDIT, - NK_COLOR_EDIT_CURSOR, - NK_COLOR_COMBO, - NK_COLOR_CHART, - NK_COLOR_CHART_COLOR, - NK_COLOR_CHART_COLOR_HIGHLIGHT, - NK_COLOR_SCROLLBAR, - NK_COLOR_SCROLLBAR_CURSOR, - NK_COLOR_SCROLLBAR_CURSOR_HOVER, - NK_COLOR_SCROLLBAR_CURSOR_ACTIVE, - NK_COLOR_TAB_HEADER, - NK_COLOR_COUNT -}; -enum nk_style_cursor { - NK_CURSOR_ARROW, - NK_CURSOR_TEXT, - NK_CURSOR_MOVE, - NK_CURSOR_RESIZE_VERTICAL, - NK_CURSOR_RESIZE_HORIZONTAL, - NK_CURSOR_RESIZE_TOP_LEFT_DOWN_RIGHT, - NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT, - NK_CURSOR_COUNT -}; -NK_API void nk_style_default(struct nk_context*); -NK_API void nk_style_from_table(struct nk_context*, const struct nk_color*); -NK_API void nk_style_load_cursor(struct nk_context*, enum nk_style_cursor, const struct nk_cursor*); -NK_API void nk_style_load_all_cursors(struct nk_context*, struct nk_cursor*); -NK_API const char* nk_style_get_color_by_name(enum nk_style_colors); -NK_API void nk_style_set_font(struct nk_context*, const struct nk_user_font*); -NK_API int nk_style_set_cursor(struct nk_context*, enum nk_style_cursor); -NK_API void nk_style_show_cursor(struct nk_context*); -NK_API void nk_style_hide_cursor(struct nk_context*); - -NK_API int nk_style_push_font(struct nk_context*, const struct nk_user_font*); -NK_API int nk_style_push_float(struct nk_context*, float*, float); -NK_API int nk_style_push_vec2(struct nk_context*, struct nk_vec2*, struct nk_vec2); -NK_API int nk_style_push_style_item(struct nk_context*, struct nk_style_item*, struct nk_style_item); -NK_API int nk_style_push_flags(struct nk_context*, nk_flags*, nk_flags); -NK_API int nk_style_push_color(struct nk_context*, struct nk_color*, struct nk_color); - -NK_API int nk_style_pop_font(struct nk_context*); -NK_API int nk_style_pop_float(struct nk_context*); -NK_API int nk_style_pop_vec2(struct nk_context*); -NK_API int nk_style_pop_style_item(struct nk_context*); -NK_API int nk_style_pop_flags(struct nk_context*); -NK_API int nk_style_pop_color(struct nk_context*); -/* ============================================================================= - * - * COLOR - * - * ============================================================================= */ -NK_API struct nk_color nk_rgb(int r, int g, int b); -NK_API struct nk_color nk_rgb_iv(const int *rgb); -NK_API struct nk_color nk_rgb_bv(const nk_byte* rgb); -NK_API struct nk_color nk_rgb_f(float r, float g, float b); -NK_API struct nk_color nk_rgb_fv(const float *rgb); -NK_API struct nk_color nk_rgb_hex(const char *rgb); - -NK_API struct nk_color nk_rgba(int r, int g, int b, int a); -NK_API struct nk_color nk_rgba_u32(nk_uint); -NK_API struct nk_color nk_rgba_iv(const int *rgba); -NK_API struct nk_color nk_rgba_bv(const nk_byte *rgba); -NK_API struct nk_color nk_rgba_f(float r, float g, float b, float a); -NK_API struct nk_color nk_rgba_fv(const float *rgba); -NK_API struct nk_color nk_rgba_hex(const char *rgb); - -NK_API struct nk_color nk_hsv(int h, int s, int v); -NK_API struct nk_color nk_hsv_iv(const int *hsv); -NK_API struct nk_color nk_hsv_bv(const nk_byte *hsv); -NK_API struct nk_color nk_hsv_f(float h, float s, float v); -NK_API struct nk_color nk_hsv_fv(const float *hsv); - -NK_API struct nk_color nk_hsva(int h, int s, int v, int a); -NK_API struct nk_color nk_hsva_iv(const int *hsva); -NK_API struct nk_color nk_hsva_bv(const nk_byte *hsva); -NK_API struct nk_color nk_hsva_f(float h, float s, float v, float a); -NK_API struct nk_color nk_hsva_fv(const float *hsva); - -/* color (conversion nuklear --> user) */ -NK_API void nk_color_f(float *r, float *g, float *b, float *a, struct nk_color); -NK_API void nk_color_fv(float *rgba_out, struct nk_color); -NK_API void nk_color_d(double *r, double *g, double *b, double *a, struct nk_color); -NK_API void nk_color_dv(double *rgba_out, struct nk_color); - -NK_API nk_uint nk_color_u32(struct nk_color); -NK_API void nk_color_hex_rgba(char *output, struct nk_color); -NK_API void nk_color_hex_rgb(char *output, struct nk_color); - -NK_API void nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color); -NK_API void nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color); -NK_API void nk_color_hsv_iv(int *hsv_out, struct nk_color); -NK_API void nk_color_hsv_bv(nk_byte *hsv_out, struct nk_color); -NK_API void nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color); -NK_API void nk_color_hsv_fv(float *hsv_out, struct nk_color); - -NK_API void nk_color_hsva_i(int *h, int *s, int *v, int *a, struct nk_color); -NK_API void nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color); -NK_API void nk_color_hsva_iv(int *hsva_out, struct nk_color); -NK_API void nk_color_hsva_bv(nk_byte *hsva_out, struct nk_color); -NK_API void nk_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_color); -NK_API void nk_color_hsva_fv(float *hsva_out, struct nk_color); -/* ============================================================================= - * - * IMAGE - * - * ============================================================================= */ -NK_API nk_handle nk_handle_ptr(void*); -NK_API nk_handle nk_handle_id(int); -NK_API struct nk_image nk_image_handle(nk_handle); -NK_API struct nk_image nk_image_ptr(void*); -NK_API struct nk_image nk_image_id(int); -NK_API int nk_image_is_subimage(const struct nk_image* img); -NK_API struct nk_image nk_subimage_ptr(void*, unsigned short w, unsigned short h, struct nk_rect sub_region); -NK_API struct nk_image nk_subimage_id(int, unsigned short w, unsigned short h, struct nk_rect sub_region); -NK_API struct nk_image nk_subimage_handle(nk_handle, unsigned short w, unsigned short h, struct nk_rect sub_region); -/* ============================================================================= - * - * MATH - * - * ============================================================================= */ -NK_API nk_hash nk_murmur_hash(const void *key, int len, nk_hash seed); -NK_API void nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, float pad_x, float pad_y, enum nk_heading); - -NK_API struct nk_vec2 nk_vec2(float x, float y); -NK_API struct nk_vec2 nk_vec2i(int x, int y); -NK_API struct nk_vec2 nk_vec2v(const float *xy); -NK_API struct nk_vec2 nk_vec2iv(const int *xy); - -NK_API struct nk_rect nk_get_null_rect(void); -NK_API struct nk_rect nk_rect(float x, float y, float w, float h); -NK_API struct nk_rect nk_recti(int x, int y, int w, int h); -NK_API struct nk_rect nk_recta(struct nk_vec2 pos, struct nk_vec2 size); -NK_API struct nk_rect nk_rectv(const float *xywh); -NK_API struct nk_rect nk_rectiv(const int *xywh); -NK_API struct nk_vec2 nk_rect_pos(struct nk_rect); -NK_API struct nk_vec2 nk_rect_size(struct nk_rect); -/* ============================================================================= - * - * STRING - * - * ============================================================================= */ -NK_API int nk_strlen(const char *str); -NK_API int nk_stricmp(const char *s1, const char *s2); -NK_API int nk_stricmpn(const char *s1, const char *s2, int n); -NK_API int nk_strtoi(const char *str, const char **endptr); -NK_API float nk_strtof(const char *str, const char **endptr); -NK_API double nk_strtod(const char *str, const char **endptr); -NK_API int nk_strfilter(const char *text, const char *regexp); -NK_API int nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score); -NK_API int nk_strmatch_fuzzy_text(const char *txt, int txt_len, const char *pattern, int *out_score); -/* ============================================================================= - * - * UTF-8 - * - * ============================================================================= */ -NK_API int nk_utf_decode(const char*, nk_rune*, int); -NK_API int nk_utf_encode(nk_rune, char*, int); -NK_API int nk_utf_len(const char*, int byte_len); -NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune *unicode, int *len); -/* =============================================================== - * - * FONT - * - * ===============================================================*/ -/* Font handling in this library was designed to be quite customizable and lets - you decide what you want to use and what you want to provide. There are three - different ways to use the font atlas. The first two will use your font - handling scheme and only requires essential data to run nuklear. The next - slightly more advanced features is font handling with vertex buffer output. - Finally the most complex API wise is using nuklears font baking API. - - 1.) Using your own implementation without vertex buffer output - -------------------------------------------------------------- - So first up the easiest way to do font handling is by just providing a - `nk_user_font` struct which only requires the height in pixel of the used - font and a callback to calculate the width of a string. This way of handling - fonts is best fitted for using the normal draw shape command API where you - do all the text drawing yourself and the library does not require any kind - of deeper knowledge about which font handling mechanism you use. - IMPORTANT: the `nk_user_font` pointer provided to nuklear has to persist - over the complete life time! I know this sucks but it is currently the only - way to switch between fonts. - - float your_text_width_calculation(nk_handle handle, float height, const char *text, int len) - { - your_font_type *type = handle.ptr; - float text_width = ...; - return text_width; - } - - struct nk_user_font font; - font.userdata.ptr = &your_font_class_or_struct; - font.height = your_font_height; - font.width = your_text_width_calculation; - - struct nk_context ctx; - nk_init_default(&ctx, &font); - - 2.) Using your own implementation with vertex buffer output - -------------------------------------------------------------- - While the first approach works fine if you don't want to use the optional - vertex buffer output it is not enough if you do. To get font handling working - for these cases you have to provide two additional parameters inside the - `nk_user_font`. First a texture atlas handle used to draw text as subimages - of a bigger font atlas texture and a callback to query a character's glyph - information (offset, size, ...). So it is still possible to provide your own - font and use the vertex buffer output. - - float your_text_width_calculation(nk_handle handle, float height, const char *text, int len) - { - your_font_type *type = handle.ptr; - float text_width = ...; - return text_width; - } - void query_your_font_glyph(nk_handle handle, float font_height, struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint) - { - your_font_type *type = handle.ptr; - glyph.width = ...; - glyph.height = ...; - glyph.xadvance = ...; - glyph.uv[0].x = ...; - glyph.uv[0].y = ...; - glyph.uv[1].x = ...; - glyph.uv[1].y = ...; - glyph.offset.x = ...; - glyph.offset.y = ...; - } - - struct nk_user_font font; - font.userdata.ptr = &your_font_class_or_struct; - font.height = your_font_height; - font.width = your_text_width_calculation; - font.query = query_your_font_glyph; - font.texture.id = your_font_texture; - - struct nk_context ctx; - nk_init_default(&ctx, &font); - - 3.) Nuklear font baker - ------------------------------------ - The final approach if you do not have a font handling functionality or don't - want to use it in this library is by using the optional font baker. - The font baker API's can be used to create a font plus font atlas texture - and can be used with or without the vertex buffer output. - - It still uses the `nk_user_font` struct and the two different approaches - previously stated still work. The font baker is not located inside - `nk_context` like all other systems since it can be understood as more of - an extension to nuklear and does not really depend on any `nk_context` state. - - Font baker need to be initialized first by one of the nk_font_atlas_init_xxx - functions. If you don't care about memory just call the default version - `nk_font_atlas_init_default` which will allocate all memory from the standard library. - If you want to control memory allocation but you don't care if the allocated - memory is temporary and therefore can be freed directly after the baking process - is over or permanent you can call `nk_font_atlas_init`. - - After successfull intializing the font baker you can add Truetype(.ttf) fonts from - different sources like memory or from file by calling one of the `nk_font_atlas_add_xxx`. - functions. Adding font will permanently store each font, font config and ttf memory block(!) - inside the font atlas and allows to reuse the font atlas. If you don't want to reuse - the font baker by for example adding additional fonts you can call - `nk_font_atlas_cleanup` after the baking process is over (after calling nk_font_atlas_end). - - As soon as you added all fonts you wanted you can now start the baking process - for every selected glyphes to image by calling `nk_font_atlas_bake`. - The baking process returns image memory, width and height which can be used to - either create your own image object or upload it to any graphics library. - No matter which case you finally have to call `nk_font_atlas_end` which - will free all temporary memory including the font atlas image so make sure - you created our texture beforehand. `nk_font_atlas_end` requires a handle - to your font texture or object and optionally fills a `struct nk_draw_null_texture` - which can be used for the optional vertex output. If you don't want it just - set the argument to `NULL`. - - At this point you are done and if you don't want to reuse the font atlas you - can call `nk_font_atlas_cleanup` to free all truetype blobs and configuration - memory. Finally if you don't use the font atlas and any of it's fonts anymore - you need to call `nk_font_atlas_clear` to free all memory still being used. - - struct nk_font_atlas atlas; - nk_font_atlas_init_default(&atlas); - nk_font_atlas_begin(&atlas); - nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, 0); - nk_font *font2 = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font2.ttf", 16, 0); - const void* img = nk_font_atlas_bake(&atlas, &img_width, &img_height, NK_FONT_ATLAS_RGBA32); - nk_font_atlas_end(&atlas, nk_handle_id(texture), 0); - - struct nk_context ctx; - nk_init_default(&ctx, &font->handle); - while (1) { - - } - nk_font_atlas_clear(&atlas); - - The font baker API is probably the most complex API inside this library and - I would suggest reading some of my examples `example/` to get a grip on how - to use the font atlas. There are a number of details I left out. For example - how to merge fonts, configure a font with `nk_font_config` to use other languages, - use another texture coodinate format and a lot more: - - struct nk_font_config cfg = nk_font_config(font_pixel_height); - cfg.merge_mode = nk_false or nk_true; - cfg.range = nk_font_korean_glyph_ranges(); - cfg.coord_type = NK_COORD_PIXEL; - nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, &cfg); - -*/ -struct nk_user_font_glyph; -typedef float(*nk_text_width_f)(nk_handle, float h, const char*, int len); -typedef void(*nk_query_font_glyph_f)(nk_handle handle, float font_height, - struct nk_user_font_glyph *glyph, - nk_rune codepoint, nk_rune next_codepoint); - -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -struct nk_user_font_glyph { - struct nk_vec2 uv[2]; - /* texture coordinates */ - struct nk_vec2 offset; - /* offset between top left and glyph */ - float width, height; - /* size of the glyph */ - float xadvance; - /* offset to the next glyph */ -}; -#endif - -struct nk_user_font { - nk_handle userdata; - /* user provided font handle */ - float height; - /* max height of the font */ - nk_text_width_f width; - /* font string width in pixel callback */ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - nk_query_font_glyph_f query; - /* font glyph callback to query drawing info */ - nk_handle texture; - /* texture handle to the used font atlas or texture */ -#endif -}; - -#ifdef NK_INCLUDE_FONT_BAKING -enum nk_font_coord_type { - NK_COORD_UV, /* texture coordinates inside font glyphs are clamped between 0-1 */ - NK_COORD_PIXEL /* texture coordinates inside font glyphs are in absolute pixel */ -}; - -struct nk_baked_font { - float height; - /* height of the font */ - float ascent, descent; - /* font glyphs ascent and descent */ - nk_rune glyph_offset; - /* glyph array offset inside the font glyph baking output array */ - nk_rune glyph_count; - /* number of glyphs of this font inside the glyph baking array output */ - const nk_rune *ranges; - /* font codepoint ranges as pairs of (from/to) and 0 as last element */ -}; - -struct nk_font_config { - struct nk_font_config *next; - /* NOTE: only used internally */ - void *ttf_blob; - /* pointer to loaded TTF file memory block. - * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */ - nk_size ttf_size; - /* size of the loaded TTF file memory block - * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */ - - unsigned char ttf_data_owned_by_atlas; - /* used inside font atlas: default to: 0*/ - unsigned char merge_mode; - /* merges this font into the last font */ - unsigned char pixel_snap; - /* align every character to pixel boundary (if true set oversample (1,1)) */ - unsigned char oversample_v, oversample_h; - /* rasterize at hight quality for sub-pixel position */ - unsigned char padding[3]; - - float size; - /* baked pixel height of the font */ - enum nk_font_coord_type coord_type; - /* texture coordinate format with either pixel or UV coordinates */ - struct nk_vec2 spacing; - /* extra pixel spacing between glyphs */ - const nk_rune *range; - /* list of unicode ranges (2 values per range, zero terminated) */ - struct nk_baked_font *font; - /* font to setup in the baking process: NOTE: not needed for font atlas */ - nk_rune fallback_glyph; - /* fallback glyph to use if a given rune is not found */ -}; - -struct nk_font_glyph { - nk_rune codepoint; - float xadvance; - float x0, y0, x1, y1, w, h; - float u0, v0, u1, v1; -}; - -struct nk_font { - struct nk_font *next; - struct nk_user_font handle; - struct nk_baked_font info; - float scale; - struct nk_font_glyph *glyphs; - const struct nk_font_glyph *fallback; - nk_rune fallback_codepoint; - nk_handle texture; - struct nk_font_config *config; -}; - -enum nk_font_atlas_format { - NK_FONT_ATLAS_ALPHA8, - NK_FONT_ATLAS_RGBA32 -}; - -struct nk_font_atlas { - void *pixel; - int tex_width; - int tex_height; - - struct nk_allocator permanent; - struct nk_allocator temporary; - - struct nk_recti custom; - struct nk_cursor cursors[NK_CURSOR_COUNT]; - - int glyph_count; - struct nk_font_glyph *glyphs; - struct nk_font *default_font; - struct nk_font *fonts; - struct nk_font_config *config; - int font_num; -}; - -/* some language glyph codepoint ranges */ -NK_API const nk_rune *nk_font_default_glyph_ranges(void); -NK_API const nk_rune *nk_font_chinese_glyph_ranges(void); -NK_API const nk_rune *nk_font_cyrillic_glyph_ranges(void); -NK_API const nk_rune *nk_font_korean_glyph_ranges(void); - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_font_atlas_init_default(struct nk_font_atlas*); -#endif -NK_API void nk_font_atlas_init(struct nk_font_atlas*, struct nk_allocator*); -NK_API void nk_font_atlas_init_custom(struct nk_font_atlas*, struct nk_allocator *persistent, struct nk_allocator *transient); -NK_API void nk_font_atlas_begin(struct nk_font_atlas*); -NK_API struct nk_font_config nk_font_config(float pixel_height); -NK_API struct nk_font *nk_font_atlas_add(struct nk_font_atlas*, const struct nk_font_config*); -#ifdef NK_INCLUDE_DEFAULT_FONT -NK_API struct nk_font* nk_font_atlas_add_default(struct nk_font_atlas*, float height, const struct nk_font_config*); -#endif -NK_API struct nk_font* nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, nk_size size, float height, const struct nk_font_config *config); -#ifdef NK_INCLUDE_STANDARD_IO -NK_API struct nk_font* nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, float height, const struct nk_font_config*); -#endif -NK_API struct nk_font *nk_font_atlas_add_compressed(struct nk_font_atlas*, void *memory, nk_size size, float height, const struct nk_font_config*); -NK_API struct nk_font* nk_font_atlas_add_compressed_base85(struct nk_font_atlas*, const char *data, float height, const struct nk_font_config *config); -NK_API const void* nk_font_atlas_bake(struct nk_font_atlas*, int *width, int *height, enum nk_font_atlas_format); -NK_API void nk_font_atlas_end(struct nk_font_atlas*, nk_handle tex, struct nk_draw_null_texture*); -NK_API const struct nk_font_glyph* nk_font_find_glyph(struct nk_font*, nk_rune unicode); -NK_API void nk_font_atlas_cleanup(struct nk_font_atlas *atlas); -NK_API void nk_font_atlas_clear(struct nk_font_atlas*); - -#endif - -/* ============================================================== - * - * MEMORY BUFFER - * - * ===============================================================*/ -/* A basic (double)-buffer with linear allocation and resetting as only - freeing policy. The buffer's main purpose is to control all memory management - inside the GUI toolkit and still leave memory control as much as possible in - the hand of the user while also making sure the library is easy to use if - not as much control is needed. - In general all memory inside this library can be provided from the user in - three different ways. - - The first way and the one providing most control is by just passing a fixed - size memory block. In this case all control lies in the hand of the user - since he can exactly control where the memory comes from and how much memory - the library should consume. Of course using the fixed size API removes the - ability to automatically resize a buffer if not enough memory is provided so - you have to take over the resizing. While being a fixed sized buffer sounds - quite limiting, it is very effective in this library since the actual memory - consumption is quite stable and has a fixed upper bound for a lot of cases. - - If you don't want to think about how much memory the library should allocate - at all time or have a very dynamic UI with unpredictable memory consumption - habits but still want control over memory allocation you can use the dynamic - allocator based API. The allocator consists of two callbacks for allocating - and freeing memory and optional userdata so you can plugin your own allocator. - - The final and easiest way can be used by defining - NK_INCLUDE_DEFAULT_ALLOCATOR which uses the standard library memory - allocation functions malloc and free and takes over complete control over - memory in this library. -*/ -struct nk_memory_status { - void *memory; - unsigned int type; - nk_size size; - nk_size allocated; - nk_size needed; - nk_size calls; -}; - -enum nk_allocation_type { - NK_BUFFER_FIXED, - NK_BUFFER_DYNAMIC -}; - -enum nk_buffer_allocation_type { - NK_BUFFER_FRONT, - NK_BUFFER_BACK, - NK_BUFFER_MAX -}; - -struct nk_buffer_marker { - int active; - nk_size offset; -}; - -struct nk_memory {void *ptr;nk_size size;}; -struct nk_buffer { - struct nk_buffer_marker marker[NK_BUFFER_MAX]; - /* buffer marker to free a buffer to a certain offset */ - struct nk_allocator pool; - /* allocator callback for dynamic buffers */ - enum nk_allocation_type type; - /* memory management type */ - struct nk_memory memory; - /* memory and size of the current memory block */ - float grow_factor; - /* growing factor for dynamic memory management */ - nk_size allocated; - /* total amount of memory allocated */ - nk_size needed; - /* totally consumed memory given that enough memory is present */ - nk_size calls; - /* number of allocation calls */ - nk_size size; - /* current size of the buffer */ -}; - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_buffer_init_default(struct nk_buffer*); -#endif -NK_API void nk_buffer_init(struct nk_buffer*, const struct nk_allocator*, nk_size size); -NK_API void nk_buffer_init_fixed(struct nk_buffer*, void *memory, nk_size size); -NK_API void nk_buffer_info(struct nk_memory_status*, struct nk_buffer*); -NK_API void nk_buffer_push(struct nk_buffer*, enum nk_buffer_allocation_type type, const void *memory, nk_size size, nk_size align); -NK_API void nk_buffer_mark(struct nk_buffer*, enum nk_buffer_allocation_type type); -NK_API void nk_buffer_reset(struct nk_buffer*, enum nk_buffer_allocation_type type); -NK_API void nk_buffer_clear(struct nk_buffer*); -NK_API void nk_buffer_free(struct nk_buffer*); -NK_API void *nk_buffer_memory(struct nk_buffer*); -NK_API const void *nk_buffer_memory_const(const struct nk_buffer*); -NK_API nk_size nk_buffer_total(struct nk_buffer*); - -/* ============================================================== - * - * STRING - * - * ===============================================================*/ -/* Basic string buffer which is only used in context with the text editor - * to manage and manipulate dynamic or fixed size string content. This is _NOT_ - * the default string handling method. The only instance you should have any contact - * with this API is if you interact with an `nk_text_edit` object inside one of the - * copy and paste functions and even there only for more advanced cases. */ -struct nk_str { - struct nk_buffer buffer; - int len; /* in codepoints/runes/glyphs */ -}; - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_str_init_default(struct nk_str*); -#endif -NK_API void nk_str_init(struct nk_str*, const struct nk_allocator*, nk_size size); -NK_API void nk_str_init_fixed(struct nk_str*, void *memory, nk_size size); -NK_API void nk_str_clear(struct nk_str*); -NK_API void nk_str_free(struct nk_str*); - -NK_API int nk_str_append_text_char(struct nk_str*, const char*, int); -NK_API int nk_str_append_str_char(struct nk_str*, const char*); -NK_API int nk_str_append_text_utf8(struct nk_str*, const char*, int); -NK_API int nk_str_append_str_utf8(struct nk_str*, const char*); -NK_API int nk_str_append_text_runes(struct nk_str*, const nk_rune*, int); -NK_API int nk_str_append_str_runes(struct nk_str*, const nk_rune*); - -NK_API int nk_str_insert_at_char(struct nk_str*, int pos, const char*, int); -NK_API int nk_str_insert_at_rune(struct nk_str*, int pos, const char*, int); - -NK_API int nk_str_insert_text_char(struct nk_str*, int pos, const char*, int); -NK_API int nk_str_insert_str_char(struct nk_str*, int pos, const char*); -NK_API int nk_str_insert_text_utf8(struct nk_str*, int pos, const char*, int); -NK_API int nk_str_insert_str_utf8(struct nk_str*, int pos, const char*); -NK_API int nk_str_insert_text_runes(struct nk_str*, int pos, const nk_rune*, int); -NK_API int nk_str_insert_str_runes(struct nk_str*, int pos, const nk_rune*); - -NK_API void nk_str_remove_chars(struct nk_str*, int len); -NK_API void nk_str_remove_runes(struct nk_str *str, int len); -NK_API void nk_str_delete_chars(struct nk_str*, int pos, int len); -NK_API void nk_str_delete_runes(struct nk_str*, int pos, int len); - -NK_API char *nk_str_at_char(struct nk_str*, int pos); -NK_API char *nk_str_at_rune(struct nk_str*, int pos, nk_rune *unicode, int *len); -NK_API nk_rune nk_str_rune_at(const struct nk_str*, int pos); -NK_API const char *nk_str_at_char_const(const struct nk_str*, int pos); -NK_API const char *nk_str_at_const(const struct nk_str*, int pos, nk_rune *unicode, int *len); - -NK_API char *nk_str_get(struct nk_str*); -NK_API const char *nk_str_get_const(const struct nk_str*); -NK_API int nk_str_len(struct nk_str*); -NK_API int nk_str_len_char(struct nk_str*); - -/*=============================================================== - * - * TEXT EDITOR - * - * ===============================================================*/ -/* Editing text in this library is handled by either `nk_edit_string` or - * `nk_edit_buffer`. But like almost everything in this library there are multiple - * ways of doing it and a balance between control and ease of use with memory - * as well as functionality controlled by flags. - * - * This library generally allows three different levels of memory control: - * First of is the most basic way of just providing a simple char array with - * string length. This method is probably the easiest way of handling simple - * user text input. Main upside is complete control over memory while the biggest - * downside in comparsion with the other two approaches is missing undo/redo. - * - * For UIs that require undo/redo the second way was created. It is based on - * a fixed size nk_text_edit struct, which has an internal undo/redo stack. - * This is mainly useful if you want something more like a text editor but don't want - * to have a dynamically growing buffer. - * - * The final way is using a dynamically growing nk_text_edit struct, which - * has both a default version if you don't care where memory comes from and an - * allocator version if you do. While the text editor is quite powerful for its - * complexity I would not recommend editing gigabytes of data with it. - * It is rather designed for uses cases which make sense for a GUI library not for - * an full blown text editor. - */ -#ifndef NK_TEXTEDIT_UNDOSTATECOUNT -#define NK_TEXTEDIT_UNDOSTATECOUNT 99 -#endif - -#ifndef NK_TEXTEDIT_UNDOCHARCOUNT -#define NK_TEXTEDIT_UNDOCHARCOUNT 999 -#endif - -struct nk_text_edit; -struct nk_clipboard { - nk_handle userdata; - nk_plugin_paste paste; - nk_plugin_copy copy; -}; - -struct nk_text_undo_record { - int where; - short insert_length; - short delete_length; - short char_storage; -}; - -struct nk_text_undo_state { - struct nk_text_undo_record undo_rec[NK_TEXTEDIT_UNDOSTATECOUNT]; - nk_rune undo_char[NK_TEXTEDIT_UNDOCHARCOUNT]; - short undo_point; - short redo_point; - short undo_char_point; - short redo_char_point; -}; - -enum nk_text_edit_type { - NK_TEXT_EDIT_SINGLE_LINE, - NK_TEXT_EDIT_MULTI_LINE -}; - -enum nk_text_edit_mode { - NK_TEXT_EDIT_MODE_VIEW, - NK_TEXT_EDIT_MODE_INSERT, - NK_TEXT_EDIT_MODE_REPLACE -}; - -struct nk_text_edit { - struct nk_clipboard clip; - struct nk_str string; - nk_plugin_filter filter; - struct nk_vec2 scrollbar; - - int cursor; - int select_start; - int select_end; - unsigned char mode; - unsigned char cursor_at_end_of_line; - unsigned char initialized; - unsigned char has_preferred_x; - unsigned char single_line; - unsigned char active; - unsigned char padding1; - float preferred_x; - struct nk_text_undo_state undo; -}; - -/* filter function */ -NK_API int nk_filter_default(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_ascii(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_float(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_decimal(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_hex(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_oct(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_binary(const struct nk_text_edit*, nk_rune unicode); - -/* text editor */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_textedit_init_default(struct nk_text_edit*); -#endif -NK_API void nk_textedit_init(struct nk_text_edit*, struct nk_allocator*, nk_size size); -NK_API void nk_textedit_init_fixed(struct nk_text_edit*, void *memory, nk_size size); -NK_API void nk_textedit_free(struct nk_text_edit*); -NK_API void nk_textedit_text(struct nk_text_edit*, const char*, int total_len); -NK_API void nk_textedit_delete(struct nk_text_edit*, int where, int len); -NK_API void nk_textedit_delete_selection(struct nk_text_edit*); -NK_API void nk_textedit_select_all(struct nk_text_edit*); -NK_API int nk_textedit_cut(struct nk_text_edit*); -NK_API int nk_textedit_paste(struct nk_text_edit*, char const*, int len); -NK_API void nk_textedit_undo(struct nk_text_edit*); -NK_API void nk_textedit_redo(struct nk_text_edit*); - -/* =============================================================== - * - * DRAWING - * - * ===============================================================*/ -/* This library was designed to be render backend agnostic so it does - not draw anything to screen. Instead all drawn shapes, widgets - are made of, are buffered into memory and make up a command queue. - Each frame therefore fills the command buffer with draw commands - that then need to be executed by the user and his own render backend. - After that the command buffer needs to be cleared and a new frame can be - started. It is probably important to note that the command buffer is the main - drawing API and the optional vertex buffer API only takes this format and - converts it into a hardware accessible format. - - To use the command queue to draw your own widgets you can access the - command buffer of each window by calling `nk_window_get_canvas` after - previously having called `nk_begin`: - - void draw_red_rectangle_widget(struct nk_context *ctx) - { - struct nk_command_buffer *canvas; - struct nk_input *input = &ctx->input; - canvas = nk_window_get_canvas(ctx); - - struct nk_rect space; - enum nk_widget_layout_states state; - state = nk_widget(&space, ctx); - if (!state) return; - - if (state != NK_WIDGET_ROM) - update_your_widget_by_user_input(...); - nk_fill_rect(canvas, space, 0, nk_rgb(255,0,0)); - } - - if (nk_begin(...)) { - nk_layout_row_dynamic(ctx, 25, 1); - draw_red_rectangle_widget(ctx); - } - nk_end(..) - - Important to know if you want to create your own widgets is the `nk_widget` - call. It allocates space on the panel reserved for this widget to be used, - but also returns the state of the widget space. If your widget is not seen and does - not have to be updated it is '0' and you can just return. If it only has - to be drawn the state will be `NK_WIDGET_ROM` otherwise you can do both - update and draw your widget. The reason for seperating is to only draw and - update what is actually neccessary which is crucial for performance. -*/ -enum nk_command_type { - NK_COMMAND_NOP, - NK_COMMAND_SCISSOR, - NK_COMMAND_LINE, - NK_COMMAND_CURVE, - NK_COMMAND_RECT, - NK_COMMAND_RECT_FILLED, - NK_COMMAND_RECT_MULTI_COLOR, - NK_COMMAND_CIRCLE, - NK_COMMAND_CIRCLE_FILLED, - NK_COMMAND_ARC, - NK_COMMAND_ARC_FILLED, - NK_COMMAND_TRIANGLE, - NK_COMMAND_TRIANGLE_FILLED, - NK_COMMAND_POLYGON, - NK_COMMAND_POLYGON_FILLED, - NK_COMMAND_POLYLINE, - NK_COMMAND_TEXT, - NK_COMMAND_IMAGE, - NK_COMMAND_CUSTOM -}; - -/* command base and header of every command inside the buffer */ -struct nk_command { - enum nk_command_type type; - nk_size next; -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif -}; - -struct nk_command_scissor { - struct nk_command header; - short x, y; - unsigned short w, h; -}; - -struct nk_command_line { - struct nk_command header; - unsigned short line_thickness; - struct nk_vec2i begin; - struct nk_vec2i end; - struct nk_color color; -}; - -struct nk_command_curve { - struct nk_command header; - unsigned short line_thickness; - struct nk_vec2i begin; - struct nk_vec2i end; - struct nk_vec2i ctrl[2]; - struct nk_color color; -}; - -struct nk_command_rect { - struct nk_command header; - unsigned short rounding; - unsigned short line_thickness; - short x, y; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_rect_filled { - struct nk_command header; - unsigned short rounding; - short x, y; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_rect_multi_color { - struct nk_command header; - short x, y; - unsigned short w, h; - struct nk_color left; - struct nk_color top; - struct nk_color bottom; - struct nk_color right; -}; - -struct nk_command_triangle { - struct nk_command header; - unsigned short line_thickness; - struct nk_vec2i a; - struct nk_vec2i b; - struct nk_vec2i c; - struct nk_color color; -}; - -struct nk_command_triangle_filled { - struct nk_command header; - struct nk_vec2i a; - struct nk_vec2i b; - struct nk_vec2i c; - struct nk_color color; -}; - -struct nk_command_circle { - struct nk_command header; - short x, y; - unsigned short line_thickness; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_circle_filled { - struct nk_command header; - short x, y; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_arc { - struct nk_command header; - short cx, cy; - unsigned short r; - unsigned short line_thickness; - float a[2]; - struct nk_color color; -}; - -struct nk_command_arc_filled { - struct nk_command header; - short cx, cy; - unsigned short r; - float a[2]; - struct nk_color color; -}; - -struct nk_command_polygon { - struct nk_command header; - struct nk_color color; - unsigned short line_thickness; - unsigned short point_count; - struct nk_vec2i points[1]; -}; - -struct nk_command_polygon_filled { - struct nk_command header; - struct nk_color color; - unsigned short point_count; - struct nk_vec2i points[1]; -}; - -struct nk_command_polyline { - struct nk_command header; - struct nk_color color; - unsigned short line_thickness; - unsigned short point_count; - struct nk_vec2i points[1]; -}; - -struct nk_command_image { - struct nk_command header; - short x, y; - unsigned short w, h; - struct nk_image img; - struct nk_color col; -}; - -typedef void (*nk_command_custom_callback)(void *canvas, short x,short y, - unsigned short w, unsigned short h, nk_handle callback_data); -struct nk_command_custom { - struct nk_command header; - short x, y; - unsigned short w, h; - nk_handle callback_data; - nk_command_custom_callback callback; -}; - -struct nk_command_text { - struct nk_command header; - const struct nk_user_font *font; - struct nk_color background; - struct nk_color foreground; - short x, y; - unsigned short w, h; - float height; - int length; - char string[1]; -}; - -enum nk_command_clipping { - NK_CLIPPING_OFF = nk_false, - NK_CLIPPING_ON = nk_true -}; - -struct nk_command_buffer { - struct nk_buffer *base; - struct nk_rect clip; - int use_clipping; - nk_handle userdata; - nk_size begin, end, last; -}; - -/* shape outlines */ -NK_API void nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, float x1, float y1, float line_thickness, struct nk_color); -NK_API void nk_stroke_curve(struct nk_command_buffer*, float, float, float, float, float, float, float, float, float line_thickness, struct nk_color); -NK_API void nk_stroke_rect(struct nk_command_buffer*, struct nk_rect, float rounding, float line_thickness, struct nk_color); -NK_API void nk_stroke_circle(struct nk_command_buffer*, struct nk_rect, float line_thickness, struct nk_color); -NK_API void nk_stroke_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, float line_thickness, struct nk_color); -NK_API void nk_stroke_triangle(struct nk_command_buffer*, float, float, float, float, float, float, float line_thichness, struct nk_color); -NK_API void nk_stroke_polyline(struct nk_command_buffer*, float *points, int point_count, float line_thickness, struct nk_color col); -NK_API void nk_stroke_polygon(struct nk_command_buffer*, float*, int point_count, float line_thickness, struct nk_color); - -/* filled shades */ -NK_API void nk_fill_rect(struct nk_command_buffer*, struct nk_rect, float rounding, struct nk_color); -NK_API void nk_fill_rect_multi_color(struct nk_command_buffer*, struct nk_rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom); -NK_API void nk_fill_circle(struct nk_command_buffer*, struct nk_rect, struct nk_color); -NK_API void nk_fill_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, struct nk_color); -NK_API void nk_fill_triangle(struct nk_command_buffer*, float x0, float y0, float x1, float y1, float x2, float y2, struct nk_color); -NK_API void nk_fill_polygon(struct nk_command_buffer*, float*, int point_count, struct nk_color); - -/* misc */ -NK_API void nk_draw_image(struct nk_command_buffer*, struct nk_rect, const struct nk_image*, struct nk_color); -NK_API void nk_draw_text(struct nk_command_buffer*, struct nk_rect, const char *text, int len, const struct nk_user_font*, struct nk_color, struct nk_color); -NK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect); -NK_API void nk_push_custom(struct nk_command_buffer*, struct nk_rect, nk_command_custom_callback, nk_handle usr); - -/* =============================================================== - * - * INPUT - * - * ===============================================================*/ -struct nk_mouse_button { - int down; - unsigned int clicked; - struct nk_vec2 clicked_pos; -}; -struct nk_mouse { - struct nk_mouse_button buttons[NK_BUTTON_MAX]; - struct nk_vec2 pos; - struct nk_vec2 prev; - struct nk_vec2 delta; - struct nk_vec2 scroll_delta; - unsigned char grab; - unsigned char grabbed; - unsigned char ungrab; -}; - -struct nk_key { - int down; - unsigned int clicked; -}; -struct nk_keyboard { - struct nk_key keys[NK_KEY_MAX]; - char text[NK_INPUT_MAX]; - int text_len; -}; - -struct nk_input { - struct nk_keyboard keyboard; - struct nk_mouse mouse; -}; - -NK_API int nk_input_has_mouse_click(const struct nk_input*, enum nk_buttons); -NK_API int nk_input_has_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect); -NK_API int nk_input_has_mouse_click_down_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect, int down); -NK_API int nk_input_is_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect); -NK_API int nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, struct nk_rect b, int down); -NK_API int nk_input_any_mouse_click_in_rect(const struct nk_input*, struct nk_rect); -NK_API int nk_input_is_mouse_prev_hovering_rect(const struct nk_input*, struct nk_rect); -NK_API int nk_input_is_mouse_hovering_rect(const struct nk_input*, struct nk_rect); -NK_API int nk_input_mouse_clicked(const struct nk_input*, enum nk_buttons, struct nk_rect); -NK_API int nk_input_is_mouse_down(const struct nk_input*, enum nk_buttons); -NK_API int nk_input_is_mouse_pressed(const struct nk_input*, enum nk_buttons); -NK_API int nk_input_is_mouse_released(const struct nk_input*, enum nk_buttons); -NK_API int nk_input_is_key_pressed(const struct nk_input*, enum nk_keys); -NK_API int nk_input_is_key_released(const struct nk_input*, enum nk_keys); -NK_API int nk_input_is_key_down(const struct nk_input*, enum nk_keys); - -/* =============================================================== - * - * DRAW LIST - * - * ===============================================================*/ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -/* The optional vertex buffer draw list provides a 2D drawing context - with antialiasing functionality which takes basic filled or outlined shapes - or a path and outputs vertexes, elements and draw commands. - The actual draw list API is not required to be used directly while using this - library since converting the default library draw command output is done by - just calling `nk_convert` but I decided to still make this library accessible - since it can be useful. - - The draw list is based on a path buffering and polygon and polyline - rendering API which allows a lot of ways to draw 2D content to screen. - In fact it is probably more powerful than needed but allows even more crazy - things than this library provides by default. -*/ -typedef nk_ushort nk_draw_index; -enum nk_draw_list_stroke { - NK_STROKE_OPEN = nk_false, - /* build up path has no connection back to the beginning */ - NK_STROKE_CLOSED = nk_true - /* build up path has a connection back to the beginning */ -}; - -enum nk_draw_vertex_layout_attribute { - NK_VERTEX_POSITION, - NK_VERTEX_COLOR, - NK_VERTEX_TEXCOORD, - NK_VERTEX_ATTRIBUTE_COUNT -}; - -enum nk_draw_vertex_layout_format { - NK_FORMAT_SCHAR, - NK_FORMAT_SSHORT, - NK_FORMAT_SINT, - NK_FORMAT_UCHAR, - NK_FORMAT_USHORT, - NK_FORMAT_UINT, - NK_FORMAT_FLOAT, - NK_FORMAT_DOUBLE, - -NK_FORMAT_COLOR_BEGIN, - NK_FORMAT_R8G8B8 = NK_FORMAT_COLOR_BEGIN, - NK_FORMAT_R16G15B16, - NK_FORMAT_R32G32B32, - - NK_FORMAT_R8G8B8A8, - NK_FORMAT_B8G8R8A8, - NK_FORMAT_R16G15B16A16, - NK_FORMAT_R32G32B32A32, - NK_FORMAT_R32G32B32A32_FLOAT, - NK_FORMAT_R32G32B32A32_DOUBLE, - - NK_FORMAT_RGB32, - NK_FORMAT_RGBA32, -NK_FORMAT_COLOR_END = NK_FORMAT_RGBA32, - NK_FORMAT_COUNT -}; - -#define NK_VERTEX_LAYOUT_END NK_VERTEX_ATTRIBUTE_COUNT,NK_FORMAT_COUNT,0 -struct nk_draw_vertex_layout_element { - enum nk_draw_vertex_layout_attribute attribute; - enum nk_draw_vertex_layout_format format; - nk_size offset; -}; - -struct nk_draw_command { - unsigned int elem_count; - /* number of elements in the current draw batch */ - struct nk_rect clip_rect; - /* current screen clipping rectangle */ - nk_handle texture; - /* current texture to set */ -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif -}; - -struct nk_draw_list { - struct nk_rect clip_rect; - struct nk_vec2 circle_vtx[12]; - struct nk_convert_config config; - - struct nk_buffer *buffer; - struct nk_buffer *vertices; - struct nk_buffer *elements; - - unsigned int element_count; - unsigned int vertex_count; - unsigned int cmd_count; - nk_size cmd_offset; - - unsigned int path_count; - unsigned int path_offset; - - enum nk_anti_aliasing line_AA; - enum nk_anti_aliasing shape_AA; - -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif -}; - -/* draw list */ -NK_API void nk_draw_list_init(struct nk_draw_list*); -NK_API void nk_draw_list_setup(struct nk_draw_list*, const struct nk_convert_config*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, enum nk_anti_aliasing line_aa,enum nk_anti_aliasing shape_aa); -NK_API void nk_draw_list_clear(struct nk_draw_list*); - -/* drawing */ -#define nk_draw_list_foreach(cmd, can, b) for((cmd)=nk__draw_list_begin(can, b); (cmd)!=0; (cmd)=nk__draw_list_next(cmd, b, can)) -NK_API const struct nk_draw_command* nk__draw_list_begin(const struct nk_draw_list*, const struct nk_buffer*); -NK_API const struct nk_draw_command* nk__draw_list_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_draw_list*); -NK_API const struct nk_draw_command* nk__draw_list_end(const struct nk_draw_list*, const struct nk_buffer*); -NK_API void nk_draw_list_clear(struct nk_draw_list *list); - -/* path */ -NK_API void nk_draw_list_path_clear(struct nk_draw_list*); -NK_API void nk_draw_list_path_line_to(struct nk_draw_list*, struct nk_vec2 pos); -NK_API void nk_draw_list_path_arc_to_fast(struct nk_draw_list*, struct nk_vec2 center, float radius, int a_min, int a_max); -NK_API void nk_draw_list_path_arc_to(struct nk_draw_list*, struct nk_vec2 center, float radius, float a_min, float a_max, unsigned int segments); -NK_API void nk_draw_list_path_rect_to(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, float rounding); -NK_API void nk_draw_list_path_curve_to(struct nk_draw_list*, struct nk_vec2 p2, struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments); -NK_API void nk_draw_list_path_fill(struct nk_draw_list*, struct nk_color); -NK_API void nk_draw_list_path_stroke(struct nk_draw_list*, struct nk_color, enum nk_draw_list_stroke closed, float thickness); - -/* stroke */ -NK_API void nk_draw_list_stroke_line(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_color, float thickness); -NK_API void nk_draw_list_stroke_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding, float thickness); -NK_API void nk_draw_list_stroke_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color, float thickness); -NK_API void nk_draw_list_stroke_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color, unsigned int segs, float thickness); -NK_API void nk_draw_list_stroke_curve(struct nk_draw_list*, struct nk_vec2 p0, struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, struct nk_color, unsigned int segments, float thickness); -NK_API void nk_draw_list_stroke_poly_line(struct nk_draw_list*, const struct nk_vec2 *pnts, const unsigned int cnt, struct nk_color, enum nk_draw_list_stroke, float thickness, enum nk_anti_aliasing); - -/* fill */ -NK_API void nk_draw_list_fill_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding); -NK_API void nk_draw_list_fill_rect_multi_color(struct nk_draw_list*, struct nk_rect rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom); -NK_API void nk_draw_list_fill_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color); -NK_API void nk_draw_list_fill_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color col, unsigned int segs); -NK_API void nk_draw_list_fill_poly_convex(struct nk_draw_list*, const struct nk_vec2 *points, const unsigned int count, struct nk_color, enum nk_anti_aliasing); - -/* misc */ -NK_API void nk_draw_list_add_image(struct nk_draw_list*, struct nk_image texture, struct nk_rect rect, struct nk_color); -NK_API void nk_draw_list_add_text(struct nk_draw_list*, const struct nk_user_font*, struct nk_rect, const char *text, int len, float font_height, struct nk_color); -#ifdef NK_INCLUDE_COMMAND_USERDATA -NK_API void nk_draw_list_push_userdata(struct nk_draw_list*, nk_handle userdata); -#endif - -#endif - -/* =============================================================== - * - * GUI - * - * ===============================================================*/ -enum nk_style_item_type { - NK_STYLE_ITEM_COLOR, - NK_STYLE_ITEM_IMAGE -}; - -union nk_style_item_data { - struct nk_image image; - struct nk_color color; -}; - -struct nk_style_item { - enum nk_style_item_type type; - union nk_style_item_data data; -}; - -struct nk_style_text { - struct nk_color color; - struct nk_vec2 padding; -}; - -struct nk_style_button { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* text */ - struct nk_color text_background; - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_active; - nk_flags text_alignment; - - /* properties */ - float border; - float rounding; - struct nk_vec2 padding; - struct nk_vec2 image_padding; - struct nk_vec2 touch_padding; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle userdata); - void(*draw_end)(struct nk_command_buffer*, nk_handle userdata); -}; - -struct nk_style_toggle { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - - /* text */ - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_active; - struct nk_color text_background; - nk_flags text_alignment; - - /* properties */ - struct nk_vec2 padding; - struct nk_vec2 touch_padding; - float spacing; - float border; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_selectable { - /* background (inactive) */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item pressed; - - /* background (active) */ - struct nk_style_item normal_active; - struct nk_style_item hover_active; - struct nk_style_item pressed_active; - - /* text color (inactive) */ - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_pressed; - - /* text color (active) */ - struct nk_color text_normal_active; - struct nk_color text_hover_active; - struct nk_color text_pressed_active; - struct nk_color text_background; - nk_flags text_alignment; - - /* properties */ - float rounding; - struct nk_vec2 padding; - struct nk_vec2 touch_padding; - struct nk_vec2 image_padding; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_slider { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* background bar */ - struct nk_color bar_normal; - struct nk_color bar_hover; - struct nk_color bar_active; - struct nk_color bar_filled; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - struct nk_style_item cursor_active; - - /* properties */ - float border; - float rounding; - float bar_height; - struct nk_vec2 padding; - struct nk_vec2 spacing; - struct nk_vec2 cursor_size; - - /* optional buttons */ - int show_buttons; - struct nk_style_button inc_button; - struct nk_style_button dec_button; - enum nk_symbol_type inc_symbol; - enum nk_symbol_type dec_symbol; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_progress { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - struct nk_style_item cursor_active; - struct nk_color cursor_border_color; - - /* properties */ - float rounding; - float border; - float cursor_border; - float cursor_rounding; - struct nk_vec2 padding; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_scrollbar { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - struct nk_style_item cursor_active; - struct nk_color cursor_border_color; - - /* properties */ - float border; - float rounding; - float border_cursor; - float rounding_cursor; - struct nk_vec2 padding; - - /* optional buttons */ - int show_buttons; - struct nk_style_button inc_button; - struct nk_style_button dec_button; - enum nk_symbol_type inc_symbol; - enum nk_symbol_type dec_symbol; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_edit { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - struct nk_style_scrollbar scrollbar; - - /* cursor */ - struct nk_color cursor_normal; - struct nk_color cursor_hover; - struct nk_color cursor_text_normal; - struct nk_color cursor_text_hover; - - /* text (unselected) */ - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_active; - - /* text (selected) */ - struct nk_color selected_normal; - struct nk_color selected_hover; - struct nk_color selected_text_normal; - struct nk_color selected_text_hover; - - /* properties */ - float border; - float rounding; - float cursor_size; - struct nk_vec2 scrollbar_size; - struct nk_vec2 padding; - float row_padding; -}; - -struct nk_style_property { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* text */ - struct nk_color label_normal; - struct nk_color label_hover; - struct nk_color label_active; - - /* symbols */ - enum nk_symbol_type sym_left; - enum nk_symbol_type sym_right; - - /* properties */ - float border; - float rounding; - struct nk_vec2 padding; - - struct nk_style_edit edit; - struct nk_style_button inc_button; - struct nk_style_button dec_button; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_chart { - /* colors */ - struct nk_style_item background; - struct nk_color border_color; - struct nk_color selected_color; - struct nk_color color; - - /* properties */ - float border; - float rounding; - struct nk_vec2 padding; -}; - -struct nk_style_combo { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* label */ - struct nk_color label_normal; - struct nk_color label_hover; - struct nk_color label_active; - - /* symbol */ - struct nk_color symbol_normal; - struct nk_color symbol_hover; - struct nk_color symbol_active; - - /* button */ - struct nk_style_button button; - enum nk_symbol_type sym_normal; - enum nk_symbol_type sym_hover; - enum nk_symbol_type sym_active; - - /* properties */ - float border; - float rounding; - struct nk_vec2 content_padding; - struct nk_vec2 button_padding; - struct nk_vec2 spacing; -}; - -struct nk_style_tab { - /* background */ - struct nk_style_item background; - struct nk_color border_color; - struct nk_color text; - - /* button */ - struct nk_style_button tab_maximize_button; - struct nk_style_button tab_minimize_button; - struct nk_style_button node_maximize_button; - struct nk_style_button node_minimize_button; - enum nk_symbol_type sym_minimize; - enum nk_symbol_type sym_maximize; - - /* properties */ - float border; - float rounding; - float indent; - struct nk_vec2 padding; - struct nk_vec2 spacing; -}; - -enum nk_style_header_align { - NK_HEADER_LEFT, - NK_HEADER_RIGHT -}; -struct nk_style_window_header { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - - /* button */ - struct nk_style_button close_button; - struct nk_style_button minimize_button; - enum nk_symbol_type close_symbol; - enum nk_symbol_type minimize_symbol; - enum nk_symbol_type maximize_symbol; - - /* title */ - struct nk_color label_normal; - struct nk_color label_hover; - struct nk_color label_active; - - /* properties */ - enum nk_style_header_align align; - struct nk_vec2 padding; - struct nk_vec2 label_padding; - struct nk_vec2 spacing; -}; - -struct nk_style_window { - struct nk_style_window_header header; - struct nk_style_item fixed_background; - struct nk_color background; - - struct nk_color border_color; - struct nk_color popup_border_color; - struct nk_color combo_border_color; - struct nk_color contextual_border_color; - struct nk_color menu_border_color; - struct nk_color group_border_color; - struct nk_color tooltip_border_color; - struct nk_style_item scaler; - - float border; - float combo_border; - float contextual_border; - float menu_border; - float group_border; - float tooltip_border; - float popup_border; - float min_row_height_padding; - - float rounding; - struct nk_vec2 spacing; - struct nk_vec2 scrollbar_size; - struct nk_vec2 min_size; - - struct nk_vec2 padding; - struct nk_vec2 group_padding; - struct nk_vec2 popup_padding; - struct nk_vec2 combo_padding; - struct nk_vec2 contextual_padding; - struct nk_vec2 menu_padding; - struct nk_vec2 tooltip_padding; -}; - -struct nk_style { - const struct nk_user_font *font; - const struct nk_cursor *cursors[NK_CURSOR_COUNT]; - const struct nk_cursor *cursor_active; - struct nk_cursor *cursor_last; - int cursor_visible; - - struct nk_style_text text; - struct nk_style_button button; - struct nk_style_button contextual_button; - struct nk_style_button menu_button; - struct nk_style_toggle option; - struct nk_style_toggle checkbox; - struct nk_style_selectable selectable; - struct nk_style_slider slider; - struct nk_style_progress progress; - struct nk_style_property property; - struct nk_style_edit edit; - struct nk_style_chart chart; - struct nk_style_scrollbar scrollh; - struct nk_style_scrollbar scrollv; - struct nk_style_tab tab; - struct nk_style_combo combo; - struct nk_style_window window; -}; - -NK_API struct nk_style_item nk_style_item_image(struct nk_image img); -NK_API struct nk_style_item nk_style_item_color(struct nk_color); -NK_API struct nk_style_item nk_style_item_hide(void); - -/*============================================================== - * PANEL - * =============================================================*/ -#ifndef NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS -#define NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS 16 -#endif -#ifndef NK_CHART_MAX_SLOT -#define NK_CHART_MAX_SLOT 4 -#endif - -enum nk_panel_type { - NK_PANEL_WINDOW = NK_FLAG(0), - NK_PANEL_GROUP = NK_FLAG(1), - NK_PANEL_POPUP = NK_FLAG(2), - NK_PANEL_CONTEXTUAL = NK_FLAG(4), - NK_PANEL_COMBO = NK_FLAG(5), - NK_PANEL_MENU = NK_FLAG(6), - NK_PANEL_TOOLTIP = NK_FLAG(7) -}; -enum nk_panel_set { - NK_PANEL_SET_NONBLOCK = NK_PANEL_CONTEXTUAL|NK_PANEL_COMBO|NK_PANEL_MENU|NK_PANEL_TOOLTIP, - NK_PANEL_SET_POPUP = NK_PANEL_SET_NONBLOCK|NK_PANEL_POPUP, - NK_PANEL_SET_SUB = NK_PANEL_SET_POPUP|NK_PANEL_GROUP -}; - -struct nk_chart_slot { - enum nk_chart_type type; - struct nk_color color; - struct nk_color highlight; - float min, max, range; - int count; - struct nk_vec2 last; - int index; -}; - -struct nk_chart { - int slot; - float x, y, w, h; - struct nk_chart_slot slots[NK_CHART_MAX_SLOT]; -}; - -enum nk_panel_row_layout_type { - NK_LAYOUT_DYNAMIC_FIXED = 0, - NK_LAYOUT_DYNAMIC_ROW, - NK_LAYOUT_DYNAMIC_FREE, - NK_LAYOUT_DYNAMIC, - NK_LAYOUT_STATIC_FIXED, - NK_LAYOUT_STATIC_ROW, - NK_LAYOUT_STATIC_FREE, - NK_LAYOUT_STATIC, - NK_LAYOUT_TEMPLATE, - NK_LAYOUT_COUNT -}; -struct nk_row_layout { - enum nk_panel_row_layout_type type; - int index; - float height; - float min_height; - int columns; - const float *ratio; - float item_width; - float item_height; - float item_offset; - float filled; - struct nk_rect item; - int tree_depth; - float templates[NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS]; -}; - -struct nk_popup_buffer { - nk_size begin; - nk_size parent; - nk_size last; - nk_size end; - int active; -}; - -struct nk_menu_state { - float x, y, w, h; - struct nk_scroll offset; -}; - -struct nk_panel { - enum nk_panel_type type; - nk_flags flags; - struct nk_rect bounds; - nk_uint *offset_x; - nk_uint *offset_y; - float at_x, at_y, max_x; - float footer_height; - float header_height; - float border; - unsigned int has_scrolling; - struct nk_rect clip; - struct nk_menu_state menu; - struct nk_row_layout row; - struct nk_chart chart; - struct nk_command_buffer *buffer; - struct nk_panel *parent; -}; - -/*============================================================== - * WINDOW - * =============================================================*/ -#ifndef NK_WINDOW_MAX_NAME -#define NK_WINDOW_MAX_NAME 64 -#endif - -struct nk_table; -enum nk_window_flags { - NK_WINDOW_PRIVATE = NK_FLAG(11), - NK_WINDOW_DYNAMIC = NK_WINDOW_PRIVATE, - /* special window type growing up in height while being filled to a certain maximum height */ - NK_WINDOW_ROM = NK_FLAG(12), - /* sets window widgets into a read only mode and does not allow input changes */ - NK_WINDOW_NOT_INTERACTIVE = NK_WINDOW_ROM|NK_WINDOW_NO_INPUT, - /* prevents all interaction caused by input to either window or widgets inside */ - NK_WINDOW_HIDDEN = NK_FLAG(13), - /* Hides window and stops any window interaction and drawing */ - NK_WINDOW_CLOSED = NK_FLAG(14), - /* Directly closes and frees the window at the end of the frame */ - NK_WINDOW_MINIMIZED = NK_FLAG(15), - /* marks the window as minimized */ - NK_WINDOW_REMOVE_ROM = NK_FLAG(16) - /* Removes read only mode at the end of the window */ -}; - -struct nk_popup_state { - struct nk_window *win; - enum nk_panel_type type; - struct nk_popup_buffer buf; - nk_hash name; - int active; - unsigned combo_count; - unsigned con_count, con_old; - unsigned active_con; - struct nk_rect header; -}; - -struct nk_edit_state { - nk_hash name; - unsigned int seq; - unsigned int old; - int active, prev; - int cursor; - int sel_start; - int sel_end; - struct nk_scroll scrollbar; - unsigned char mode; - unsigned char single_line; -}; - -struct nk_property_state { - int active, prev; - char buffer[NK_MAX_NUMBER_BUFFER]; - int length; - int cursor; - int select_start; - int select_end; - nk_hash name; - unsigned int seq; - unsigned int old; - int state; -}; - -struct nk_window { - unsigned int seq; - nk_hash name; - char name_string[NK_WINDOW_MAX_NAME]; - nk_flags flags; - - struct nk_rect bounds; - struct nk_scroll scrollbar; - struct nk_command_buffer buffer; - struct nk_panel *layout; - float scrollbar_hiding_timer; - - /* persistent widget state */ - struct nk_property_state property; - struct nk_popup_state popup; - struct nk_edit_state edit; - unsigned int scrolled; - - struct nk_table *tables; - unsigned int table_count; - - /* window list hooks */ - struct nk_window *next; - struct nk_window *prev; - struct nk_window *parent; -}; - -/*============================================================== - * STACK - * =============================================================*/ -/* The style modifier stack can be used to temporarily change a - * property inside `nk_style`. For example if you want a special - * red button you can temporarily push the old button color onto a stack - * draw the button with a red color and then you just pop the old color - * back from the stack: - * - * nk_style_push_style_item(ctx, &ctx->style.button.normal, nk_style_item_color(nk_rgb(255,0,0))); - * nk_style_push_style_item(ctx, &ctx->style.button.hover, nk_style_item_color(nk_rgb(255,0,0))); - * nk_style_push_style_item(ctx, &ctx->style.button.active, nk_style_item_color(nk_rgb(255,0,0))); - * nk_style_push_vec2(ctx, &cx->style.button.padding, nk_vec2(2,2)); - * - * nk_button(...); - * - * nk_style_pop_style_item(ctx); - * nk_style_pop_style_item(ctx); - * nk_style_pop_style_item(ctx); - * nk_style_pop_vec2(ctx); - * - * Nuklear has a stack for style_items, float properties, vector properties, - * flags, colors, fonts and for button_behavior. Each has it's own fixed size stack - * which can be changed at compile time. - */ -#ifndef NK_BUTTON_BEHAVIOR_STACK_SIZE -#define NK_BUTTON_BEHAVIOR_STACK_SIZE 8 -#endif - -#ifndef NK_FONT_STACK_SIZE -#define NK_FONT_STACK_SIZE 8 -#endif - -#ifndef NK_STYLE_ITEM_STACK_SIZE -#define NK_STYLE_ITEM_STACK_SIZE 16 -#endif - -#ifndef NK_FLOAT_STACK_SIZE -#define NK_FLOAT_STACK_SIZE 32 -#endif - -#ifndef NK_VECTOR_STACK_SIZE -#define NK_VECTOR_STACK_SIZE 16 -#endif - -#ifndef NK_FLAGS_STACK_SIZE -#define NK_FLAGS_STACK_SIZE 32 -#endif - -#ifndef NK_COLOR_STACK_SIZE -#define NK_COLOR_STACK_SIZE 32 -#endif - -#define NK_CONFIGURATION_STACK_TYPE(prefix, name, type)\ - struct nk_config_stack_##name##_element {\ - prefix##_##type *address;\ - prefix##_##type old_value;\ - } -#define NK_CONFIG_STACK(type,size)\ - struct nk_config_stack_##type {\ - int head;\ - struct nk_config_stack_##type##_element elements[size];\ - } - -#define nk_float float -NK_CONFIGURATION_STACK_TYPE(struct nk, style_item, style_item); -NK_CONFIGURATION_STACK_TYPE(nk ,float, float); -NK_CONFIGURATION_STACK_TYPE(struct nk, vec2, vec2); -NK_CONFIGURATION_STACK_TYPE(nk ,flags, flags); -NK_CONFIGURATION_STACK_TYPE(struct nk, color, color); -NK_CONFIGURATION_STACK_TYPE(const struct nk, user_font, user_font*); -NK_CONFIGURATION_STACK_TYPE(enum nk, button_behavior, button_behavior); - -NK_CONFIG_STACK(style_item, NK_STYLE_ITEM_STACK_SIZE); -NK_CONFIG_STACK(float, NK_FLOAT_STACK_SIZE); -NK_CONFIG_STACK(vec2, NK_VECTOR_STACK_SIZE); -NK_CONFIG_STACK(flags, NK_FLAGS_STACK_SIZE); -NK_CONFIG_STACK(color, NK_COLOR_STACK_SIZE); -NK_CONFIG_STACK(user_font, NK_FONT_STACK_SIZE); -NK_CONFIG_STACK(button_behavior, NK_BUTTON_BEHAVIOR_STACK_SIZE); - -struct nk_configuration_stacks { - struct nk_config_stack_style_item style_items; - struct nk_config_stack_float floats; - struct nk_config_stack_vec2 vectors; - struct nk_config_stack_flags flags; - struct nk_config_stack_color colors; - struct nk_config_stack_user_font fonts; - struct nk_config_stack_button_behavior button_behaviors; -}; - -/*============================================================== - * CONTEXT - * =============================================================*/ -#define NK_VALUE_PAGE_CAPACITY \ - (((NK_MAX(sizeof(struct nk_window),sizeof(struct nk_panel)) / sizeof(nk_uint))) / 2) - -struct nk_table { - unsigned int seq; - unsigned int size; - nk_hash keys[NK_VALUE_PAGE_CAPACITY]; - nk_uint values[NK_VALUE_PAGE_CAPACITY]; - struct nk_table *next, *prev; -}; - -union nk_page_data { - struct nk_table tbl; - struct nk_panel pan; - struct nk_window win; -}; - -struct nk_page_element { - union nk_page_data data; - struct nk_page_element *next; - struct nk_page_element *prev; -}; - -struct nk_page { - unsigned int size; - struct nk_page *next; - struct nk_page_element win[1]; -}; - -struct nk_pool { - struct nk_allocator alloc; - enum nk_allocation_type type; - unsigned int page_count; - struct nk_page *pages; - struct nk_page_element *freelist; - unsigned capacity; - nk_size size; - nk_size cap; -}; - -struct nk_context { -/* public: can be accessed freely */ - struct nk_input input; - struct nk_style style; - struct nk_buffer memory; - struct nk_clipboard clip; - nk_flags last_widget_state; - enum nk_button_behavior button_behavior; - struct nk_configuration_stacks stacks; - float delta_time_seconds; - -/* private: - should only be accessed if you - know what you are doing */ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - struct nk_draw_list draw_list; -#endif -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif - /* text editor objects are quite big because of an internal - * undo/redo stack. Therefore it does not make sense to have one for - * each window for temporary use cases, so I only provide *one* instance - * for all windows. This works because the content is cleared anyway */ - struct nk_text_edit text_edit; - /* draw buffer used for overlay drawing operation like cursor */ - struct nk_command_buffer overlay; - - /* windows */ - int build; - int use_pool; - struct nk_pool pool; - struct nk_window *begin; - struct nk_window *end; - struct nk_window *active; - struct nk_window *current; - struct nk_page_element *freelist; - unsigned int count; - unsigned int seq; -}; - -/* ============================================================== - * MATH - * =============================================================== */ -#define NK_PI 3.141592654f -#define NK_UTF_INVALID 0xFFFD -#define NK_MAX_FLOAT_PRECISION 2 - -#define NK_UNUSED(x) ((void)(x)) -#define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x))) -#define NK_LEN(a) (sizeof(a)/sizeof(a)[0]) -#define NK_ABS(a) (((a) < 0) ? -(a) : (a)) -#define NK_BETWEEN(x, a, b) ((a) <= (x) && (x) < (b)) -#define NK_INBOX(px, py, x, y, w, h)\ - (NK_BETWEEN(px,x,x+w) && NK_BETWEEN(py,y,y+h)) -#define NK_INTERSECT(x0, y0, w0, h0, x1, y1, w1, h1) \ - (!(((x1 > (x0 + w0)) || ((x1 + w1) < x0) || (y1 > (y0 + h0)) || (y1 + h1) < y0))) -#define NK_CONTAINS(x, y, w, h, bx, by, bw, bh)\ - (NK_INBOX(x,y, bx, by, bw, bh) && NK_INBOX(x+w,y+h, bx, by, bw, bh)) - -#define nk_vec2_sub(a, b) nk_vec2((a).x - (b).x, (a).y - (b).y) -#define nk_vec2_add(a, b) nk_vec2((a).x + (b).x, (a).y + (b).y) -#define nk_vec2_len_sqr(a) ((a).x*(a).x+(a).y*(a).y) -#define nk_vec2_muls(a, t) nk_vec2((a).x * (t), (a).y * (t)) - -#define nk_ptr_add(t, p, i) ((t*)((void*)((nk_byte*)(p) + (i)))) -#define nk_ptr_add_const(t, p, i) ((const t*)((const void*)((const nk_byte*)(p) + (i)))) -#define nk_zero_struct(s) nk_zero(&s, sizeof(s)) - -/* ============================================================== - * ALIGNMENT - * =============================================================== */ -/* Pointer to Integer type conversion for pointer alignment */ -#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC*/ -# define NK_UINT_TO_PTR(x) ((void*)(__PTRDIFF_TYPE__)(x)) -# define NK_PTR_TO_UINT(x) ((nk_size)(__PTRDIFF_TYPE__)(x)) -#elif !defined(__GNUC__) /* works for compilers other than LLVM */ -# define NK_UINT_TO_PTR(x) ((void*)&((char*)0)[x]) -# define NK_PTR_TO_UINT(x) ((nk_size)(((char*)x)-(char*)0)) -#elif defined(NK_USE_FIXED_TYPES) /* used if we have */ -# define NK_UINT_TO_PTR(x) ((void*)(uintptr_t)(x)) -# define NK_PTR_TO_UINT(x) ((uintptr_t)(x)) -#else /* generates warning but works */ -# define NK_UINT_TO_PTR(x) ((void*)(x)) -# define NK_PTR_TO_UINT(x) ((nk_size)(x)) -#endif - -#define NK_ALIGN_PTR(x, mask)\ - (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x) + (mask-1)) & ~(mask-1)))) -#define NK_ALIGN_PTR_BACK(x, mask)\ - (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x)) & ~(mask-1)))) - -#define NK_OFFSETOF(st,m) ((nk_ptr)&(((st*)0)->m)) -#define NK_CONTAINER_OF(ptr,type,member)\ - (type*)((void*)((char*)(1 ? (ptr): &((type*)0)->member) - NK_OFFSETOF(type, member))) - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -template struct nk_alignof; -template struct nk_helper{enum {value = size_diff};}; -template struct nk_helper{enum {value = nk_alignof::value};}; -template struct nk_alignof{struct Big {T x; char c;}; enum { - diff = sizeof(Big) - sizeof(T), value = nk_helper::value};}; -#define NK_ALIGNOF(t) (nk_alignof::value) -#elif defined(_MSC_VER) -#define NK_ALIGNOF(t) (__alignof(t)) -#else -#define NK_ALIGNOF(t) ((char*)(&((struct {char c; t _h;}*)0)->_h) - (char*)0) -#endif - -#endif /* NK_H_ */ -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_IMPLEMENTATION - -#ifndef NK_POOL_DEFAULT_CAPACITY -#define NK_POOL_DEFAULT_CAPACITY 16 -#endif - -#ifndef NK_DEFAULT_COMMAND_BUFFER_SIZE -#define NK_DEFAULT_COMMAND_BUFFER_SIZE (4*1024) -#endif - -#ifndef NK_BUFFER_DEFAULT_INITIAL_SIZE -#define NK_BUFFER_DEFAULT_INITIAL_SIZE (4*1024) -#endif - -/* standard library headers */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -#include /* malloc, free */ -#endif -#ifdef NK_INCLUDE_STANDARD_IO -#include /* fopen, fclose,... */ -#endif -#ifdef NK_INCLUDE_STANDARD_VARARGS -#include /* valist, va_start, va_end, ... */ -#endif -#ifndef NK_ASSERT -#include -#define NK_ASSERT(expr) assert(expr) -#endif - -#ifndef NK_MEMSET -#define NK_MEMSET nk_memset -#endif -#ifndef NK_MEMCPY -#define NK_MEMCPY nk_memcopy -#endif -#ifndef NK_SQRT -#define NK_SQRT nk_sqrt -#endif -#ifndef NK_SIN -#define NK_SIN nk_sin -#endif -#ifndef NK_COS -#define NK_COS nk_cos -#endif -#ifndef NK_STRTOD -#define NK_STRTOD nk_strtod -#endif -#ifndef NK_DTOA -#define NK_DTOA nk_dtoa -#endif - -#define NK_DEFAULT (-1) - -#ifndef NK_VSNPRINTF -/* If your compiler does support `vsnprintf` I would highly recommend - * defining this to vsnprintf instead since `vsprintf` is basically - * unbelievable unsafe and should *NEVER* be used. But I have to support - * it since C89 only provides this unsafe version. */ - #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) ||\ - (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ - (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) ||\ - (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) ||\ - defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE) - #define NK_VSNPRINTF(s,n,f,a) vsnprintf(s,n,f,a) - #else - #define NK_VSNPRINTF(s,n,f,a) vsprintf(s,f,a) - #endif -#endif - -#define NK_SCHAR_MIN (-127) -#define NK_SCHAR_MAX 127 -#define NK_UCHAR_MIN 0 -#define NK_UCHAR_MAX 256 -#define NK_SSHORT_MIN (-32767) -#define NK_SSHORT_MAX 32767 -#define NK_USHORT_MIN 0 -#define NK_USHORT_MAX 65535 -#define NK_SINT_MIN (-2147483647) -#define NK_SINT_MAX 2147483647 -#define NK_UINT_MIN 0 -#define NK_UINT_MAX 4294967295u - -/* Make sure correct type size: - * This will fire with a negative subscript error if the type sizes - * are set incorrectly by the compiler, and compile out if not */ -NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*)); -NK_STATIC_ASSERT(sizeof(nk_ptr) == sizeof(void*)); -NK_STATIC_ASSERT(sizeof(nk_flags) >= 4); -NK_STATIC_ASSERT(sizeof(nk_rune) >= 4); -NK_STATIC_ASSERT(sizeof(nk_ushort) == 2); -NK_STATIC_ASSERT(sizeof(nk_short) == 2); -NK_STATIC_ASSERT(sizeof(nk_uint) == 4); -NK_STATIC_ASSERT(sizeof(nk_int) == 4); -NK_STATIC_ASSERT(sizeof(nk_byte) == 1); - -NK_GLOBAL const struct nk_rect nk_null_rect = {-8192.0f, -8192.0f, 16384, 16384}; -#define NK_FLOAT_PRECISION 0.00000000000001 - -NK_GLOBAL const struct nk_color nk_red = {255,0,0,255}; -NK_GLOBAL const struct nk_color nk_green = {0,255,0,255}; -NK_GLOBAL const struct nk_color nk_blue = {0,0,255,255}; -NK_GLOBAL const struct nk_color nk_white = {255,255,255,255}; -NK_GLOBAL const struct nk_color nk_black = {0,0,0,255}; -NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255}; - -/* - * ============================================================== - * - * MATH - * - * =============================================================== - */ -/* Since nuklear is supposed to work on all systems providing floating point - math without any dependencies I also had to implement my own math functions - for sqrt, sin and cos. Since the actual highly accurate implementations for - the standard library functions are quite complex and I do not need high - precision for my use cases I use approximations. - - Sqrt - ---- - For square root nuklear uses the famous fast inverse square root: - https://en.wikipedia.org/wiki/Fast_inverse_square_root with - slightly tweaked magic constant. While on todays hardware it is - probably not faster it is still fast and accurate enough for - nuklear's use cases. IMPORTANT: this requires float format IEEE 754 - - Sine/Cosine - ----------- - All constants inside both function are generated Remez's minimax - approximations for value range 0...2*PI. The reason why I decided to - approximate exactly that range is that nuklear only needs sine and - cosine to generate circles which only requires that exact range. - In addition I used Remez instead of Taylor for additional precision: - www.lolengine.net/blog/2011/12/21/better-function-approximatations. - - The tool I used to generate constants for both sine and cosine - (it can actually approximate a lot more functions) can be - found here: www.lolengine.net/wiki/oss/lolremez -*/ -NK_INTERN float -nk_inv_sqrt(float number) -{ - float x2; - const float threehalfs = 1.5f; - union {nk_uint i; float f;} conv = {0}; - conv.f = number; - x2 = number * 0.5f; - conv.i = 0x5f375A84 - (conv.i >> 1); - conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f)); - return conv.f; -} - -NK_INTERN float -nk_sqrt(float x) -{ - return x * nk_inv_sqrt(x); -} - -NK_INTERN float -nk_sin(float x) -{ - NK_STORAGE const float a0 = +1.91059300966915117e-31f; - NK_STORAGE const float a1 = +1.00086760103908896f; - NK_STORAGE const float a2 = -1.21276126894734565e-2f; - NK_STORAGE const float a3 = -1.38078780785773762e-1f; - NK_STORAGE const float a4 = -2.67353392911981221e-2f; - NK_STORAGE const float a5 = +2.08026600266304389e-2f; - NK_STORAGE const float a6 = -3.03996055049204407e-3f; - NK_STORAGE const float a7 = +1.38235642404333740e-4f; - return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7)))))); -} - -NK_INTERN float -nk_cos(float x) -{ - NK_STORAGE const float a0 = +1.00238601909309722f; - NK_STORAGE const float a1 = -3.81919947353040024e-2f; - NK_STORAGE const float a2 = -3.94382342128062756e-1f; - NK_STORAGE const float a3 = -1.18134036025221444e-1f; - NK_STORAGE const float a4 = +1.07123798512170878e-1f; - NK_STORAGE const float a5 = -1.86637164165180873e-2f; - NK_STORAGE const float a6 = +9.90140908664079833e-4f; - NK_STORAGE const float a7 = -5.23022132118824778e-14f; - return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7)))))); -} - -NK_INTERN nk_uint -nk_round_up_pow2(nk_uint v) -{ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; -} - -NK_API struct nk_rect -nk_get_null_rect(void) -{ - return nk_null_rect; -} - -NK_API struct nk_rect -nk_rect(float x, float y, float w, float h) -{ - struct nk_rect r; - r.x = x; r.y = y; - r.w = w; r.h = h; - return r; -} - -NK_API struct nk_rect -nk_recti(int x, int y, int w, int h) -{ - struct nk_rect r; - r.x = (float)x; - r.y = (float)y; - r.w = (float)w; - r.h = (float)h; - return r; -} - -NK_API struct nk_rect -nk_recta(struct nk_vec2 pos, struct nk_vec2 size) -{ - return nk_rect(pos.x, pos.y, size.x, size.y); -} - -NK_API struct nk_rect -nk_rectv(const float *r) -{ - return nk_rect(r[0], r[1], r[2], r[3]); -} - -NK_API struct nk_rect -nk_rectiv(const int *r) -{ - return nk_recti(r[0], r[1], r[2], r[3]); -} - -NK_API struct nk_vec2 -nk_rect_pos(struct nk_rect r) -{ - struct nk_vec2 ret; - ret.x = r.x; ret.y = r.y; - return ret; -} - -NK_API struct nk_vec2 -nk_rect_size(struct nk_rect r) -{ - struct nk_vec2 ret; - ret.x = r.w; ret.y = r.h; - return ret; -} - -NK_INTERN struct nk_rect -nk_shrink_rect(struct nk_rect r, float amount) -{ - struct nk_rect res; - r.w = NK_MAX(r.w, 2 * amount); - r.h = NK_MAX(r.h, 2 * amount); - res.x = r.x + amount; - res.y = r.y + amount; - res.w = r.w - 2 * amount; - res.h = r.h - 2 * amount; - return res; -} - -NK_INTERN struct nk_rect -nk_pad_rect(struct nk_rect r, struct nk_vec2 pad) -{ - r.w = NK_MAX(r.w, 2 * pad.x); - r.h = NK_MAX(r.h, 2 * pad.y); - r.x += pad.x; r.y += pad.y; - r.w -= 2 * pad.x; - r.h -= 2 * pad.y; - return r; -} - -NK_API struct nk_vec2 -nk_vec2(float x, float y) -{ - struct nk_vec2 ret; - ret.x = x; ret.y = y; - return ret; -} - -NK_API struct nk_vec2 -nk_vec2i(int x, int y) -{ - struct nk_vec2 ret; - ret.x = (float)x; - ret.y = (float)y; - return ret; -} - -NK_API struct nk_vec2 -nk_vec2v(const float *v) -{ - return nk_vec2(v[0], v[1]); -} - -NK_API struct nk_vec2 -nk_vec2iv(const int *v) -{ - return nk_vec2i(v[0], v[1]); -} - -/* - * ============================================================== - * - * UTIL - * - * =============================================================== - */ -NK_INTERN int nk_str_match_here(const char *regexp, const char *text); -NK_INTERN int nk_str_match_star(int c, const char *regexp, const char *text); -NK_INTERN int nk_is_lower(int c) {return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF);} -NK_INTERN int nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && c <= 0xDF);} -NK_INTERN int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;} -NK_INTERN int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;} - -NK_INTERN void* -nk_memcopy(void *dst0, const void *src0, nk_size length) -{ - nk_ptr t; - char *dst = (char*)dst0; - const char *src = (const char*)src0; - if (length == 0 || dst == src) - goto done; - - #define nk_word int - #define nk_wsize sizeof(nk_word) - #define nk_wmask (nk_wsize-1) - #define NK_TLOOP(s) if (t) NK_TLOOP1(s) - #define NK_TLOOP1(s) do { s; } while (--t) - - if (dst < src) { - t = (nk_ptr)src; /* only need low bits */ - if ((t | (nk_ptr)dst) & nk_wmask) { - if ((t ^ (nk_ptr)dst) & nk_wmask || length < nk_wsize) - t = length; - else - t = nk_wsize - (t & nk_wmask); - length -= t; - NK_TLOOP1(*dst++ = *src++); - } - t = length / nk_wsize; - NK_TLOOP(*(nk_word*)(void*)dst = *(const nk_word*)(const void*)src; - src += nk_wsize; dst += nk_wsize); - t = length & nk_wmask; - NK_TLOOP(*dst++ = *src++); - } else { - src += length; - dst += length; - t = (nk_ptr)src; - if ((t | (nk_ptr)dst) & nk_wmask) { - if ((t ^ (nk_ptr)dst) & nk_wmask || length <= nk_wsize) - t = length; - else - t &= nk_wmask; - length -= t; - NK_TLOOP1(*--dst = *--src); - } - t = length / nk_wsize; - NK_TLOOP(src -= nk_wsize; dst -= nk_wsize; - *(nk_word*)(void*)dst = *(const nk_word*)(const void*)src); - t = length & nk_wmask; - NK_TLOOP(*--dst = *--src); - } - #undef nk_word - #undef nk_wsize - #undef nk_wmask - #undef NK_TLOOP - #undef NK_TLOOP1 -done: - return (dst0); -} - -NK_INTERN void -nk_memset(void *ptr, int c0, nk_size size) -{ - #define nk_word unsigned - #define nk_wsize sizeof(nk_word) - #define nk_wmask (nk_wsize - 1) - nk_byte *dst = (nk_byte*)ptr; - unsigned c = 0; - nk_size t = 0; - - if ((c = (nk_byte)c0) != 0) { - c = (c << 8) | c; /* at least 16-bits */ - if (sizeof(unsigned int) > 2) - c = (c << 16) | c; /* at least 32-bits*/ - } - - /* too small of a word count */ - dst = (nk_byte*)ptr; - if (size < 3 * nk_wsize) { - while (size--) *dst++ = (nk_byte)c0; - return; - } - - /* align destination */ - if ((t = NK_PTR_TO_UINT(dst) & nk_wmask) != 0) { - t = nk_wsize -t; - size -= t; - do { - *dst++ = (nk_byte)c0; - } while (--t != 0); - } - - /* fill word */ - t = size / nk_wsize; - do { - *(nk_word*)((void*)dst) = c; - dst += nk_wsize; - } while (--t != 0); - - /* fill trailing bytes */ - t = (size & nk_wmask); - if (t != 0) { - do { - *dst++ = (nk_byte)c0; - } while (--t != 0); - } - - #undef nk_word - #undef nk_wsize - #undef nk_wmask -} - -NK_INTERN void -nk_zero(void *ptr, nk_size size) -{ - NK_ASSERT(ptr); - NK_MEMSET(ptr, 0, size); -} - -NK_API int -nk_strlen(const char *str) -{ - int siz = 0; - NK_ASSERT(str); - while (str && *str++ != '\0') siz++; - return siz; -} - -NK_API int -nk_strtoi(const char *str, const char **endptr) -{ - int neg = 1; - const char *p = str; - int value = 0; - - NK_ASSERT(str); - if (!str) return 0; - - /* skip whitespace */ - while (*p == ' ') p++; - if (*p == '-') { - neg = -1; - p++; - } - while (*p && *p >= '0' && *p <= '9') { - value = value * 10 + (int) (*p - '0'); - p++; - } - if (endptr) - *endptr = p; - return neg*value; -} - -NK_API double -nk_strtod(const char *str, const char **endptr) -{ - double m; - double neg = 1.0; - const char *p = str; - double value = 0; - double number = 0; - - NK_ASSERT(str); - if (!str) return 0; - - /* skip whitespace */ - while (*p == ' ') p++; - if (*p == '-') { - neg = -1.0; - p++; - } - - while (*p && *p != '.' && *p != 'e') { - value = value * 10.0 + (double) (*p - '0'); - p++; - } - - if (*p == '.') { - p++; - for(m = 0.1; *p && *p != 'e'; p++ ) { - value = value + (double) (*p - '0') * m; - m *= 0.1; - } - } - if (*p == 'e') { - int i, pow, div; - p++; - if (*p == '-') { - div = nk_true; - p++; - } else if (*p == '+') { - div = nk_false; - p++; - } else div = nk_false; - - for (pow = 0; *p; p++) - pow = pow * 10 + (int) (*p - '0'); - - for (m = 1.0, i = 0; i < pow; i++) - m *= 10.0; - - if (div) - value /= m; - else value *= m; - } - number = value * neg; - if (endptr) - *endptr = p; - return number; -} - -NK_API float -nk_strtof(const char *str, const char **endptr) -{ - float float_value; - double double_value; - double_value = NK_STRTOD(str, endptr); - float_value = (float)double_value; - return float_value; -} - -NK_API int -nk_stricmp(const char *s1, const char *s2) -{ - nk_int c1,c2,d; - do { - c1 = *s1++; - c2 = *s2++; - d = c1 - c2; - while (d) { - if (c1 <= 'Z' && c1 >= 'A') { - d += ('a' - 'A'); - if (!d) break; - } - if (c2 <= 'Z' && c2 >= 'A') { - d -= ('a' - 'A'); - if (!d) break; - } - return ((d >= 0) << 1) - 1; - } - } while (c1); - return 0; -} - -NK_API int -nk_stricmpn(const char *s1, const char *s2, int n) -{ - int c1,c2,d; - NK_ASSERT(n >= 0); - do { - c1 = *s1++; - c2 = *s2++; - if (!n--) return 0; - - d = c1 - c2; - while (d) { - if (c1 <= 'Z' && c1 >= 'A') { - d += ('a' - 'A'); - if (!d) break; - } - if (c2 <= 'Z' && c2 >= 'A') { - d -= ('a' - 'A'); - if (!d) break; - } - return ((d >= 0) << 1) - 1; - } - } while (c1); - return 0; -} - -NK_INTERN int -nk_str_match_here(const char *regexp, const char *text) -{ - if (regexp[0] == '\0') - return 1; - if (regexp[1] == '*') - return nk_str_match_star(regexp[0], regexp+2, text); - if (regexp[0] == '$' && regexp[1] == '\0') - return *text == '\0'; - if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text)) - return nk_str_match_here(regexp+1, text+1); - return 0; -} - -NK_INTERN int -nk_str_match_star(int c, const char *regexp, const char *text) -{ - do {/* a '* matches zero or more instances */ - if (nk_str_match_here(regexp, text)) - return 1; - } while (*text != '\0' && (*text++ == c || c == '.')); - return 0; -} - -NK_API int -nk_strfilter(const char *text, const char *regexp) -{ - /* - c matches any literal character c - . matches any single character - ^ matches the beginning of the input string - $ matches the end of the input string - * matches zero or more occurrences of the previous character*/ - if (regexp[0] == '^') - return nk_str_match_here(regexp+1, text); - do { /* must look even if string is empty */ - if (nk_str_match_here(regexp, text)) - return 1; - } while (*text++ != '\0'); - return 0; -} - -NK_API int -nk_strmatch_fuzzy_text(const char *str, int str_len, - const char *pattern, int *out_score) -{ - /* Returns true if each character in pattern is found sequentially within str - * if found then outScore is also set. Score value has no intrinsic meaning. - * Range varies with pattern. Can only compare scores with same search pattern. */ - - /* ------- scores --------- */ - /* bonus for adjacent matches */ - #define NK_ADJACENCY_BONUS 5 - /* bonus if match occurs after a separator */ - #define NK_SEPARATOR_BONUS 10 - /* bonus if match is uppercase and prev is lower */ - #define NK_CAMEL_BONUS 10 - /* penalty applied for every letter in str before the first match */ - #define NK_LEADING_LETTER_PENALTY (-3) - /* maximum penalty for leading letters */ - #define NK_MAX_LEADING_LETTER_PENALTY (-9) - /* penalty for every letter that doesn't matter */ - #define NK_UNMATCHED_LETTER_PENALTY (-1) - - /* loop variables */ - int score = 0; - char const * pattern_iter = pattern; - int str_iter = 0; - int prev_matched = nk_false; - int prev_lower = nk_false; - /* true so if first letter match gets separator bonus*/ - int prev_separator = nk_true; - - /* use "best" matched letter if multiple string letters match the pattern */ - char const * best_letter = 0; - int best_letter_score = 0; - - /* loop over strings */ - NK_ASSERT(str); - NK_ASSERT(pattern); - if (!str || !str_len || !pattern) return 0; - while (str_iter < str_len) - { - const char pattern_letter = *pattern_iter; - const char str_letter = str[str_iter]; - - int next_match = *pattern_iter != '\0' && - nk_to_lower(pattern_letter) == nk_to_lower(str_letter); - int rematch = best_letter && nk_to_upper(*best_letter) == nk_to_upper(str_letter); - - int advanced = next_match && best_letter; - int pattern_repeat = best_letter && *pattern_iter != '\0'; - pattern_repeat = pattern_repeat && - nk_to_lower(*best_letter) == nk_to_lower(pattern_letter); - - if (advanced || pattern_repeat) { - score += best_letter_score; - best_letter = 0; - best_letter_score = 0; - } - - if (next_match || rematch) - { - int new_score = 0; - /* Apply penalty for each letter before the first pattern match */ - if (pattern_iter == pattern) { - int count = (int)(&str[str_iter] - str); - int penalty = NK_LEADING_LETTER_PENALTY * count; - if (penalty < NK_MAX_LEADING_LETTER_PENALTY) - penalty = NK_MAX_LEADING_LETTER_PENALTY; - - score += penalty; - } - - /* apply bonus for consecutive bonuses */ - if (prev_matched) - new_score += NK_ADJACENCY_BONUS; - - /* apply bonus for matches after a separator */ - if (prev_separator) - new_score += NK_SEPARATOR_BONUS; - - /* apply bonus across camel case boundaries */ - if (prev_lower && nk_is_upper(str_letter)) - new_score += NK_CAMEL_BONUS; - - /* update pattern iter IFF the next pattern letter was matched */ - if (next_match) - ++pattern_iter; - - /* update best letter in str which may be for a "next" letter or a rematch */ - if (new_score >= best_letter_score) { - /* apply penalty for now skipped letter */ - if (best_letter != 0) - score += NK_UNMATCHED_LETTER_PENALTY; - - best_letter = &str[str_iter]; - best_letter_score = new_score; - } - prev_matched = nk_true; - } else { - score += NK_UNMATCHED_LETTER_PENALTY; - prev_matched = nk_false; - } - - /* separators should be more easily defined */ - prev_lower = nk_is_lower(str_letter) != 0; - prev_separator = str_letter == '_' || str_letter == ' '; - - ++str_iter; - } - - /* apply score for last match */ - if (best_letter) - score += best_letter_score; - - /* did not match full pattern */ - if (*pattern_iter != '\0') - return nk_false; - - if (out_score) - *out_score = score; - return nk_true; -} - -NK_API int -nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score) -{return nk_strmatch_fuzzy_text(str, nk_strlen(str), pattern, out_score);} - -NK_INTERN int -nk_string_float_limit(char *string, int prec) -{ - int dot = 0; - char *c = string; - while (*c) { - if (*c == '.') { - dot = 1; - c++; - continue; - } - if (dot == (prec+1)) { - *c = 0; - break; - } - if (dot > 0) dot++; - c++; - } - return (int)(c - string); -} - -NK_INTERN double -nk_pow(double x, int n) -{ - /* check the sign of n */ - double r = 1; - int plus = n >= 0; - n = (plus) ? n : -n; - while (n > 0) { - if ((n & 1) == 1) - r *= x; - n /= 2; - x *= x; - } - return plus ? r : 1.0 / r; -} - -NK_INTERN int -nk_ifloord(double x) -{ - x = (double)((int)x - ((x < 0.0) ? 1 : 0)); - return (int)x; -} - -NK_INTERN int -nk_ifloorf(float x) -{ - x = (float)((int)x - ((x < 0.0f) ? 1 : 0)); - return (int)x; -} - -NK_INTERN int -nk_iceilf(float x) -{ - if (x >= 0) { - int i = (int)x; - return i; - } else { - int t = (int)x; - float r = x - (float)t; - return (r > 0.0f) ? t+1: t; - } -} - -NK_INTERN int -nk_log10(double n) -{ - int neg; - int ret; - int exp = 0; - - neg = (n < 0) ? 1 : 0; - ret = (neg) ? (int)-n : (int)n; - while ((ret / 10) > 0) { - ret /= 10; - exp++; - } - if (neg) exp = -exp; - return exp; -} - -NK_INTERN void -nk_strrev_ascii(char *s) -{ - int len = nk_strlen(s); - int end = len / 2; - int i = 0; - char t; - for (; i < end; ++i) { - t = s[i]; - s[i] = s[len - 1 - i]; - s[len -1 - i] = t; - } -} - -NK_INTERN char* -nk_itoa(char *s, long n) -{ - long i = 0; - if (n == 0) { - s[i++] = '0'; - s[i] = 0; - return s; - } - if (n < 0) { - s[i++] = '-'; - n = -n; - } - while (n > 0) { - s[i++] = (char)('0' + (n % 10)); - n /= 10; - } - s[i] = 0; - if (s[0] == '-') - ++s; - - nk_strrev_ascii(s); - return s; -} - -NK_INTERN char* -nk_dtoa(char *s, double n) -{ - int useExp = 0; - int digit = 0, m = 0, m1 = 0; - char *c = s; - int neg = 0; - - NK_ASSERT(s); - if (!s) return 0; - - if (n == 0.0) { - s[0] = '0'; s[1] = '\0'; - return s; - } - - neg = (n < 0); - if (neg) n = -n; - - /* calculate magnitude */ - m = nk_log10(n); - useExp = (m >= 14 || (neg && m >= 9) || m <= -9); - if (neg) *(c++) = '-'; - - /* set up for scientific notation */ - if (useExp) { - if (m < 0) - m -= 1; - n = n / (double)nk_pow(10.0, m); - m1 = m; - m = 0; - } - if (m < 1.0) { - m = 0; - } - - /* convert the number */ - while (n > NK_FLOAT_PRECISION || m >= 0) { - double weight = nk_pow(10.0, m); - if (weight > 0) { - double t = (double)n / weight; - digit = nk_ifloord(t); - n -= ((double)digit * weight); - *(c++) = (char)('0' + (char)digit); - } - if (m == 0 && n > 0) - *(c++) = '.'; - m--; - } - - if (useExp) { - /* convert the exponent */ - int i, j; - *(c++) = 'e'; - if (m1 > 0) { - *(c++) = '+'; - } else { - *(c++) = '-'; - m1 = -m1; - } - m = 0; - while (m1 > 0) { - *(c++) = (char)('0' + (char)(m1 % 10)); - m1 /= 10; - m++; - } - c -= m; - for (i = 0, j = m-1; i= buf_size) break; - iter++; - - /* flag arguments */ - while (*iter) { - if (*iter == '-') flag |= NK_ARG_FLAG_LEFT; - else if (*iter == '+') flag |= NK_ARG_FLAG_PLUS; - else if (*iter == ' ') flag |= NK_ARG_FLAG_SPACE; - else if (*iter == '#') flag |= NK_ARG_FLAG_NUM; - else if (*iter == '0') flag |= NK_ARG_FLAG_ZERO; - else break; - iter++; - } - - /* width argument */ - width = NK_DEFAULT; - if (*iter >= '1' && *iter <= '9') { - const char *end; - width = nk_strtoi(iter, &end); - if (end == iter) - width = -1; - else iter = end; - } else if (*iter == '*') { - width = va_arg(args, int); - iter++; - } - - /* precision argument */ - precision = NK_DEFAULT; - if (*iter == '.') { - iter++; - if (*iter == '*') { - precision = va_arg(args, int); - iter++; - } else { - const char *end; - precision = nk_strtoi(iter, &end); - if (end == iter) - precision = -1; - else iter = end; - } - } - - /* length modifier */ - if (*iter == 'h') { - if (*(iter+1) == 'h') { - arg_type = NK_ARG_TYPE_CHAR; - iter++; - } else arg_type = NK_ARG_TYPE_SHORT; - iter++; - } else if (*iter == 'l') { - arg_type = NK_ARG_TYPE_LONG; - iter++; - } else arg_type = NK_ARG_TYPE_DEFAULT; - - /* specifier */ - if (*iter == '%') { - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_ASSERT(precision == NK_DEFAULT); - NK_ASSERT(width == NK_DEFAULT); - if (len < buf_size) - buf[len++] = '%'; - } else if (*iter == 's') { - /* string */ - const char *str = va_arg(args, const char*); - NK_ASSERT(str != buf && "buffer and argument are not allowed to overlap!"); - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_ASSERT(precision == NK_DEFAULT); - NK_ASSERT(width == NK_DEFAULT); - if (str == buf) return -1; - while (str && *str && len < buf_size) - buf[len++] = *str++; - } else if (*iter == 'n') { - /* current length callback */ - signed int *n = va_arg(args, int*); - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_ASSERT(precision == NK_DEFAULT); - NK_ASSERT(width == NK_DEFAULT); - if (n) *n = len; - } else if (*iter == 'c' || *iter == 'i' || *iter == 'd') { - /* signed integer */ - long value = 0; - const char *num_iter; - int num_len, num_print, padding; - int cur_precision = NK_MAX(precision, 1); - int cur_width = NK_MAX(width, 0); - - /* retrieve correct value type */ - if (arg_type == NK_ARG_TYPE_CHAR) - value = (signed char)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_SHORT) - value = (signed short)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_LONG) - value = va_arg(args, signed long); - else if (*iter == 'c') - value = (unsigned char)va_arg(args, int); - else value = va_arg(args, signed int); - - /* convert number to string */ - nk_itoa(number_buffer, value); - num_len = nk_strlen(number_buffer); - padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0); - if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE)) - padding = NK_MAX(padding-1, 0); - - /* fill left padding up to a total of `width` characters */ - if (!(flag & NK_ARG_FLAG_LEFT)) { - while (padding-- > 0 && (len < buf_size)) { - if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT)) - buf[len++] = '0'; - else buf[len++] = ' '; - } - } - - /* copy string value representation into buffer */ - if ((flag & NK_ARG_FLAG_PLUS) && value >= 0 && len < buf_size) - buf[len++] = '+'; - else if ((flag & NK_ARG_FLAG_SPACE) && value >= 0 && len < buf_size) - buf[len++] = ' '; - - /* fill up to precision number of digits with '0' */ - num_print = NK_MAX(cur_precision, num_len); - while (precision && (num_print > num_len) && (len < buf_size)) { - buf[len++] = '0'; - num_print--; - } - - /* copy string value representation into buffer */ - num_iter = number_buffer; - while (precision && *num_iter && len < buf_size) - buf[len++] = *num_iter++; - - /* fill right padding up to width characters */ - if (flag & NK_ARG_FLAG_LEFT) { - while ((padding-- > 0) && (len < buf_size)) - buf[len++] = ' '; - } - } else if (*iter == 'o' || *iter == 'x' || *iter == 'X' || *iter == 'u') { - /* unsigned integer */ - unsigned long value = 0; - int num_len = 0, num_print, padding = 0; - int cur_precision = NK_MAX(precision, 1); - int cur_width = NK_MAX(width, 0); - unsigned int base = (*iter == 'o') ? 8: (*iter == 'u')? 10: 16; - - /* print oct/hex/dec value */ - const char *upper_output_format = "0123456789ABCDEF"; - const char *lower_output_format = "0123456789abcdef"; - const char *output_format = (*iter == 'x') ? - lower_output_format: upper_output_format; - - /* retrieve correct value type */ - if (arg_type == NK_ARG_TYPE_CHAR) - value = (unsigned char)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_SHORT) - value = (unsigned short)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_LONG) - value = va_arg(args, unsigned long); - else value = va_arg(args, unsigned int); - - do { - /* convert decimal number into hex/oct number */ - int digit = output_format[value % base]; - if (num_len < NK_MAX_NUMBER_BUFFER) - number_buffer[num_len++] = (char)digit; - value /= base; - } while (value > 0); - - num_print = NK_MAX(cur_precision, num_len); - padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0); - if (flag & NK_ARG_FLAG_NUM) - padding = NK_MAX(padding-1, 0); - - /* fill left padding up to a total of `width` characters */ - if (!(flag & NK_ARG_FLAG_LEFT)) { - while ((padding-- > 0) && (len < buf_size)) { - if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT)) - buf[len++] = '0'; - else buf[len++] = ' '; - } - } - - /* fill up to precision number of digits */ - if (num_print && (flag & NK_ARG_FLAG_NUM)) { - if ((*iter == 'o') && (len < buf_size)) { - buf[len++] = '0'; - } else if ((*iter == 'x') && ((len+1) < buf_size)) { - buf[len++] = '0'; - buf[len++] = 'x'; - } else if ((*iter == 'X') && ((len+1) < buf_size)) { - buf[len++] = '0'; - buf[len++] = 'X'; - } - } - while (precision && (num_print > num_len) && (len < buf_size)) { - buf[len++] = '0'; - num_print--; - } - - /* reverse number direction */ - while (num_len > 0) { - if (precision && (len < buf_size)) - buf[len++] = number_buffer[num_len-1]; - num_len--; - } - - /* fill right padding up to width characters */ - if (flag & NK_ARG_FLAG_LEFT) { - while ((padding-- > 0) && (len < buf_size)) - buf[len++] = ' '; - } - } else if (*iter == 'f') { - /* floating point */ - const char *num_iter; - int cur_precision = (precision < 0) ? 6: precision; - int prefix, cur_width = NK_MAX(width, 0); - double value = va_arg(args, double); - int num_len = 0, frac_len = 0, dot = 0; - int padding = 0; - - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_DTOA(number_buffer, value); - num_len = nk_strlen(number_buffer); - - /* calculate padding */ - num_iter = number_buffer; - while (*num_iter && *num_iter != '.') - num_iter++; - - prefix = (*num_iter == '.')?(int)(num_iter - number_buffer)+1:0; - padding = NK_MAX(cur_width - (prefix + NK_MIN(cur_precision, num_len - prefix)) , 0); - if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE)) - padding = NK_MAX(padding-1, 0); - - /* fill left padding up to a total of `width` characters */ - if (!(flag & NK_ARG_FLAG_LEFT)) { - while (padding-- > 0 && (len < buf_size)) { - if (flag & NK_ARG_FLAG_ZERO) - buf[len++] = '0'; - else buf[len++] = ' '; - } - } - - /* copy string value representation into buffer */ - num_iter = number_buffer; - if ((flag & NK_ARG_FLAG_PLUS) && (value >= 0) && (len < buf_size)) - buf[len++] = '+'; - else if ((flag & NK_ARG_FLAG_SPACE) && (value >= 0) && (len < buf_size)) - buf[len++] = ' '; - while (*num_iter) { - if (dot) frac_len++; - if (len < buf_size) - buf[len++] = *num_iter; - if (*num_iter == '.') dot = 1; - if (frac_len >= cur_precision) break; - num_iter++; - } - - /* fill number up to precision */ - while (frac_len < cur_precision) { - if (!dot && len < buf_size) { - buf[len++] = '.'; - dot = 1; - } - if (len < buf_size) - buf[len++] = '0'; - frac_len++; - } - - /* fill right padding up to width characters */ - if (flag & NK_ARG_FLAG_LEFT) { - while ((padding-- > 0) && (len < buf_size)) - buf[len++] = ' '; - } - } else { - /* Specifier not supported: g,G,e,E,p,z */ - NK_ASSERT(0 && "specifier is not supported!"); - return result; - } - } - buf[(len >= buf_size)?(buf_size-1):len] = 0; - result = (len >= buf_size)?-1:len; - return result; -} -#endif - -NK_INTERN int -nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args) -{ - int result = -1; - NK_ASSERT(buf); - NK_ASSERT(buf_size); - if (!buf || !buf_size || !fmt) return 0; -#ifdef NK_INCLUDE_STANDARD_IO - result = NK_VSNPRINTF(buf, (nk_size)buf_size, fmt, args); - result = (result >= buf_size) ? -1: result; - buf[buf_size-1] = 0; -#else - result = nk_vsnprintf(buf, buf_size, fmt, args); -#endif - return result; -} -#endif - -NK_API nk_hash -nk_murmur_hash(const void * key, int len, nk_hash seed) -{ - /* 32-Bit MurmurHash3: https://code.google.com/p/smhasher/wiki/MurmurHash3*/ - #define NK_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r))) - union {const nk_uint *i; const nk_byte *b;} conv = {0}; - const nk_byte *data = (const nk_byte*)key; - const int nblocks = len/4; - nk_uint h1 = seed; - const nk_uint c1 = 0xcc9e2d51; - const nk_uint c2 = 0x1b873593; - const nk_byte *tail; - const nk_uint *blocks; - nk_uint k1; - int i; - - /* body */ - if (!key) return 0; - conv.b = (data + nblocks*4); - blocks = (const nk_uint*)conv.i; - for (i = -nblocks; i; ++i) { - k1 = blocks[i]; - k1 *= c1; - k1 = NK_ROTL(k1,15); - k1 *= c2; - - h1 ^= k1; - h1 = NK_ROTL(h1,13); - h1 = h1*5+0xe6546b64; - } - - /* tail */ - tail = (const nk_byte*)(data + nblocks*4); - k1 = 0; - switch (len & 3) { - case 3: k1 ^= (nk_uint)(tail[2] << 16); - case 2: k1 ^= (nk_uint)(tail[1] << 8u); - case 1: k1 ^= tail[0]; - k1 *= c1; - k1 = NK_ROTL(k1,15); - k1 *= c2; - h1 ^= k1; - default: break; - } - - /* finalization */ - h1 ^= (nk_uint)len; - /* fmix32 */ - h1 ^= h1 >> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >> 16; - - #undef NK_ROTL - return h1; -} - -#ifdef NK_INCLUDE_STANDARD_IO -NK_INTERN char* -nk_file_load(const char* path, nk_size* siz, struct nk_allocator *alloc) -{ - char *buf; - FILE *fd; - long ret; - - NK_ASSERT(path); - NK_ASSERT(siz); - NK_ASSERT(alloc); - if (!path || !siz || !alloc) - return 0; - - fd = fopen(path, "rb"); - if (!fd) return 0; - fseek(fd, 0, SEEK_END); - ret = ftell(fd); - if (ret < 0) { - fclose(fd); - return 0; - } - *siz = (nk_size)ret; - fseek(fd, 0, SEEK_SET); - buf = (char*)alloc->alloc(alloc->userdata,0, *siz); - NK_ASSERT(buf); - if (!buf) { - fclose(fd); - return 0; - } - *siz = (nk_size)fread(buf, *siz, 1, fd); - fclose(fd); - return buf; -} -#endif - -/* - * ============================================================== - * - * COLOR - * - * =============================================================== - */ -NK_INTERN int -nk_parse_hex(const char *p, int length) -{ - int i = 0; - int len = 0; - while (len < length) { - i <<= 4; - if (p[len] >= 'a' && p[len] <= 'f') - i += ((p[len] - 'a') + 10); - else if (p[len] >= 'A' && p[len] <= 'F') - i += ((p[len] - 'A') + 10); - else i += (p[len] - '0'); - len++; - } - return i; -} - -NK_API struct nk_color -nk_rgba(int r, int g, int b, int a) -{ - struct nk_color ret; - ret.r = (nk_byte)NK_CLAMP(0, r, 255); - ret.g = (nk_byte)NK_CLAMP(0, g, 255); - ret.b = (nk_byte)NK_CLAMP(0, b, 255); - ret.a = (nk_byte)NK_CLAMP(0, a, 255); - return ret; -} - -NK_API struct nk_color -nk_rgb_hex(const char *rgb) -{ - struct nk_color col; - const char *c = rgb; - if (*c == '#') c++; - col.r = (nk_byte)nk_parse_hex(c, 2); - col.g = (nk_byte)nk_parse_hex(c+2, 2); - col.b = (nk_byte)nk_parse_hex(c+4, 2); - col.a = 255; - return col; -} - -NK_API struct nk_color -nk_rgba_hex(const char *rgb) -{ - struct nk_color col; - const char *c = rgb; - if (*c == '#') c++; - col.r = (nk_byte)nk_parse_hex(c, 2); - col.g = (nk_byte)nk_parse_hex(c+2, 2); - col.b = (nk_byte)nk_parse_hex(c+4, 2); - col.a = (nk_byte)nk_parse_hex(c+6, 2); - return col; -} - -NK_API void -nk_color_hex_rgba(char *output, struct nk_color col) -{ - #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i)) - output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4); - output[1] = (char)NK_TO_HEX((col.r & 0x0F)); - output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4); - output[3] = (char)NK_TO_HEX((col.g & 0x0F)); - output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4); - output[5] = (char)NK_TO_HEX((col.b & 0x0F)); - output[6] = (char)NK_TO_HEX((col.a & 0xF0) >> 4); - output[7] = (char)NK_TO_HEX((col.a & 0x0F)); - output[8] = '\0'; - #undef NK_TO_HEX -} - -NK_API void -nk_color_hex_rgb(char *output, struct nk_color col) -{ - #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i)) - output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4); - output[1] = (char)NK_TO_HEX((col.r & 0x0F)); - output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4); - output[3] = (char)NK_TO_HEX((col.g & 0x0F)); - output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4); - output[5] = (char)NK_TO_HEX((col.b & 0x0F)); - output[6] = '\0'; - #undef NK_TO_HEX -} - -NK_API struct nk_color -nk_rgba_iv(const int *c) -{ - return nk_rgba(c[0], c[1], c[2], c[3]); -} - -NK_API struct nk_color -nk_rgba_bv(const nk_byte *c) -{ - return nk_rgba(c[0], c[1], c[2], c[3]); -} - -NK_API struct nk_color -nk_rgb(int r, int g, int b) -{ - struct nk_color ret; - ret.r = (nk_byte)NK_CLAMP(0, r, 255); - ret.g = (nk_byte)NK_CLAMP(0, g, 255); - ret.b = (nk_byte)NK_CLAMP(0, b, 255); - ret.a = (nk_byte)255; - return ret; -} - -NK_API struct nk_color -nk_rgb_iv(const int *c) -{ - return nk_rgb(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_rgb_bv(const nk_byte* c) -{ - return nk_rgb(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_rgba_u32(nk_uint in) -{ - struct nk_color ret; - ret.r = (in & 0xFF); - ret.g = ((in >> 8) & 0xFF); - ret.b = ((in >> 16) & 0xFF); - ret.a = (nk_byte)((in >> 24) & 0xFF); - return ret; -} - -NK_API struct nk_color -nk_rgba_f(float r, float g, float b, float a) -{ - struct nk_color ret; - ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f); - ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f); - ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f); - ret.a = (nk_byte)(NK_SATURATE(a) * 255.0f); - return ret; -} - -NK_API struct nk_color -nk_rgba_fv(const float *c) -{ - return nk_rgba_f(c[0], c[1], c[2], c[3]); -} - -NK_API struct nk_color -nk_rgb_f(float r, float g, float b) -{ - struct nk_color ret; - ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f); - ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f); - ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f); - ret.a = 255; - return ret; -} - -NK_API struct nk_color -nk_rgb_fv(const float *c) -{ - return nk_rgb_f(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_hsv(int h, int s, int v) -{ - return nk_hsva(h, s, v, 255); -} - -NK_API struct nk_color -nk_hsv_iv(const int *c) -{ - return nk_hsv(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_hsv_bv(const nk_byte *c) -{ - return nk_hsv(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_hsv_f(float h, float s, float v) -{ - return nk_hsva_f(h, s, v, 1.0f); -} - -NK_API struct nk_color -nk_hsv_fv(const float *c) -{ - return nk_hsv_f(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_hsva(int h, int s, int v, int a) -{ - float hf = ((float)NK_CLAMP(0, h, 255)) / 255.0f; - float sf = ((float)NK_CLAMP(0, s, 255)) / 255.0f; - float vf = ((float)NK_CLAMP(0, v, 255)) / 255.0f; - float af = ((float)NK_CLAMP(0, a, 255)) / 255.0f; - return nk_hsva_f(hf, sf, vf, af); -} - -NK_API struct nk_color -nk_hsva_iv(const int *c) -{ - return nk_hsva(c[0], c[1], c[2], c[3]); -} - -NK_API struct nk_color -nk_hsva_bv(const nk_byte *c) -{ - return nk_hsva(c[0], c[1], c[2], c[3]); -} - -NK_API struct nk_color -nk_hsva_f(float h, float s, float v, float a) -{ - struct nk_colorf out = {0,0,0,0}; - float p, q, t, f; - int i; - - if (s <= 0.0f) { - out.r = v; out.g = v; out.b = v; - return nk_rgb_f(out.r, out.g, out.b); - } - - h = h / (60.0f/360.0f); - i = (int)h; - f = h - (float)i; - p = v * (1.0f - s); - q = v * (1.0f - (s * f)); - t = v * (1.0f - s * (1.0f - f)); - - switch (i) { - case 0: default: out.r = v; out.g = t; out.b = p; break; - case 1: out.r = q; out.g = v; out.b = p; break; - case 2: out.r = p; out.g = v; out.b = t; break; - case 3: out.r = p; out.g = q; out.b = v; break; - case 4: out.r = t; out.g = p; out.b = v; break; - case 5: out.r = v; out.g = p; out.b = q; break; - } - return nk_rgba_f(out.r, out.g, out.b, a); -} - -NK_API struct nk_color -nk_hsva_fv(const float *c) -{ - return nk_hsva_f(c[0], c[1], c[2], c[3]); -} - -NK_API nk_uint -nk_color_u32(struct nk_color in) -{ - nk_uint out = (nk_uint)in.r; - out |= ((nk_uint)in.g << 8); - out |= ((nk_uint)in.b << 16); - out |= ((nk_uint)in.a << 24); - return out; -} - -NK_API void -nk_color_f(float *r, float *g, float *b, float *a, struct nk_color in) -{ - NK_STORAGE const float s = 1.0f/255.0f; - *r = (float)in.r * s; - *g = (float)in.g * s; - *b = (float)in.b * s; - *a = (float)in.a * s; -} - -NK_API void -nk_color_fv(float *c, struct nk_color in) -{ - nk_color_f(&c[0], &c[1], &c[2], &c[3], in); -} - -NK_API void -nk_color_d(double *r, double *g, double *b, double *a, struct nk_color in) -{ - NK_STORAGE const double s = 1.0/255.0; - *r = (double)in.r * s; - *g = (double)in.g * s; - *b = (double)in.b * s; - *a = (double)in.a * s; -} - -NK_API void -nk_color_dv(double *c, struct nk_color in) -{ - nk_color_d(&c[0], &c[1], &c[2], &c[3], in); -} - -NK_API void -nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color in) -{ - float a; - nk_color_hsva_f(out_h, out_s, out_v, &a, in); -} - -NK_API void -nk_color_hsv_fv(float *out, struct nk_color in) -{ - float a; - nk_color_hsva_f(&out[0], &out[1], &out[2], &a, in); -} - -NK_API void -nk_color_hsva_f(float *out_h, float *out_s, - float *out_v, float *out_a, struct nk_color in) -{ - float chroma; - float K = 0.0f; - float r,g,b,a; - - nk_color_f(&r,&g,&b,&a, in); - if (g < b) { - const float t = g; g = b; b = t; - K = -1.f; - } - if (r < g) { - const float t = r; r = g; g = t; - K = -2.f/6.0f - K; - } - chroma = r - ((g < b) ? g: b); - *out_h = NK_ABS(K + (g - b)/(6.0f * chroma + 1e-20f)); - *out_s = chroma / (r + 1e-20f); - *out_v = r; - *out_a = (float)in.a / 255.0f; -} - -NK_API void -nk_color_hsva_fv(float *out, struct nk_color in) -{ - nk_color_hsva_f(&out[0], &out[1], &out[2], &out[3], in); -} - -NK_API void -nk_color_hsva_i(int *out_h, int *out_s, int *out_v, - int *out_a, struct nk_color in) -{ - float h,s,v,a; - nk_color_hsva_f(&h, &s, &v, &a, in); - *out_h = (nk_byte)(h * 255.0f); - *out_s = (nk_byte)(s * 255.0f); - *out_v = (nk_byte)(v * 255.0f); - *out_a = (nk_byte)(a * 255.0f); -} - -NK_API void -nk_color_hsva_iv(int *out, struct nk_color in) -{ - nk_color_hsva_i(&out[0], &out[1], &out[2], &out[3], in); -} - -NK_API void -nk_color_hsva_bv(nk_byte *out, struct nk_color in) -{ - int tmp[4]; - nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); - out[0] = (nk_byte)tmp[0]; - out[1] = (nk_byte)tmp[1]; - out[2] = (nk_byte)tmp[2]; - out[3] = (nk_byte)tmp[3]; -} - -NK_API void -nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color in) -{ - int tmp[4]; - nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); - *h = (nk_byte)tmp[0]; - *s = (nk_byte)tmp[1]; - *v = (nk_byte)tmp[2]; - *a = (nk_byte)tmp[3]; -} - -NK_API void -nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color in) -{ - int a; - nk_color_hsva_i(out_h, out_s, out_v, &a, in); -} - -NK_API void -nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color in) -{ - int tmp[4]; - nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); - *out_h = (nk_byte)tmp[0]; - *out_s = (nk_byte)tmp[1]; - *out_v = (nk_byte)tmp[2]; -} - -NK_API void -nk_color_hsv_iv(int *out, struct nk_color in) -{ - nk_color_hsv_i(&out[0], &out[1], &out[2], in); -} - -NK_API void -nk_color_hsv_bv(nk_byte *out, struct nk_color in) -{ - int tmp[4]; - nk_color_hsv_i(&tmp[0], &tmp[1], &tmp[2], in); - out[0] = (nk_byte)tmp[0]; - out[1] = (nk_byte)tmp[1]; - out[2] = (nk_byte)tmp[2]; -} -/* - * ============================================================== - * - * IMAGE - * - * =============================================================== - */ -NK_API nk_handle -nk_handle_ptr(void *ptr) -{ - nk_handle handle = {0}; - handle.ptr = ptr; - return handle; -} - -NK_API nk_handle -nk_handle_id(int id) -{ - nk_handle handle; - nk_zero_struct(handle); - handle.id = id; - return handle; -} - -NK_API struct nk_image -nk_subimage_ptr(void *ptr, unsigned short w, unsigned short h, struct nk_rect r) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle.ptr = ptr; - s.w = w; s.h = h; - s.region[0] = (unsigned short)r.x; - s.region[1] = (unsigned short)r.y; - s.region[2] = (unsigned short)r.w; - s.region[3] = (unsigned short)r.h; - return s; -} - -NK_API struct nk_image -nk_subimage_id(int id, unsigned short w, unsigned short h, struct nk_rect r) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle.id = id; - s.w = w; s.h = h; - s.region[0] = (unsigned short)r.x; - s.region[1] = (unsigned short)r.y; - s.region[2] = (unsigned short)r.w; - s.region[3] = (unsigned short)r.h; - return s; -} - -NK_API struct nk_image -nk_subimage_handle(nk_handle handle, unsigned short w, unsigned short h, - struct nk_rect r) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle = handle; - s.w = w; s.h = h; - s.region[0] = (unsigned short)r.x; - s.region[1] = (unsigned short)r.y; - s.region[2] = (unsigned short)r.w; - s.region[3] = (unsigned short)r.h; - return s; -} - -NK_API struct nk_image -nk_image_handle(nk_handle handle) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle = handle; - s.w = 0; s.h = 0; - s.region[0] = 0; - s.region[1] = 0; - s.region[2] = 0; - s.region[3] = 0; - return s; -} - -NK_API struct nk_image -nk_image_ptr(void *ptr) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - NK_ASSERT(ptr); - s.handle.ptr = ptr; - s.w = 0; s.h = 0; - s.region[0] = 0; - s.region[1] = 0; - s.region[2] = 0; - s.region[3] = 0; - return s; -} - -NK_API struct nk_image -nk_image_id(int id) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle.id = id; - s.w = 0; s.h = 0; - s.region[0] = 0; - s.region[1] = 0; - s.region[2] = 0; - s.region[3] = 0; - return s; -} - -NK_API int -nk_image_is_subimage(const struct nk_image* img) -{ - NK_ASSERT(img); - return !(img->w == 0 && img->h == 0); -} - -NK_INTERN void -nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0, - float x1, float y1) -{ - NK_ASSERT(a); - NK_ASSERT(clip); - clip->x = NK_MAX(a->x, x0); - clip->y = NK_MAX(a->y, y0); - clip->w = NK_MIN(a->x + a->w, x1) - clip->x; - clip->h = NK_MIN(a->y + a->h, y1) - clip->y; - clip->w = NK_MAX(0, clip->w); - clip->h = NK_MAX(0, clip->h); -} - -NK_API void -nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, - float pad_x, float pad_y, enum nk_heading direction) -{ - float w_half, h_half; - NK_ASSERT(result); - - r.w = NK_MAX(2 * pad_x, r.w); - r.h = NK_MAX(2 * pad_y, r.h); - r.w = r.w - 2 * pad_x; - r.h = r.h - 2 * pad_y; - - r.x = r.x + pad_x; - r.y = r.y + pad_y; - - w_half = r.w / 2.0f; - h_half = r.h / 2.0f; - - if (direction == NK_UP) { - result[0] = nk_vec2(r.x + w_half, r.y); - result[1] = nk_vec2(r.x + r.w, r.y + r.h); - result[2] = nk_vec2(r.x, r.y + r.h); - } else if (direction == NK_RIGHT) { - result[0] = nk_vec2(r.x, r.y); - result[1] = nk_vec2(r.x + r.w, r.y + h_half); - result[2] = nk_vec2(r.x, r.y + r.h); - } else if (direction == NK_DOWN) { - result[0] = nk_vec2(r.x, r.y); - result[1] = nk_vec2(r.x + r.w, r.y); - result[2] = nk_vec2(r.x + w_half, r.y + r.h); - } else { - result[0] = nk_vec2(r.x, r.y + h_half); - result[1] = nk_vec2(r.x + r.w, r.y); - result[2] = nk_vec2(r.x + r.w, r.y + r.h); - } -} - -NK_INTERN int -nk_text_clamp(const struct nk_user_font *font, const char *text, - int text_len, float space, int *glyphs, float *text_width, - nk_rune *sep_list, int sep_count) -{ - int i = 0; - int glyph_len = 0; - float last_width = 0; - nk_rune unicode = 0; - float width = 0; - int len = 0; - int g = 0; - float s; - - int sep_len = 0; - int sep_g = 0; - float sep_width = 0; - sep_count = NK_MAX(sep_count,0); - - glyph_len = nk_utf_decode(text, &unicode, text_len); - while (glyph_len && (width < space) && (len < text_len)) { - len += glyph_len; - s = font->width(font->userdata, font->height, text, len); - for (i = 0; i < sep_count; ++i) { - if (unicode != sep_list[i]) continue; - sep_width = last_width = width; - sep_g = g+1; - sep_len = len; - break; - } - if (i == sep_count){ - last_width = sep_width = width; - sep_g = g+1; - } - width = s; - glyph_len = nk_utf_decode(&text[len], &unicode, text_len - len); - g++; - } - if (len >= text_len) { - *glyphs = g; - *text_width = last_width; - return len; - } else { - *glyphs = sep_g; - *text_width = sep_width; - return (!sep_len) ? len: sep_len; - } -} - -enum {NK_DO_NOT_STOP_ON_NEW_LINE, NK_STOP_ON_NEW_LINE}; -NK_INTERN struct nk_vec2 -nk_text_calculate_text_bounds(const struct nk_user_font *font, - const char *begin, int byte_len, float row_height, const char **remaining, - struct nk_vec2 *out_offset, int *glyphs, int op) -{ - float line_height = row_height; - struct nk_vec2 text_size = nk_vec2(0,0); - float line_width = 0.0f; - - float glyph_width; - int glyph_len = 0; - nk_rune unicode = 0; - int text_len = 0; - if (!begin || byte_len <= 0 || !font) - return nk_vec2(0,row_height); - - glyph_len = nk_utf_decode(begin, &unicode, byte_len); - if (!glyph_len) return text_size; - glyph_width = font->width(font->userdata, font->height, begin, glyph_len); - - *glyphs = 0; - while ((text_len < byte_len) && glyph_len) { - if (unicode == '\n') { - text_size.x = NK_MAX(text_size.x, line_width); - text_size.y += line_height; - line_width = 0; - *glyphs+=1; - if (op == NK_STOP_ON_NEW_LINE) - break; - - text_len++; - glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); - continue; - } - - if (unicode == '\r') { - text_len++; - *glyphs+=1; - glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); - continue; - } - - *glyphs = *glyphs + 1; - text_len += glyph_len; - line_width += (float)glyph_width; - glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); - glyph_width = font->width(font->userdata, font->height, begin+text_len, glyph_len); - continue; - } - - if (text_size.x < line_width) - text_size.x = line_width; - if (out_offset) - *out_offset = nk_vec2(line_width, text_size.y + line_height); - if (line_width > 0 || text_size.y == 0.0f) - text_size.y += line_height; - if (remaining) - *remaining = begin+text_len; - return text_size; -} - -/* ============================================================== - * - * UTF-8 - * - * ===============================================================*/ -NK_GLOBAL const nk_byte nk_utfbyte[NK_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; -NK_GLOBAL const nk_byte nk_utfmask[NK_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; -NK_GLOBAL const nk_uint nk_utfmin[NK_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x10000}; -NK_GLOBAL const nk_uint nk_utfmax[NK_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; - -NK_INTERN int -nk_utf_validate(nk_rune *u, int i) -{ - NK_ASSERT(u); - if (!u) return 0; - if (!NK_BETWEEN(*u, nk_utfmin[i], nk_utfmax[i]) || - NK_BETWEEN(*u, 0xD800, 0xDFFF)) - *u = NK_UTF_INVALID; - for (i = 1; *u > nk_utfmax[i]; ++i); - return i; -} - -NK_INTERN nk_rune -nk_utf_decode_byte(char c, int *i) -{ - NK_ASSERT(i); - if (!i) return 0; - for(*i = 0; *i < (int)NK_LEN(nk_utfmask); ++(*i)) { - if (((nk_byte)c & nk_utfmask[*i]) == nk_utfbyte[*i]) - return (nk_byte)(c & ~nk_utfmask[*i]); - } - return 0; -} - -NK_API int -nk_utf_decode(const char *c, nk_rune *u, int clen) -{ - int i, j, len, type=0; - nk_rune udecoded; - - NK_ASSERT(c); - NK_ASSERT(u); - - if (!c || !u) return 0; - if (!clen) return 0; - *u = NK_UTF_INVALID; - - udecoded = nk_utf_decode_byte(c[0], &len); - if (!NK_BETWEEN(len, 1, NK_UTF_SIZE)) - return 1; - - for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { - udecoded = (udecoded << 6) | nk_utf_decode_byte(c[i], &type); - if (type != 0) - return j; - } - if (j < len) - return 0; - *u = udecoded; - nk_utf_validate(u, len); - return len; -} - -NK_INTERN char -nk_utf_encode_byte(nk_rune u, int i) -{ - return (char)((nk_utfbyte[i]) | ((nk_byte)u & ~nk_utfmask[i])); -} - -NK_API int -nk_utf_encode(nk_rune u, char *c, int clen) -{ - int len, i; - len = nk_utf_validate(&u, 0); - if (clen < len || !len || len > NK_UTF_SIZE) - return 0; - - for (i = len - 1; i != 0; --i) { - c[i] = nk_utf_encode_byte(u, 0); - u >>= 6; - } - c[0] = nk_utf_encode_byte(u, len); - return len; -} - -NK_API int -nk_utf_len(const char *str, int len) -{ - const char *text; - int glyphs = 0; - int text_len; - int glyph_len; - int src_len = 0; - nk_rune unicode; - - NK_ASSERT(str); - if (!str || !len) return 0; - - text = str; - text_len = len; - glyph_len = nk_utf_decode(text, &unicode, text_len); - while (glyph_len && src_len < len) { - glyphs++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, &unicode, text_len - src_len); - } - return glyphs; -} - -NK_API const char* -nk_utf_at(const char *buffer, int length, int index, - nk_rune *unicode, int *len) -{ - int i = 0; - int src_len = 0; - int glyph_len = 0; - const char *text; - int text_len; - - NK_ASSERT(buffer); - NK_ASSERT(unicode); - NK_ASSERT(len); - - if (!buffer || !unicode || !len) return 0; - if (index < 0) { - *unicode = NK_UTF_INVALID; - *len = 0; - return 0; - } - - text = buffer; - text_len = length; - glyph_len = nk_utf_decode(text, unicode, text_len); - while (glyph_len) { - if (i == index) { - *len = glyph_len; - break; - } - - i++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); - } - if (i != index) return 0; - return buffer + src_len; -} - -/* ============================================================== - * - * BUFFER - * - * ===============================================================*/ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_INTERN void* nk_malloc(nk_handle unused, void *old,nk_size size) -{NK_UNUSED(unused); NK_UNUSED(old); return malloc(size);} -NK_INTERN void nk_mfree(nk_handle unused, void *ptr) -{NK_UNUSED(unused); free(ptr);} - -NK_API void -nk_buffer_init_default(struct nk_buffer *buffer) -{ - struct nk_allocator alloc; - alloc.userdata.ptr = 0; - alloc.alloc = nk_malloc; - alloc.free = nk_mfree; - nk_buffer_init(buffer, &alloc, NK_BUFFER_DEFAULT_INITIAL_SIZE); -} -#endif - -NK_API void -nk_buffer_init(struct nk_buffer *b, const struct nk_allocator *a, - nk_size initial_size) -{ - NK_ASSERT(b); - NK_ASSERT(a); - NK_ASSERT(initial_size); - if (!b || !a || !initial_size) return; - - nk_zero(b, sizeof(*b)); - b->type = NK_BUFFER_DYNAMIC; - b->memory.ptr = a->alloc(a->userdata,0, initial_size); - b->memory.size = initial_size; - b->size = initial_size; - b->grow_factor = 2.0f; - b->pool = *a; -} - -NK_API void -nk_buffer_init_fixed(struct nk_buffer *b, void *m, nk_size size) -{ - NK_ASSERT(b); - NK_ASSERT(m); - NK_ASSERT(size); - if (!b || !m || !size) return; - - nk_zero(b, sizeof(*b)); - b->type = NK_BUFFER_FIXED; - b->memory.ptr = m; - b->memory.size = size; - b->size = size; -} - -NK_INTERN void* -nk_buffer_align(void *unaligned, nk_size align, nk_size *alignment, - enum nk_buffer_allocation_type type) -{ - void *memory = 0; - switch (type) { - default: - case NK_BUFFER_MAX: - case NK_BUFFER_FRONT: - if (align) { - memory = NK_ALIGN_PTR(unaligned, align); - *alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned); - } else { - memory = unaligned; - *alignment = 0; - } - break; - case NK_BUFFER_BACK: - if (align) { - memory = NK_ALIGN_PTR_BACK(unaligned, align); - *alignment = (nk_size)((nk_byte*)unaligned - (nk_byte*)memory); - } else { - memory = unaligned; - *alignment = 0; - } - break; - } - return memory; -} - -NK_INTERN void* -nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size) -{ - void *temp; - nk_size buffer_size; - - NK_ASSERT(b); - NK_ASSERT(size); - if (!b || !size || !b->pool.alloc || !b->pool.free) - return 0; - - buffer_size = b->memory.size; - temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity); - NK_ASSERT(temp); - if (!temp) return 0; - - *size = capacity; - if (temp != b->memory.ptr) { - NK_MEMCPY(temp, b->memory.ptr, buffer_size); - b->pool.free(b->pool.userdata, b->memory.ptr); - } - - if (b->size == buffer_size) { - /* no back buffer so just set correct size */ - b->size = capacity; - return temp; - } else { - /* copy back buffer to the end of the new buffer */ - void *dst, *src; - nk_size back_size; - back_size = buffer_size - b->size; - dst = nk_ptr_add(void, temp, capacity - back_size); - src = nk_ptr_add(void, temp, b->size); - NK_MEMCPY(dst, src, back_size); - b->size = capacity - back_size; - } - return temp; -} - -NK_INTERN void* -nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, - nk_size size, nk_size align) -{ - int full; - nk_size alignment; - void *unaligned; - void *memory; - - NK_ASSERT(b); - NK_ASSERT(size); - if (!b || !size) return 0; - b->needed += size; - - /* calculate total size with needed alignment + size */ - if (type == NK_BUFFER_FRONT) - unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated); - else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size); - memory = nk_buffer_align(unaligned, align, &alignment, type); - - /* check if buffer has enough memory*/ - if (type == NK_BUFFER_FRONT) - full = ((b->allocated + size + alignment) > b->size); - else full = ((b->size - NK_MIN(b->size,(size + alignment))) <= b->allocated); - - if (full) { - nk_size capacity; - if (b->type != NK_BUFFER_DYNAMIC) - return 0; - NK_ASSERT(b->pool.alloc && b->pool.free); - if (b->type != NK_BUFFER_DYNAMIC || !b->pool.alloc || !b->pool.free) - return 0; - - /* buffer is full so allocate bigger buffer if dynamic */ - capacity = (nk_size)((float)b->memory.size * b->grow_factor); - capacity = NK_MAX(capacity, nk_round_up_pow2((nk_uint)(b->allocated + size))); - b->memory.ptr = nk_buffer_realloc(b, capacity, &b->memory.size); - if (!b->memory.ptr) return 0; - - /* align newly allocated pointer */ - if (type == NK_BUFFER_FRONT) - unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated); - else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size); - memory = nk_buffer_align(unaligned, align, &alignment, type); - } - if (type == NK_BUFFER_FRONT) - b->allocated += size + alignment; - else b->size -= (size + alignment); - b->needed += alignment; - b->calls++; - return memory; -} - -NK_API void -nk_buffer_push(struct nk_buffer *b, enum nk_buffer_allocation_type type, - const void *memory, nk_size size, nk_size align) -{ - void *mem = nk_buffer_alloc(b, type, size, align); - if (!mem) return; - NK_MEMCPY(mem, memory, size); -} - -NK_API void -nk_buffer_mark(struct nk_buffer *buffer, enum nk_buffer_allocation_type type) -{ - NK_ASSERT(buffer); - if (!buffer) return; - buffer->marker[type].active = nk_true; - if (type == NK_BUFFER_BACK) - buffer->marker[type].offset = buffer->size; - else buffer->marker[type].offset = buffer->allocated; -} - -NK_API void -nk_buffer_reset(struct nk_buffer *buffer, enum nk_buffer_allocation_type type) -{ - NK_ASSERT(buffer); - if (!buffer) return; - if (type == NK_BUFFER_BACK) { - /* reset back buffer either back to marker or empty */ - buffer->needed -= (buffer->memory.size - buffer->marker[type].offset); - if (buffer->marker[type].active) - buffer->size = buffer->marker[type].offset; - else buffer->size = buffer->memory.size; - buffer->marker[type].active = nk_false; - } else { - /* reset front buffer either back to back marker or empty */ - buffer->needed -= (buffer->allocated - buffer->marker[type].offset); - if (buffer->marker[type].active) - buffer->allocated = buffer->marker[type].offset; - else buffer->allocated = 0; - buffer->marker[type].active = nk_false; - } -} - -NK_API void -nk_buffer_clear(struct nk_buffer *b) -{ - NK_ASSERT(b); - if (!b) return; - b->allocated = 0; - b->size = b->memory.size; - b->calls = 0; - b->needed = 0; -} - -NK_API void -nk_buffer_free(struct nk_buffer *b) -{ - NK_ASSERT(b); - if (!b || !b->memory.ptr) return; - if (b->type == NK_BUFFER_FIXED) return; - if (!b->pool.free) return; - NK_ASSERT(b->pool.free); - b->pool.free(b->pool.userdata, b->memory.ptr); -} - -NK_API void -nk_buffer_info(struct nk_memory_status *s, struct nk_buffer *b) -{ - NK_ASSERT(b); - NK_ASSERT(s); - if (!s || !b) return; - s->allocated = b->allocated; - s->size = b->memory.size; - s->needed = b->needed; - s->memory = b->memory.ptr; - s->calls = b->calls; -} - -NK_API void* -nk_buffer_memory(struct nk_buffer *buffer) -{ - NK_ASSERT(buffer); - if (!buffer) return 0; - return buffer->memory.ptr; -} - -NK_API const void* -nk_buffer_memory_const(const struct nk_buffer *buffer) -{ - NK_ASSERT(buffer); - if (!buffer) return 0; - return buffer->memory.ptr; -} - -NK_API nk_size -nk_buffer_total(struct nk_buffer *buffer) -{ - NK_ASSERT(buffer); - if (!buffer) return 0; - return buffer->memory.size; -} - -/* - * ============================================================== - * - * STRING - * - * =============================================================== - */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void -nk_str_init_default(struct nk_str *str) -{ - struct nk_allocator alloc; - alloc.userdata.ptr = 0; - alloc.alloc = nk_malloc; - alloc.free = nk_mfree; - nk_buffer_init(&str->buffer, &alloc, 32); - str->len = 0; -} -#endif - -NK_API void -nk_str_init(struct nk_str *str, const struct nk_allocator *alloc, nk_size size) -{ - nk_buffer_init(&str->buffer, alloc, size); - str->len = 0; -} - -NK_API void -nk_str_init_fixed(struct nk_str *str, void *memory, nk_size size) -{ - nk_buffer_init_fixed(&str->buffer, memory, size); - str->len = 0; -} - -NK_API int -nk_str_append_text_char(struct nk_str *s, const char *str, int len) -{ - char *mem; - NK_ASSERT(s); - NK_ASSERT(str); - if (!s || !str || !len) return 0; - mem = (char*)nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0); - if (!mem) return 0; - NK_MEMCPY(mem, str, (nk_size)len * sizeof(char)); - s->len += nk_utf_len(str, len); - return len; -} - -NK_API int -nk_str_append_str_char(struct nk_str *s, const char *str) -{ - return nk_str_append_text_char(s, str, nk_strlen(str)); -} - -NK_API int -nk_str_append_text_utf8(struct nk_str *str, const char *text, int len) -{ - int i = 0; - int byte_len = 0; - nk_rune unicode; - if (!str || !text || !len) return 0; - for (i = 0; i < len; ++i) - byte_len += nk_utf_decode(text+byte_len, &unicode, 4); - nk_str_append_text_char(str, text, byte_len); - return len; -} - -NK_API int -nk_str_append_str_utf8(struct nk_str *str, const char *text) -{ - int runes = 0; - int byte_len = 0; - int num_runes = 0; - int glyph_len = 0; - nk_rune unicode; - if (!str || !text) return 0; - - glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4); - while (unicode != '\0' && glyph_len) { - glyph_len = nk_utf_decode(text+byte_len, &unicode, 4); - byte_len += glyph_len; - num_runes++; - } - nk_str_append_text_char(str, text, byte_len); - return runes; -} - -NK_API int -nk_str_append_text_runes(struct nk_str *str, const nk_rune *text, int len) -{ - int i = 0; - int byte_len = 0; - nk_glyph glyph; - - NK_ASSERT(str); - if (!str || !text || !len) return 0; - for (i = 0; i < len; ++i) { - byte_len = nk_utf_encode(text[i], glyph, NK_UTF_SIZE); - if (!byte_len) break; - nk_str_append_text_char(str, glyph, byte_len); - } - return len; -} - -NK_API int -nk_str_append_str_runes(struct nk_str *str, const nk_rune *runes) -{ - int i = 0; - nk_glyph glyph; - int byte_len; - NK_ASSERT(str); - if (!str || !runes) return 0; - while (runes[i] != '\0') { - byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); - nk_str_append_text_char(str, glyph, byte_len); - i++; - } - return i; -} - -NK_API int -nk_str_insert_at_char(struct nk_str *s, int pos, const char *str, int len) -{ - int i; - void *mem; - char *src; - char *dst; - - int copylen; - NK_ASSERT(s); - NK_ASSERT(str); - NK_ASSERT(len >= 0); - if (!s || !str || !len || (nk_size)pos > s->buffer.allocated) return 0; - if ((s->buffer.allocated + (nk_size)len >= s->buffer.memory.size) && - (s->buffer.type == NK_BUFFER_FIXED)) return 0; - - copylen = (int)s->buffer.allocated - pos; - if (!copylen) { - nk_str_append_text_char(s, str, len); - return 1; - } - mem = nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0); - if (!mem) return 0; - - /* memmove */ - NK_ASSERT(((int)pos + (int)len + ((int)copylen - 1)) >= 0); - NK_ASSERT(((int)pos + ((int)copylen - 1)) >= 0); - dst = nk_ptr_add(char, s->buffer.memory.ptr, pos + len + (copylen - 1)); - src = nk_ptr_add(char, s->buffer.memory.ptr, pos + (copylen-1)); - for (i = 0; i < copylen; ++i) *dst-- = *src--; - mem = nk_ptr_add(void, s->buffer.memory.ptr, pos); - NK_MEMCPY(mem, str, (nk_size)len * sizeof(char)); - s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); - return 1; -} - -NK_API int -nk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len) -{ - int glyph_len; - nk_rune unicode; - const char *begin; - const char *buffer; - - NK_ASSERT(str); - NK_ASSERT(cstr); - NK_ASSERT(len); - if (!str || !cstr || !len) return 0; - begin = nk_str_at_rune(str, pos, &unicode, &glyph_len); - if (!str->len) - return nk_str_append_text_char(str, cstr, len); - buffer = nk_str_get_const(str); - if (!begin) return 0; - return nk_str_insert_at_char(str, (int)(begin - buffer), cstr, len); -} - -NK_API int -nk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len) -{ - return nk_str_insert_text_utf8(str, pos, text, len); -} - -NK_API int -nk_str_insert_str_char(struct nk_str *str, int pos, const char *text) -{ - return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text)); -} - -NK_API int -nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len) -{ - int i = 0; - int byte_len = 0; - nk_rune unicode; - - NK_ASSERT(str); - NK_ASSERT(text); - if (!str || !text || !len) return 0; - for (i = 0; i < len; ++i) - byte_len += nk_utf_decode(text+byte_len, &unicode, 4); - nk_str_insert_at_rune(str, pos, text, byte_len); - return len; -} - -NK_API int -nk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text) -{ - int runes = 0; - int byte_len = 0; - int num_runes = 0; - int glyph_len = 0; - nk_rune unicode; - if (!str || !text) return 0; - - glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4); - while (unicode != '\0' && glyph_len) { - glyph_len = nk_utf_decode(text+byte_len, &unicode, 4); - byte_len += glyph_len; - num_runes++; - } - nk_str_insert_at_rune(str, pos, text, byte_len); - return runes; -} - -NK_API int -nk_str_insert_text_runes(struct nk_str *str, int pos, const nk_rune *runes, int len) -{ - int i = 0; - int byte_len = 0; - nk_glyph glyph; - - NK_ASSERT(str); - if (!str || !runes || !len) return 0; - for (i = 0; i < len; ++i) { - byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); - if (!byte_len) break; - nk_str_insert_at_rune(str, pos+i, glyph, byte_len); - } - return len; -} - -NK_API int -nk_str_insert_str_runes(struct nk_str *str, int pos, const nk_rune *runes) -{ - int i = 0; - nk_glyph glyph; - int byte_len; - NK_ASSERT(str); - if (!str || !runes) return 0; - while (runes[i] != '\0') { - byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); - nk_str_insert_at_rune(str, pos+i, glyph, byte_len); - i++; - } - return i; -} - -NK_API void -nk_str_remove_chars(struct nk_str *s, int len) -{ - NK_ASSERT(s); - NK_ASSERT(len >= 0); - if (!s || len < 0 || (nk_size)len > s->buffer.allocated) return; - NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0); - s->buffer.allocated -= (nk_size)len; - s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); -} - -NK_API void -nk_str_remove_runes(struct nk_str *str, int len) -{ - int index; - const char *begin; - const char *end; - nk_rune unicode; - - NK_ASSERT(str); - NK_ASSERT(len >= 0); - if (!str || len < 0) return; - if (len >= str->len) { - str->len = 0; - return; - } - - index = str->len - len; - begin = nk_str_at_rune(str, index, &unicode, &len); - end = (const char*)str->buffer.memory.ptr + str->buffer.allocated; - nk_str_remove_chars(str, (int)(end-begin)+1); -} - -NK_API void -nk_str_delete_chars(struct nk_str *s, int pos, int len) -{ - NK_ASSERT(s); - if (!s || !len || (nk_size)pos > s->buffer.allocated || - (nk_size)(pos + len) > s->buffer.allocated) return; - - if ((nk_size)(pos + len) < s->buffer.allocated) { - /* memmove */ - char *dst = nk_ptr_add(char, s->buffer.memory.ptr, pos); - char *src = nk_ptr_add(char, s->buffer.memory.ptr, pos + len); - NK_MEMCPY(dst, src, s->buffer.allocated - (nk_size)(pos + len)); - NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0); - s->buffer.allocated -= (nk_size)len; - } else nk_str_remove_chars(s, len); - s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); -} - -NK_API void -nk_str_delete_runes(struct nk_str *s, int pos, int len) -{ - char *temp; - nk_rune unicode; - char *begin; - char *end; - int unused; - - NK_ASSERT(s); - NK_ASSERT(s->len >= pos + len); - if (s->len < pos + len) - len = NK_CLAMP(0, (s->len - pos), s->len); - if (!len) return; - - temp = (char *)s->buffer.memory.ptr; - begin = nk_str_at_rune(s, pos, &unicode, &unused); - if (!begin) return; - s->buffer.memory.ptr = begin; - end = nk_str_at_rune(s, len, &unicode, &unused); - s->buffer.memory.ptr = temp; - if (!end) return; - nk_str_delete_chars(s, (int)(begin - temp), (int)(end - begin)); -} - -NK_API char* -nk_str_at_char(struct nk_str *s, int pos) -{ - NK_ASSERT(s); - if (!s || pos > (int)s->buffer.allocated) return 0; - return nk_ptr_add(char, s->buffer.memory.ptr, pos); -} - -NK_API char* -nk_str_at_rune(struct nk_str *str, int pos, nk_rune *unicode, int *len) -{ - int i = 0; - int src_len = 0; - int glyph_len = 0; - char *text; - int text_len; - - NK_ASSERT(str); - NK_ASSERT(unicode); - NK_ASSERT(len); - - if (!str || !unicode || !len) return 0; - if (pos < 0) { - *unicode = 0; - *len = 0; - return 0; - } - - text = (char*)str->buffer.memory.ptr; - text_len = (int)str->buffer.allocated; - glyph_len = nk_utf_decode(text, unicode, text_len); - while (glyph_len) { - if (i == pos) { - *len = glyph_len; - break; - } - - i++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); - } - if (i != pos) return 0; - return text + src_len; -} - -NK_API const char* -nk_str_at_char_const(const struct nk_str *s, int pos) -{ - NK_ASSERT(s); - if (!s || pos > (int)s->buffer.allocated) return 0; - return nk_ptr_add(char, s->buffer.memory.ptr, pos); -} - -NK_API const char* -nk_str_at_const(const struct nk_str *str, int pos, nk_rune *unicode, int *len) -{ - int i = 0; - int src_len = 0; - int glyph_len = 0; - char *text; - int text_len; - - NK_ASSERT(str); - NK_ASSERT(unicode); - NK_ASSERT(len); - - if (!str || !unicode || !len) return 0; - if (pos < 0) { - *unicode = 0; - *len = 0; - return 0; - } - - text = (char*)str->buffer.memory.ptr; - text_len = (int)str->buffer.allocated; - glyph_len = nk_utf_decode(text, unicode, text_len); - while (glyph_len) { - if (i == pos) { - *len = glyph_len; - break; - } - - i++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); - } - if (i != pos) return 0; - return text + src_len; -} - -NK_API nk_rune -nk_str_rune_at(const struct nk_str *str, int pos) -{ - int len; - nk_rune unicode = 0; - nk_str_at_const(str, pos, &unicode, &len); - return unicode; -} - -NK_API char* -nk_str_get(struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return (char*)s->buffer.memory.ptr; -} - -NK_API const char* -nk_str_get_const(const struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return (const char*)s->buffer.memory.ptr; -} - -NK_API int -nk_str_len(struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return s->len; -} - -NK_API int -nk_str_len_char(struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return (int)s->buffer.allocated; -} - -NK_API void -nk_str_clear(struct nk_str *str) -{ - NK_ASSERT(str); - nk_buffer_clear(&str->buffer); - str->len = 0; -} - -NK_API void -nk_str_free(struct nk_str *str) -{ - NK_ASSERT(str); - nk_buffer_free(&str->buffer); - str->len = 0; -} - -/* - * ============================================================== - * - * Command buffer - * - * =============================================================== -*/ -NK_INTERN void -nk_command_buffer_init(struct nk_command_buffer *cmdbuf, - struct nk_buffer *buffer, enum nk_command_clipping clip) -{ - NK_ASSERT(cmdbuf); - NK_ASSERT(buffer); - if (!cmdbuf || !buffer) return; - cmdbuf->base = buffer; - cmdbuf->use_clipping = clip; - cmdbuf->begin = buffer->allocated; - cmdbuf->end = buffer->allocated; - cmdbuf->last = buffer->allocated; -} - -NK_INTERN void -nk_command_buffer_reset(struct nk_command_buffer *buffer) -{ - NK_ASSERT(buffer); - if (!buffer) return; - buffer->begin = 0; - buffer->end = 0; - buffer->last = 0; - buffer->clip = nk_null_rect; -#ifdef NK_INCLUDE_COMMAND_USERDATA - buffer->userdata.ptr = 0; -#endif -} - -NK_INTERN void* -nk_command_buffer_push(struct nk_command_buffer* b, - enum nk_command_type t, nk_size size) -{ - NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_command); - struct nk_command *cmd; - nk_size alignment; - void *unaligned; - void *memory; - - NK_ASSERT(b); - NK_ASSERT(b->base); - if (!b) return 0; - cmd = (struct nk_command*)nk_buffer_alloc(b->base,NK_BUFFER_FRONT,size,align); - if (!cmd) return 0; - - /* make sure the offset to the next command is aligned */ - b->last = (nk_size)((nk_byte*)cmd - (nk_byte*)b->base->memory.ptr); - unaligned = (nk_byte*)cmd + size; - memory = NK_ALIGN_PTR(unaligned, align); - alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned); -#ifdef NK_ZERO_COMMAND_MEMORY - NK_MEMSET(cmd, 0, size + alignment); -#endif - - cmd->type = t; - cmd->next = b->base->allocated + alignment; -#ifdef NK_INCLUDE_COMMAND_USERDATA - cmd->userdata = b->userdata; -#endif - b->end = cmd->next; - return cmd; -} - -NK_API void -nk_push_scissor(struct nk_command_buffer *b, struct nk_rect r) -{ - struct nk_command_scissor *cmd; - NK_ASSERT(b); - if (!b) return; - - b->clip.x = r.x; - b->clip.y = r.y; - b->clip.w = r.w; - b->clip.h = r.h; - cmd = (struct nk_command_scissor*) - nk_command_buffer_push(b, NK_COMMAND_SCISSOR, sizeof(*cmd)); - - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(0, r.w); - cmd->h = (unsigned short)NK_MAX(0, r.h); -} - -NK_API void -nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, - float x1, float y1, float line_thickness, struct nk_color c) -{ - struct nk_command_line *cmd; - NK_ASSERT(b); - if (!b || line_thickness <= 0) return; - cmd = (struct nk_command_line*) - nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->begin.x = (short)x0; - cmd->begin.y = (short)y0; - cmd->end.x = (short)x1; - cmd->end.y = (short)y1; - cmd->color = c; -} - -NK_API void -nk_stroke_curve(struct nk_command_buffer *b, float ax, float ay, - float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y, - float bx, float by, float line_thickness, struct nk_color col) -{ - struct nk_command_curve *cmd; - NK_ASSERT(b); - if (!b || col.a == 0 || line_thickness <= 0) return; - - cmd = (struct nk_command_curve*) - nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->begin.x = (short)ax; - cmd->begin.y = (short)ay; - cmd->ctrl[0].x = (short)ctrl0x; - cmd->ctrl[0].y = (short)ctrl0y; - cmd->ctrl[1].x = (short)ctrl1x; - cmd->ctrl[1].y = (short)ctrl1y; - cmd->end.x = (short)bx; - cmd->end.y = (short)by; - cmd->color = col; -} - -NK_API void -nk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect, - float rounding, float line_thickness, struct nk_color c) -{ - struct nk_command_rect *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || rect.w == 0 || rect.h == 0 || line_thickness <= 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - clip->x, clip->y, clip->w, clip->h)) return; - } - cmd = (struct nk_command_rect*) - nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd)); - if (!cmd) return; - cmd->rounding = (unsigned short)rounding; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->x = (short)rect.x; - cmd->y = (short)rect.y; - cmd->w = (unsigned short)NK_MAX(0, rect.w); - cmd->h = (unsigned short)NK_MAX(0, rect.h); - cmd->color = c; -} - -NK_API void -nk_fill_rect(struct nk_command_buffer *b, struct nk_rect rect, - float rounding, struct nk_color c) -{ - struct nk_command_rect_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - clip->x, clip->y, clip->w, clip->h)) return; - } - - cmd = (struct nk_command_rect_filled*) - nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->rounding = (unsigned short)rounding; - cmd->x = (short)rect.x; - cmd->y = (short)rect.y; - cmd->w = (unsigned short)NK_MAX(0, rect.w); - cmd->h = (unsigned short)NK_MAX(0, rect.h); - cmd->color = c; -} - -NK_API void -nk_fill_rect_multi_color(struct nk_command_buffer *b, struct nk_rect rect, - struct nk_color left, struct nk_color top, struct nk_color right, - struct nk_color bottom) -{ - struct nk_command_rect_multi_color *cmd; - NK_ASSERT(b); - if (!b || rect.w == 0 || rect.h == 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - clip->x, clip->y, clip->w, clip->h)) return; - } - - cmd = (struct nk_command_rect_multi_color*) - nk_command_buffer_push(b, NK_COMMAND_RECT_MULTI_COLOR, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)rect.x; - cmd->y = (short)rect.y; - cmd->w = (unsigned short)NK_MAX(0, rect.w); - cmd->h = (unsigned short)NK_MAX(0, rect.h); - cmd->left = left; - cmd->top = top; - cmd->right = right; - cmd->bottom = bottom; -} - -NK_API void -nk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r, - float line_thickness, struct nk_color c) -{ - struct nk_command_circle *cmd; - if (!b || r.w == 0 || r.h == 0 || line_thickness <= 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_circle*) - nk_command_buffer_push(b, NK_COMMAND_CIRCLE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(r.w, 0); - cmd->h = (unsigned short)NK_MAX(r.h, 0); - cmd->color = c; -} - -NK_API void -nk_fill_circle(struct nk_command_buffer *b, struct nk_rect r, struct nk_color c) -{ - struct nk_command_circle_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || r.w == 0 || r.h == 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_circle_filled*) - nk_command_buffer_push(b, NK_COMMAND_CIRCLE_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(r.w, 0); - cmd->h = (unsigned short)NK_MAX(r.h, 0); - cmd->color = c; -} - -NK_API void -nk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius, - float a_min, float a_max, float line_thickness, struct nk_color c) -{ - struct nk_command_arc *cmd; - if (!b || c.a == 0 || line_thickness <= 0) return; - cmd = (struct nk_command_arc*) - nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->cx = (short)cx; - cmd->cy = (short)cy; - cmd->r = (unsigned short)radius; - cmd->a[0] = a_min; - cmd->a[1] = a_max; - cmd->color = c; -} - -NK_API void -nk_fill_arc(struct nk_command_buffer *b, float cx, float cy, float radius, - float a_min, float a_max, struct nk_color c) -{ - struct nk_command_arc_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0) return; - cmd = (struct nk_command_arc_filled*) - nk_command_buffer_push(b, NK_COMMAND_ARC_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->cx = (short)cx; - cmd->cy = (short)cy; - cmd->r = (unsigned short)radius; - cmd->a[0] = a_min; - cmd->a[1] = a_max; - cmd->color = c; -} - -NK_API void -nk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1, - float y1, float x2, float y2, float line_thickness, struct nk_color c) -{ - struct nk_command_triangle *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || line_thickness <= 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_triangle*) - nk_command_buffer_push(b, NK_COMMAND_TRIANGLE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->a.x = (short)x0; - cmd->a.y = (short)y0; - cmd->b.x = (short)x1; - cmd->b.y = (short)y1; - cmd->c.x = (short)x2; - cmd->c.y = (short)y2; - cmd->color = c; -} - -NK_API void -nk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1, - float y1, float x2, float y2, struct nk_color c) -{ - struct nk_command_triangle_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0) return; - if (!b) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_triangle_filled*) - nk_command_buffer_push(b, NK_COMMAND_TRIANGLE_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->a.x = (short)x0; - cmd->a.y = (short)y0; - cmd->b.x = (short)x1; - cmd->b.y = (short)y1; - cmd->c.x = (short)x2; - cmd->c.y = (short)y2; - cmd->color = c; -} - -NK_API void -nk_stroke_polygon(struct nk_command_buffer *b, float *points, int point_count, - float line_thickness, struct nk_color col) -{ - int i; - nk_size size = 0; - struct nk_command_polygon *cmd; - - NK_ASSERT(b); - if (!b || col.a == 0 || line_thickness <= 0) return; - size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; - cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size); - if (!cmd) return; - cmd->color = col; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->point_count = (unsigned short)point_count; - for (i = 0; i < point_count; ++i) { - cmd->points[i].x = (short)points[i*2]; - cmd->points[i].y = (short)points[i*2+1]; - } -} - -NK_API void -nk_fill_polygon(struct nk_command_buffer *b, float *points, int point_count, - struct nk_color col) -{ - int i; - nk_size size = 0; - struct nk_command_polygon_filled *cmd; - - NK_ASSERT(b); - if (!b || col.a == 0) return; - size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; - cmd = (struct nk_command_polygon_filled*) - nk_command_buffer_push(b, NK_COMMAND_POLYGON_FILLED, size); - if (!cmd) return; - cmd->color = col; - cmd->point_count = (unsigned short)point_count; - for (i = 0; i < point_count; ++i) { - cmd->points[i].x = (short)points[i*2+0]; - cmd->points[i].y = (short)points[i*2+1]; - } -} - -NK_API void -nk_stroke_polyline(struct nk_command_buffer *b, float *points, int point_count, - float line_thickness, struct nk_color col) -{ - int i; - nk_size size = 0; - struct nk_command_polyline *cmd; - - NK_ASSERT(b); - if (!b || col.a == 0 || line_thickness <= 0) return; - size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; - cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size); - if (!cmd) return; - cmd->color = col; - cmd->point_count = (unsigned short)point_count; - cmd->line_thickness = (unsigned short)line_thickness; - for (i = 0; i < point_count; ++i) { - cmd->points[i].x = (short)points[i*2]; - cmd->points[i].y = (short)points[i*2+1]; - } -} - -NK_API void -nk_draw_image(struct nk_command_buffer *b, struct nk_rect r, - const struct nk_image *img, struct nk_color col) -{ - struct nk_command_image *cmd; - NK_ASSERT(b); - if (!b) return; - if (b->use_clipping) { - const struct nk_rect *c = &b->clip; - if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) - return; - } - - cmd = (struct nk_command_image*) - nk_command_buffer_push(b, NK_COMMAND_IMAGE, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(0, r.w); - cmd->h = (unsigned short)NK_MAX(0, r.h); - cmd->img = *img; - cmd->col = col; -} - -NK_API void -nk_push_custom(struct nk_command_buffer *b, struct nk_rect r, - nk_command_custom_callback cb, nk_handle usr) -{ - struct nk_command_custom *cmd; - NK_ASSERT(b); - if (!b) return; - if (b->use_clipping) { - const struct nk_rect *c = &b->clip; - if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) - return; - } - - cmd = (struct nk_command_custom*) - nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(0, r.w); - cmd->h = (unsigned short)NK_MAX(0, r.h); - cmd->callback_data = usr; - cmd->callback = cb; -} - -NK_API void -nk_draw_text(struct nk_command_buffer *b, struct nk_rect r, - const char *string, int length, const struct nk_user_font *font, - struct nk_color bg, struct nk_color fg) -{ - float text_width = 0; - struct nk_command_text *cmd; - - NK_ASSERT(b); - NK_ASSERT(font); - if (!b || !string || !length || (bg.a == 0 && fg.a == 0)) return; - if (b->use_clipping) { - const struct nk_rect *c = &b->clip; - if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) - return; - } - - /* make sure text fits inside bounds */ - text_width = font->width(font->userdata, font->height, string, length); - if (text_width > r.w){ - int glyphs = 0; - float txt_width = (float)text_width; - length = nk_text_clamp(font, string, length, r.w, &glyphs, &txt_width, 0,0); - } - - if (!length) return; - cmd = (struct nk_command_text*) - nk_command_buffer_push(b, NK_COMMAND_TEXT, sizeof(*cmd) + (nk_size)(length + 1)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)r.w; - cmd->h = (unsigned short)r.h; - cmd->background = bg; - cmd->foreground = fg; - cmd->font = font; - cmd->length = length; - cmd->height = font->height; - NK_MEMCPY(cmd->string, string, (nk_size)length); - cmd->string[length] = '\0'; -} - -/* ============================================================== - * - * DRAW LIST - * - * ===============================================================*/ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -NK_API void -nk_draw_list_init(struct nk_draw_list *list) -{ - nk_size i = 0; - NK_ASSERT(list); - if (!list) return; - nk_zero(list, sizeof(*list)); - for (i = 0; i < NK_LEN(list->circle_vtx); ++i) { - const float a = ((float)i / (float)NK_LEN(list->circle_vtx)) * 2 * NK_PI; - list->circle_vtx[i].x = (float)NK_COS(a); - list->circle_vtx[i].y = (float)NK_SIN(a); - } -} - -NK_API void -nk_draw_list_setup(struct nk_draw_list *canvas, const struct nk_convert_config *config, - struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, - enum nk_anti_aliasing line_aa, enum nk_anti_aliasing shape_aa) -{ - NK_ASSERT(canvas); - NK_ASSERT(config); - NK_ASSERT(cmds); - NK_ASSERT(vertices); - NK_ASSERT(elements); - if (!canvas || !config || !cmds || !vertices || !elements) - return; - - canvas->buffer = cmds; - canvas->config = *config; - canvas->elements = elements; - canvas->vertices = vertices; - canvas->line_AA = line_aa; - canvas->shape_AA = shape_aa; - canvas->clip_rect = nk_null_rect; -} - -NK_API const struct nk_draw_command* -nk__draw_list_begin(const struct nk_draw_list *canvas, const struct nk_buffer *buffer) -{ - nk_byte *memory; - nk_size offset; - const struct nk_draw_command *cmd; - - NK_ASSERT(buffer); - if (!buffer || !buffer->size || !canvas->cmd_count) - return 0; - - memory = (nk_byte*)buffer->memory.ptr; - offset = buffer->memory.size - canvas->cmd_offset; - cmd = nk_ptr_add(const struct nk_draw_command, memory, offset); - return cmd; -} - -NK_API const struct nk_draw_command* -nk__draw_list_end(const struct nk_draw_list *canvas, const struct nk_buffer *buffer) -{ - nk_size size; - nk_size offset; - nk_byte *memory; - const struct nk_draw_command *end; - - NK_ASSERT(buffer); - NK_ASSERT(canvas); - if (!buffer || !canvas) - return 0; - - memory = (nk_byte*)buffer->memory.ptr; - size = buffer->memory.size; - offset = size - canvas->cmd_offset; - end = nk_ptr_add(const struct nk_draw_command, memory, offset); - end -= (canvas->cmd_count-1); - return end; -} - -NK_API const struct nk_draw_command* -nk__draw_list_next(const struct nk_draw_command *cmd, - const struct nk_buffer *buffer, const struct nk_draw_list *canvas) -{ - const struct nk_draw_command *end; - NK_ASSERT(buffer); - NK_ASSERT(canvas); - if (!cmd || !buffer || !canvas) - return 0; - - end = nk__draw_list_end(canvas, buffer); - if (cmd <= end) return 0; - return (cmd-1); -} - -NK_API void -nk_draw_list_clear(struct nk_draw_list *list) -{ - NK_ASSERT(list); - if (!list) return; - if (list->buffer) - nk_buffer_clear(list->buffer); - if (list->vertices) - nk_buffer_clear(list->vertices); - if (list->elements) - nk_buffer_clear(list->elements); - - list->element_count = 0; - list->vertex_count = 0; - list->cmd_offset = 0; - list->cmd_count = 0; - list->path_count = 0; - list->vertices = 0; - list->elements = 0; - list->clip_rect = nk_null_rect; -} - -NK_INTERN struct nk_vec2* -nk_draw_list_alloc_path(struct nk_draw_list *list, int count) -{ - struct nk_vec2 *points; - NK_STORAGE const nk_size point_align = NK_ALIGNOF(struct nk_vec2); - NK_STORAGE const nk_size point_size = sizeof(struct nk_vec2); - points = (struct nk_vec2*) - nk_buffer_alloc(list->buffer, NK_BUFFER_FRONT, - point_size * (nk_size)count, point_align); - - if (!points) return 0; - if (!list->path_offset) { - void *memory = nk_buffer_memory(list->buffer); - list->path_offset = (unsigned int)((nk_byte*)points - (nk_byte*)memory); - } - list->path_count += (unsigned int)count; - return points; -} - -NK_INTERN struct nk_vec2 -nk_draw_list_path_last(struct nk_draw_list *list) -{ - void *memory; - struct nk_vec2 *point; - NK_ASSERT(list->path_count); - memory = nk_buffer_memory(list->buffer); - point = nk_ptr_add(struct nk_vec2, memory, list->path_offset); - point += (list->path_count-1); - return *point; -} - -NK_INTERN struct nk_draw_command* -nk_draw_list_push_command(struct nk_draw_list *list, struct nk_rect clip, - nk_handle texture) -{ - NK_STORAGE const nk_size cmd_align = NK_ALIGNOF(struct nk_draw_command); - NK_STORAGE const nk_size cmd_size = sizeof(struct nk_draw_command); - struct nk_draw_command *cmd; - - NK_ASSERT(list); - cmd = (struct nk_draw_command*) - nk_buffer_alloc(list->buffer, NK_BUFFER_BACK, cmd_size, cmd_align); - - if (!cmd) return 0; - if (!list->cmd_count) { - nk_byte *memory = (nk_byte*)nk_buffer_memory(list->buffer); - nk_size total = nk_buffer_total(list->buffer); - memory = nk_ptr_add(nk_byte, memory, total); - list->cmd_offset = (nk_size)(memory - (nk_byte*)cmd); - } - - cmd->elem_count = 0; - cmd->clip_rect = clip; - cmd->texture = texture; -#ifdef NK_INCLUDE_COMMAND_USERDATA - cmd->userdata = list->userdata; -#endif - - list->cmd_count++; - list->clip_rect = clip; - return cmd; -} - -NK_INTERN struct nk_draw_command* -nk_draw_list_command_last(struct nk_draw_list *list) -{ - void *memory; - nk_size size; - struct nk_draw_command *cmd; - NK_ASSERT(list->cmd_count); - - memory = nk_buffer_memory(list->buffer); - size = nk_buffer_total(list->buffer); - cmd = nk_ptr_add(struct nk_draw_command, memory, size - list->cmd_offset); - return (cmd - (list->cmd_count-1)); -} - -NK_INTERN void -nk_draw_list_add_clip(struct nk_draw_list *list, struct nk_rect rect) -{ - NK_ASSERT(list); - if (!list) return; - if (!list->cmd_count) { - nk_draw_list_push_command(list, rect, list->config.null.texture); - } else { - struct nk_draw_command *prev = nk_draw_list_command_last(list); - if (prev->elem_count == 0) - prev->clip_rect = rect; - nk_draw_list_push_command(list, rect, prev->texture); - } -} - -NK_INTERN void -nk_draw_list_push_image(struct nk_draw_list *list, nk_handle texture) -{ - NK_ASSERT(list); - if (!list) return; - if (!list->cmd_count) { - nk_draw_list_push_command(list, nk_null_rect, texture); - } else { - struct nk_draw_command *prev = nk_draw_list_command_last(list); - if (prev->elem_count == 0) - prev->texture = texture; - else if (prev->texture.id != texture.id) - nk_draw_list_push_command(list, prev->clip_rect, texture); - } -} - -#ifdef NK_INCLUDE_COMMAND_USERDATA -NK_API void -nk_draw_list_push_userdata(struct nk_draw_list *list, nk_handle userdata) -{ - list->userdata = userdata; -} -#endif - -NK_INTERN void* -nk_draw_list_alloc_vertices(struct nk_draw_list *list, nk_size count) -{ - void *vtx; - NK_ASSERT(list); - if (!list) return 0; - vtx = nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, - list->config.vertex_size*count, list->config.vertex_alignment); - if (!vtx) return 0; - list->vertex_count += (unsigned int)count; - return vtx; -} - -NK_INTERN nk_draw_index* -nk_draw_list_alloc_elements(struct nk_draw_list *list, nk_size count) -{ - nk_draw_index *ids; - struct nk_draw_command *cmd; - NK_STORAGE const nk_size elem_align = NK_ALIGNOF(nk_draw_index); - NK_STORAGE const nk_size elem_size = sizeof(nk_draw_index); - NK_ASSERT(list); - if (!list) return 0; - - ids = (nk_draw_index*) - nk_buffer_alloc(list->elements, NK_BUFFER_FRONT, elem_size*count, elem_align); - if (!ids) return 0; - cmd = nk_draw_list_command_last(list); - list->element_count += (unsigned int)count; - cmd->elem_count += (unsigned int)count; - return ids; -} - -NK_INTERN int -nk_draw_vertex_layout_element_is_end_of_layout( - const struct nk_draw_vertex_layout_element *element) -{ - return (element->attribute == NK_VERTEX_ATTRIBUTE_COUNT || - element->format == NK_FORMAT_COUNT); -} - -NK_INTERN void -nk_draw_vertex_color(void *attribute, const float *values, - enum nk_draw_vertex_layout_format format) -{ - /* if this triggers you tried to provide a value format for a color */ - NK_ASSERT(format >= NK_FORMAT_COLOR_BEGIN); - NK_ASSERT(format <= NK_FORMAT_COLOR_END); - if (format < NK_FORMAT_COLOR_BEGIN || format > NK_FORMAT_COLOR_END) return; - - switch (format) { - default: NK_ASSERT(0 && "Invalid vertex layout color format"); break; - case NK_FORMAT_R8G8B8A8: - case NK_FORMAT_R8G8B8: { - struct nk_color col = nk_rgba_fv(values); - NK_MEMCPY(attribute, &col.r, sizeof(col)); - } break; - case NK_FORMAT_B8G8R8A8: { - struct nk_color col = nk_rgba_fv(values); - struct nk_color bgra = nk_rgba(col.b, col.g, col.r, col.a); - NK_MEMCPY(attribute, &bgra, sizeof(bgra)); - } break; - case NK_FORMAT_R16G15B16: { - nk_ushort col[3]; - col[0] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[0] * NK_USHORT_MAX, NK_USHORT_MAX); - col[1] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[1] * NK_USHORT_MAX, NK_USHORT_MAX); - col[2] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[2] * NK_USHORT_MAX, NK_USHORT_MAX); - NK_MEMCPY(attribute, col, sizeof(col)); - } break; - case NK_FORMAT_R16G15B16A16: { - nk_ushort col[4]; - col[0] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[0] * NK_USHORT_MAX, NK_USHORT_MAX); - col[1] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[1] * NK_USHORT_MAX, NK_USHORT_MAX); - col[2] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[2] * NK_USHORT_MAX, NK_USHORT_MAX); - col[3] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[3] * NK_USHORT_MAX, NK_USHORT_MAX); - NK_MEMCPY(attribute, col, sizeof(col)); - } break; - case NK_FORMAT_R32G32B32: { - nk_uint col[3]; - col[0] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[0] * NK_UINT_MAX, NK_UINT_MAX); - col[1] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[1] * NK_UINT_MAX, NK_UINT_MAX); - col[2] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[2] * NK_UINT_MAX, NK_UINT_MAX); - NK_MEMCPY(attribute, col, sizeof(col)); - } break; - case NK_FORMAT_R32G32B32A32: { - nk_uint col[4]; - col[0] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[0] * NK_UINT_MAX, NK_UINT_MAX); - col[1] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[1] * NK_UINT_MAX, NK_UINT_MAX); - col[2] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[2] * NK_UINT_MAX, NK_UINT_MAX); - col[3] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[3] * NK_UINT_MAX, NK_UINT_MAX); - NK_MEMCPY(attribute, col, sizeof(col)); - } break; - case NK_FORMAT_R32G32B32A32_FLOAT: - NK_MEMCPY(attribute, values, sizeof(float)*4); - break; - case NK_FORMAT_R32G32B32A32_DOUBLE: { - double col[4]; - col[0] = (double)NK_SATURATE(values[0]); - col[1] = (double)NK_SATURATE(values[1]); - col[2] = (double)NK_SATURATE(values[2]); - col[3] = (double)NK_SATURATE(values[3]); - NK_MEMCPY(attribute, col, sizeof(col)); - } break; - case NK_FORMAT_RGB32: - case NK_FORMAT_RGBA32: { - struct nk_color col = nk_rgba_fv(values); - nk_uint color = nk_color_u32(col); - NK_MEMCPY(attribute, &color, sizeof(color)); - } break; - } -} - -NK_INTERN void -nk_draw_vertex_element(void *dst, const float *values, int value_count, - enum nk_draw_vertex_layout_format format) -{ - int value_index; - void *attribute = dst; - /* if this triggers you tried to provide a color format for a value */ - NK_ASSERT(format < NK_FORMAT_COLOR_BEGIN); - if (format >= NK_FORMAT_COLOR_BEGIN && format <= NK_FORMAT_COLOR_END) return; - for (value_index = 0; value_index < value_count; ++value_index) { - switch (format) { - default: NK_ASSERT(0 && "invalid vertex layout format"); break; - case NK_FORMAT_SCHAR: { - char value = (char)NK_CLAMP(NK_SCHAR_MIN, values[value_index], NK_SCHAR_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(char)); - } break; - case NK_FORMAT_SSHORT: { - nk_short value = (nk_short)NK_CLAMP(NK_SSHORT_MIN, values[value_index], NK_SSHORT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(value)); - } break; - case NK_FORMAT_SINT: { - nk_int value = (nk_int)NK_CLAMP(NK_SINT_MIN, values[value_index], NK_SINT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(nk_int)); - } break; - case NK_FORMAT_UCHAR: { - unsigned char value = (unsigned char)NK_CLAMP(NK_UCHAR_MIN, values[value_index], NK_UCHAR_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(unsigned char)); - } break; - case NK_FORMAT_USHORT: { - nk_ushort value = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[value_index], NK_USHORT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(value)); - } break; - case NK_FORMAT_UINT: { - nk_uint value = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[value_index], NK_UINT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(nk_uint)); - } break; - case NK_FORMAT_FLOAT: - NK_MEMCPY(attribute, &values[value_index], sizeof(values[value_index])); - attribute = (void*)((char*)attribute + sizeof(float)); - break; - case NK_FORMAT_DOUBLE: { - double value = (double)values[value_index]; - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(double)); - } break; - } - } -} - -NK_INTERN void* -nk_draw_vertex(void *dst, const struct nk_convert_config *config, - struct nk_vec2 pos, struct nk_vec2 uv, struct nk_colorf color) -{ - void *result = (void*)((char*)dst + config->vertex_size); - const struct nk_draw_vertex_layout_element *elem_iter = config->vertex_layout; - while (!nk_draw_vertex_layout_element_is_end_of_layout(elem_iter)) { - void *address = (void*)((char*)dst + elem_iter->offset); - switch (elem_iter->attribute) { - case NK_VERTEX_ATTRIBUTE_COUNT: - default: NK_ASSERT(0 && "wrong element attribute"); - case NK_VERTEX_POSITION: nk_draw_vertex_element(address, &pos.x, 2, elem_iter->format); break; - case NK_VERTEX_TEXCOORD: nk_draw_vertex_element(address, &uv.x, 2, elem_iter->format); break; - case NK_VERTEX_COLOR: nk_draw_vertex_color(address, &color.r, elem_iter->format); break; - } - elem_iter++; - } - return result; -} - -NK_API void -nk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *points, - const unsigned int points_count, struct nk_color color, enum nk_draw_list_stroke closed, - float thickness, enum nk_anti_aliasing aliasing) -{ - nk_size count; - int thick_line; - struct nk_colorf col; - struct nk_colorf col_trans; - NK_ASSERT(list); - if (!list || points_count < 2) return; - - color.a = (nk_byte)((float)color.a * list->config.global_alpha); - count = points_count; - if (!closed) count = points_count-1; - thick_line = thickness > 1.0f; - -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_draw_list_push_userdata(list, list->userdata); -#endif - - color.a = (nk_byte)((float)color.a * list->config.global_alpha); - nk_color_fv(&col.r, color); - col_trans = col; - col_trans.a = 0; - - if (aliasing == NK_ANTI_ALIASING_ON) { - /* ANTI-ALIASED STROKE */ - const float AA_SIZE = 1.0f; - NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2); - NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2); - - /* allocate vertices and elements */ - nk_size i1 = 0; - nk_size vertex_offset; - nk_size index = list->vertex_count; - - const nk_size idx_count = (thick_line) ? (count * 18) : (count * 12); - const nk_size vtx_count = (thick_line) ? (points_count * 4): (points_count *3); - - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - - nk_size size; - struct nk_vec2 *normals, *temp; - if (!vtx || !ids) return; - - /* temporary allocate normals + points */ - vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr); - nk_buffer_mark(list->vertices, NK_BUFFER_FRONT); - size = pnt_size * ((thick_line) ? 5 : 3) * points_count; - normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align); - NK_ASSERT(normals); - if (!normals) return; - temp = normals + points_count; - - /* make sure vertex pointer is still correct */ - vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset); - - /* calculate normals */ - for (i1 = 0; i1 < count; ++i1) { - const nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1); - struct nk_vec2 diff = nk_vec2_sub(points[i2], points[i1]); - float len; - - /* vec2 inverted length */ - len = nk_vec2_len_sqr(diff); - if (len != 0.0f) - len = nk_inv_sqrt(len); - else len = 1.0f; - - diff = nk_vec2_muls(diff, len); - normals[i1].x = diff.y; - normals[i1].y = -diff.x; - } - - if (!closed) - normals[points_count-1] = normals[points_count-2]; - - if (!thick_line) { - nk_size idx1, i; - if (!closed) { - struct nk_vec2 d; - temp[0] = nk_vec2_add(points[0], nk_vec2_muls(normals[0], AA_SIZE)); - temp[1] = nk_vec2_sub(points[0], nk_vec2_muls(normals[0], AA_SIZE)); - d = nk_vec2_muls(normals[points_count-1], AA_SIZE); - temp[(points_count-1) * 2 + 0] = nk_vec2_add(points[points_count-1], d); - temp[(points_count-1) * 2 + 1] = nk_vec2_sub(points[points_count-1], d); - } - - /* fill elements */ - idx1 = index; - for (i1 = 0; i1 < count; i1++) { - struct nk_vec2 dm; - float dmr2; - nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1); - nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 3); - - /* average normals */ - dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f); - dmr2 = dm.x * dm.x + dm.y* dm.y; - if (dmr2 > 0.000001f) { - float scale = 1.0f/dmr2; - scale = NK_MIN(100.0f, scale); - dm = nk_vec2_muls(dm, scale); - } - - dm = nk_vec2_muls(dm, AA_SIZE); - temp[i2*2+0] = nk_vec2_add(points[i2], dm); - temp[i2*2+1] = nk_vec2_sub(points[i2], dm); - - ids[0] = (nk_draw_index)(idx2 + 0); ids[1] = (nk_draw_index)(idx1+0); - ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2); - ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+0); - ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1); - ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0); - ids[10]= (nk_draw_index)(idx2 + 0); ids[11]= (nk_draw_index)(idx2+1); - ids += 12; - idx1 = idx2; - } - - /* fill vertices */ - for (i = 0; i < points_count; ++i) { - const struct nk_vec2 uv = list->config.null.uv; - vtx = nk_draw_vertex(vtx, &list->config, points[i], uv, col); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+0], uv, col_trans); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+1], uv, col_trans); - } - } else { - nk_size idx1, i; - const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; - if (!closed) { - struct nk_vec2 d1 = nk_vec2_muls(normals[0], half_inner_thickness + AA_SIZE); - struct nk_vec2 d2 = nk_vec2_muls(normals[0], half_inner_thickness); - - temp[0] = nk_vec2_add(points[0], d1); - temp[1] = nk_vec2_add(points[0], d2); - temp[2] = nk_vec2_sub(points[0], d2); - temp[3] = nk_vec2_sub(points[0], d1); - - d1 = nk_vec2_muls(normals[points_count-1], half_inner_thickness + AA_SIZE); - d2 = nk_vec2_muls(normals[points_count-1], half_inner_thickness); - - temp[(points_count-1)*4+0] = nk_vec2_add(points[points_count-1], d1); - temp[(points_count-1)*4+1] = nk_vec2_add(points[points_count-1], d2); - temp[(points_count-1)*4+2] = nk_vec2_sub(points[points_count-1], d2); - temp[(points_count-1)*4+3] = nk_vec2_sub(points[points_count-1], d1); - } - - /* add all elements */ - idx1 = index; - for (i1 = 0; i1 < count; ++i1) { - struct nk_vec2 dm_out, dm_in; - const nk_size i2 = ((i1+1) == points_count) ? 0: (i1 + 1); - nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 4); - - /* average normals */ - struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f); - float dmr2 = dm.x * dm.x + dm.y* dm.y; - if (dmr2 > 0.000001f) { - float scale = 1.0f/dmr2; - scale = NK_MIN(100.0f, scale); - dm = nk_vec2_muls(dm, scale); - } - - dm_out = nk_vec2_muls(dm, ((half_inner_thickness) + AA_SIZE)); - dm_in = nk_vec2_muls(dm, half_inner_thickness); - temp[i2*4+0] = nk_vec2_add(points[i2], dm_out); - temp[i2*4+1] = nk_vec2_add(points[i2], dm_in); - temp[i2*4+2] = nk_vec2_sub(points[i2], dm_in); - temp[i2*4+3] = nk_vec2_sub(points[i2], dm_out); - - /* add indexes */ - ids[0] = (nk_draw_index)(idx2 + 1); ids[1] = (nk_draw_index)(idx1+1); - ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2); - ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+1); - ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1); - ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0); - ids[10]= (nk_draw_index)(idx2 + 0); ids[11] = (nk_draw_index)(idx2+1); - ids[12]= (nk_draw_index)(idx2 + 2); ids[13] = (nk_draw_index)(idx1+2); - ids[14]= (nk_draw_index)(idx1 + 3); ids[15] = (nk_draw_index)(idx1+3); - ids[16]= (nk_draw_index)(idx2 + 3); ids[17] = (nk_draw_index)(idx2+2); - ids += 18; - idx1 = idx2; - } - - /* add vertices */ - for (i = 0; i < points_count; ++i) { - const struct nk_vec2 uv = list->config.null.uv; - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+0], uv, col_trans); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+1], uv, col); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+2], uv, col); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+3], uv, col_trans); - } - } - /* free temporary normals + points */ - nk_buffer_reset(list->vertices, NK_BUFFER_FRONT); - } else { - /* NON ANTI-ALIASED STROKE */ - nk_size i1 = 0; - nk_size idx = list->vertex_count; - const nk_size idx_count = count * 6; - const nk_size vtx_count = count * 4; - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - if (!vtx || !ids) return; - - for (i1 = 0; i1 < count; ++i1) { - float dx, dy; - const struct nk_vec2 uv = list->config.null.uv; - const nk_size i2 = ((i1+1) == points_count) ? 0 : i1 + 1; - const struct nk_vec2 p1 = points[i1]; - const struct nk_vec2 p2 = points[i2]; - struct nk_vec2 diff = nk_vec2_sub(p2, p1); - float len; - - /* vec2 inverted length */ - len = nk_vec2_len_sqr(diff); - if (len != 0.0f) - len = nk_inv_sqrt(len); - else len = 1.0f; - diff = nk_vec2_muls(diff, len); - - /* add vertices */ - dx = diff.x * (thickness * 0.5f); - dy = diff.y * (thickness * 0.5f); - - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x + dy, p1.y - dx), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x + dy, p2.y - dx), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x - dy, p2.y + dx), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x - dy, p1.y + dx), uv, col); - - ids[0] = (nk_draw_index)(idx+0); ids[1] = (nk_draw_index)(idx+1); - ids[2] = (nk_draw_index)(idx+2); ids[3] = (nk_draw_index)(idx+0); - ids[4] = (nk_draw_index)(idx+2); ids[5] = (nk_draw_index)(idx+3); - - ids += 6; - idx += 4; - } - } -} - -NK_API void -nk_draw_list_fill_poly_convex(struct nk_draw_list *list, - const struct nk_vec2 *points, const unsigned int points_count, - struct nk_color color, enum nk_anti_aliasing aliasing) -{ - struct nk_colorf col; - struct nk_colorf col_trans; - - NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2); - NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2); - NK_ASSERT(list); - if (!list || points_count < 3) return; - -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_draw_list_push_userdata(list, list->userdata); -#endif - - color.a = (nk_byte)((float)color.a * list->config.global_alpha); - nk_color_fv(&col.r, color); - col_trans = col; - col_trans.a = 0; - - if (aliasing == NK_ANTI_ALIASING_ON) { - nk_size i = 0; - nk_size i0 = 0; - nk_size i1 = 0; - - const float AA_SIZE = 1.0f; - nk_size vertex_offset = 0; - nk_size index = list->vertex_count; - - const nk_size idx_count = (points_count-2)*3 + points_count*6; - const nk_size vtx_count = (points_count*2); - - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - - nk_size size = 0; - struct nk_vec2 *normals = 0; - unsigned int vtx_inner_idx = (unsigned int)(index + 0); - unsigned int vtx_outer_idx = (unsigned int)(index + 1); - if (!vtx || !ids) return; - - /* temporary allocate normals */ - vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr); - nk_buffer_mark(list->vertices, NK_BUFFER_FRONT); - size = pnt_size * points_count; - normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align); - NK_ASSERT(normals); - if (!normals) return; - vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset); - - /* add elements */ - for (i = 2; i < points_count; i++) { - ids[0] = (nk_draw_index)(vtx_inner_idx); - ids[1] = (nk_draw_index)(vtx_inner_idx + ((i-1) << 1)); - ids[2] = (nk_draw_index)(vtx_inner_idx + (i << 1)); - ids += 3; - } - - /* compute normals */ - for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) { - struct nk_vec2 p0 = points[i0]; - struct nk_vec2 p1 = points[i1]; - struct nk_vec2 diff = nk_vec2_sub(p1, p0); - - /* vec2 inverted length */ - float len = nk_vec2_len_sqr(diff); - if (len != 0.0f) - len = nk_inv_sqrt(len); - else len = 1.0f; - diff = nk_vec2_muls(diff, len); - - normals[i0].x = diff.y; - normals[i0].y = -diff.x; - } - - /* add vertices + indexes */ - for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) { - const struct nk_vec2 uv = list->config.null.uv; - struct nk_vec2 n0 = normals[i0]; - struct nk_vec2 n1 = normals[i1]; - struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(n0, n1), 0.5f); - float dmr2 = dm.x*dm.x + dm.y*dm.y; - if (dmr2 > 0.000001f) { - float scale = 1.0f / dmr2; - scale = NK_MIN(scale, 100.0f); - dm = nk_vec2_muls(dm, scale); - } - dm = nk_vec2_muls(dm, AA_SIZE * 0.5f); - - /* add vertices */ - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_sub(points[i1], dm), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_add(points[i1], dm), uv, col_trans); - - /* add indexes */ - ids[0] = (nk_draw_index)(vtx_inner_idx+(i1<<1)); - ids[1] = (nk_draw_index)(vtx_inner_idx+(i0<<1)); - ids[2] = (nk_draw_index)(vtx_outer_idx+(i0<<1)); - ids[3] = (nk_draw_index)(vtx_outer_idx+(i0<<1)); - ids[4] = (nk_draw_index)(vtx_outer_idx+(i1<<1)); - ids[5] = (nk_draw_index)(vtx_inner_idx+(i1<<1)); - ids += 6; - } - /* free temporary normals + points */ - nk_buffer_reset(list->vertices, NK_BUFFER_FRONT); - } else { - nk_size i = 0; - nk_size index = list->vertex_count; - const nk_size idx_count = (points_count-2)*3; - const nk_size vtx_count = points_count; - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - - if (!vtx || !ids) return; - for (i = 0; i < vtx_count; ++i) - vtx = nk_draw_vertex(vtx, &list->config, points[i], list->config.null.uv, col); - for (i = 2; i < points_count; ++i) { - ids[0] = (nk_draw_index)index; - ids[1] = (nk_draw_index)(index+ i - 1); - ids[2] = (nk_draw_index)(index+i); - ids += 3; - } - } -} - -NK_API void -nk_draw_list_path_clear(struct nk_draw_list *list) -{ - NK_ASSERT(list); - if (!list) return; - nk_buffer_reset(list->buffer, NK_BUFFER_FRONT); - list->path_count = 0; - list->path_offset = 0; -} - -NK_API void -nk_draw_list_path_line_to(struct nk_draw_list *list, struct nk_vec2 pos) -{ - struct nk_vec2 *points = 0; - struct nk_draw_command *cmd = 0; - NK_ASSERT(list); - if (!list) return; - if (!list->cmd_count) - nk_draw_list_add_clip(list, nk_null_rect); - - cmd = nk_draw_list_command_last(list); - if (cmd && cmd->texture.ptr != list->config.null.texture.ptr) - nk_draw_list_push_image(list, list->config.null.texture); - - points = nk_draw_list_alloc_path(list, 1); - if (!points) return; - points[0] = pos; -} - -NK_API void -nk_draw_list_path_arc_to_fast(struct nk_draw_list *list, struct nk_vec2 center, - float radius, int a_min, int a_max) -{ - int a = 0; - NK_ASSERT(list); - if (!list) return; - if (a_min <= a_max) { - for (a = a_min; a <= a_max; a++) { - const struct nk_vec2 c = list->circle_vtx[(nk_size)a % NK_LEN(list->circle_vtx)]; - const float x = center.x + c.x * radius; - const float y = center.y + c.y * radius; - nk_draw_list_path_line_to(list, nk_vec2(x, y)); - } - } -} - -NK_API void -nk_draw_list_path_arc_to(struct nk_draw_list *list, struct nk_vec2 center, - float radius, float a_min, float a_max, unsigned int segments) -{ - unsigned int i = 0; - NK_ASSERT(list); - if (!list) return; - if (radius == 0.0f) return; - for (i = 0; i <= segments; ++i) { - const float a = a_min + ((float)i / ((float)segments) * (a_max - a_min)); - const float x = center.x + (float)NK_COS(a) * radius; - const float y = center.y + (float)NK_SIN(a) * radius; - nk_draw_list_path_line_to(list, nk_vec2(x, y)); - } -} - -NK_API void -nk_draw_list_path_rect_to(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, float rounding) -{ - float r; - NK_ASSERT(list); - if (!list) return; - r = rounding; - r = NK_MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x)); - r = NK_MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y)); - - if (r == 0.0f) { - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, nk_vec2(b.x,a.y)); - nk_draw_list_path_line_to(list, b); - nk_draw_list_path_line_to(list, nk_vec2(a.x,b.y)); - } else { - nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, a.y + r), r, 6, 9); - nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, a.y + r), r, 9, 12); - nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, b.y - r), r, 0, 3); - nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, b.y - r), r, 3, 6); - } -} - -NK_API void -nk_draw_list_path_curve_to(struct nk_draw_list *list, struct nk_vec2 p2, - struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments) -{ - float t_step; - unsigned int i_step; - struct nk_vec2 p1; - - NK_ASSERT(list); - NK_ASSERT(list->path_count); - if (!list || !list->path_count) return; - num_segments = NK_MAX(num_segments, 1); - - p1 = nk_draw_list_path_last(list); - t_step = 1.0f/(float)num_segments; - for (i_step = 1; i_step <= num_segments; ++i_step) { - float t = t_step * (float)i_step; - float u = 1.0f - t; - float w1 = u*u*u; - float w2 = 3*u*u*t; - float w3 = 3*u*t*t; - float w4 = t * t *t; - float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x; - float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y; - nk_draw_list_path_line_to(list, nk_vec2(x,y)); - } -} - -NK_API void -nk_draw_list_path_fill(struct nk_draw_list *list, struct nk_color color) -{ - struct nk_vec2 *points; - NK_ASSERT(list); - if (!list) return; - points = (struct nk_vec2*)nk_buffer_memory(list->buffer); - nk_draw_list_fill_poly_convex(list, points, list->path_count, color, list->config.shape_AA); - nk_draw_list_path_clear(list); -} - -NK_API void -nk_draw_list_path_stroke(struct nk_draw_list *list, struct nk_color color, - enum nk_draw_list_stroke closed, float thickness) -{ - struct nk_vec2 *points; - NK_ASSERT(list); - if (!list) return; - points = (struct nk_vec2*)nk_buffer_memory(list->buffer); - nk_draw_list_stroke_poly_line(list, points, list->path_count, color, - closed, thickness, list->config.line_AA); - nk_draw_list_path_clear(list); -} - -NK_API void -nk_draw_list_stroke_line(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, struct nk_color col, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - if (list->line_AA == NK_ANTI_ALIASING_ON) { - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, b); - } else { - nk_draw_list_path_line_to(list, nk_vec2_sub(a,nk_vec2(0.5f,0.5f))); - nk_draw_list_path_line_to(list, nk_vec2_sub(b,nk_vec2(0.5f,0.5f))); - } - nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness); -} - -NK_API void -nk_draw_list_fill_rect(struct nk_draw_list *list, struct nk_rect rect, - struct nk_color col, float rounding) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - - if (list->line_AA == NK_ANTI_ALIASING_ON) { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } else { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } nk_draw_list_path_fill(list, col); -} - -NK_API void -nk_draw_list_stroke_rect(struct nk_draw_list *list, struct nk_rect rect, - struct nk_color col, float rounding, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - if (list->line_AA == NK_ANTI_ALIASING_ON) { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } else { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); -} - -NK_API void -nk_draw_list_fill_rect_multi_color(struct nk_draw_list *list, struct nk_rect rect, - struct nk_color left, struct nk_color top, struct nk_color right, - struct nk_color bottom) -{ - void *vtx; - struct nk_colorf col_left, col_top; - struct nk_colorf col_right, col_bottom; - nk_draw_index *idx; - nk_draw_index index; - - nk_color_fv(&col_left.r, left); - nk_color_fv(&col_right.r, right); - nk_color_fv(&col_top.r, top); - nk_color_fv(&col_bottom.r, bottom); - - NK_ASSERT(list); - if (!list) return; - - nk_draw_list_push_image(list, list->config.null.texture); - index = (nk_draw_index)list->vertex_count; - vtx = nk_draw_list_alloc_vertices(list, 4); - idx = nk_draw_list_alloc_elements(list, 6); - if (!vtx || !idx) return; - - idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1); - idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0); - idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3); - - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y), list->config.null.uv, col_left); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y), list->config.null.uv, col_top); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y + rect.h), list->config.null.uv, col_right); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y + rect.h), list->config.null.uv, col_bottom); -} - -NK_API void -nk_draw_list_fill_triangle(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, struct nk_vec2 c, struct nk_color col) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, b); - nk_draw_list_path_line_to(list, c); - nk_draw_list_path_fill(list, col); -} - -NK_API void -nk_draw_list_stroke_triangle(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, struct nk_vec2 c, struct nk_color col, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, b); - nk_draw_list_path_line_to(list, c); - nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); -} - -NK_API void -nk_draw_list_fill_circle(struct nk_draw_list *list, struct nk_vec2 center, - float radius, struct nk_color col, unsigned int segs) -{ - float a_max; - NK_ASSERT(list); - if (!list || !col.a) return; - a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs; - nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs); - nk_draw_list_path_fill(list, col); -} - -NK_API void -nk_draw_list_stroke_circle(struct nk_draw_list *list, struct nk_vec2 center, - float radius, struct nk_color col, unsigned int segs, float thickness) -{ - float a_max; - NK_ASSERT(list); - if (!list || !col.a) return; - a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs; - nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs); - nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); -} - -NK_API void -nk_draw_list_stroke_curve(struct nk_draw_list *list, struct nk_vec2 p0, - struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, - struct nk_color col, unsigned int segments, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - nk_draw_list_path_line_to(list, p0); - nk_draw_list_path_curve_to(list, cp0, cp1, p1, segments); - nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness); -} - -NK_INTERN void -nk_draw_list_push_rect_uv(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 c, struct nk_vec2 uva, struct nk_vec2 uvc, - struct nk_color color) -{ - void *vtx; - struct nk_vec2 uvb; - struct nk_vec2 uvd; - struct nk_vec2 b; - struct nk_vec2 d; - - struct nk_colorf col; - nk_draw_index *idx; - nk_draw_index index; - NK_ASSERT(list); - if (!list) return; - - nk_color_fv(&col.r, color); - uvb = nk_vec2(uvc.x, uva.y); - uvd = nk_vec2(uva.x, uvc.y); - b = nk_vec2(c.x, a.y); - d = nk_vec2(a.x, c.y); - - index = (nk_draw_index)list->vertex_count; - vtx = nk_draw_list_alloc_vertices(list, 4); - idx = nk_draw_list_alloc_elements(list, 6); - if (!vtx || !idx) return; - - idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1); - idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0); - idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3); - - vtx = nk_draw_vertex(vtx, &list->config, a, uva, col); - vtx = nk_draw_vertex(vtx, &list->config, b, uvb, col); - vtx = nk_draw_vertex(vtx, &list->config, c, uvc, col); - vtx = nk_draw_vertex(vtx, &list->config, d, uvd, col); -} - -NK_API void -nk_draw_list_add_image(struct nk_draw_list *list, struct nk_image texture, - struct nk_rect rect, struct nk_color color) -{ - NK_ASSERT(list); - if (!list) return; - /* push new command with given texture */ - nk_draw_list_push_image(list, texture.handle); - if (nk_image_is_subimage(&texture)) { - /* add region inside of the texture */ - struct nk_vec2 uv[2]; - uv[0].x = (float)texture.region[0]/(float)texture.w; - uv[0].y = (float)texture.region[1]/(float)texture.h; - uv[1].x = (float)(texture.region[0] + texture.region[2])/(float)texture.w; - uv[1].y = (float)(texture.region[1] + texture.region[3])/(float)texture.h; - nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), uv[0], uv[1], color); - } else nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), - nk_vec2(0.0f, 0.0f), nk_vec2(1.0f, 1.0f),color); -} - -NK_API void -nk_draw_list_add_text(struct nk_draw_list *list, const struct nk_user_font *font, - struct nk_rect rect, const char *text, int len, float font_height, - struct nk_color fg) -{ - float x = 0; - int text_len = 0; - nk_rune unicode = 0; - nk_rune next = 0; - int glyph_len = 0; - int next_glyph_len = 0; - struct nk_user_font_glyph g; - - NK_ASSERT(list); - if (!list || !len || !text) return; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - list->clip_rect.x, list->clip_rect.y, list->clip_rect.w, list->clip_rect.h)) return; - - nk_draw_list_push_image(list, font->texture); - x = rect.x; - glyph_len = nk_utf_decode(text, &unicode, len); - if (!glyph_len) return; - - /* draw every glyph image */ - fg.a = (nk_byte)((float)fg.a * list->config.global_alpha); - while (text_len < len && glyph_len) { - float gx, gy, gh, gw; - float char_width = 0; - if (unicode == NK_UTF_INVALID) break; - - /* query currently drawn glyph information */ - next_glyph_len = nk_utf_decode(text + text_len + glyph_len, &next, (int)len - text_len); - font->query(font->userdata, font_height, &g, unicode, - (next == NK_UTF_INVALID) ? '\0' : next); - - /* calculate and draw glyph drawing rectangle and image */ - gx = x + g.offset.x; - gy = rect.y + g.offset.y; - gw = g.width; gh = g.height; - char_width = g.xadvance; - nk_draw_list_push_rect_uv(list, nk_vec2(gx,gy), nk_vec2(gx + gw, gy+ gh), - g.uv[0], g.uv[1], fg); - - /* offset next glyph */ - text_len += glyph_len; - x += char_width; - glyph_len = next_glyph_len; - unicode = next; - } -} - -NK_API nk_flags -nk_convert(struct nk_context *ctx, struct nk_buffer *cmds, - struct nk_buffer *vertices, struct nk_buffer *elements, - const struct nk_convert_config *config) -{ - nk_flags res = NK_CONVERT_SUCCESS; - const struct nk_command *cmd; - NK_ASSERT(ctx); - NK_ASSERT(cmds); - NK_ASSERT(vertices); - NK_ASSERT(elements); - NK_ASSERT(config); - NK_ASSERT(config->vertex_layout); - NK_ASSERT(config->vertex_size); - if (!ctx || !cmds || !vertices || !elements || !config || !config->vertex_layout) - return NK_CONVERT_INVALID_PARAM; - - nk_draw_list_setup(&ctx->draw_list, config, cmds, vertices, elements, - config->line_AA, config->shape_AA); - nk_foreach(cmd, ctx) - { -#ifdef NK_INCLUDE_COMMAND_USERDATA - ctx->draw_list.userdata = cmd->userdata; -#endif - switch (cmd->type) { - case NK_COMMAND_NOP: break; - case NK_COMMAND_SCISSOR: { - const struct nk_command_scissor *s = (const struct nk_command_scissor*)cmd; - nk_draw_list_add_clip(&ctx->draw_list, nk_rect(s->x, s->y, s->w, s->h)); - } break; - case NK_COMMAND_LINE: { - const struct nk_command_line *l = (const struct nk_command_line*)cmd; - nk_draw_list_stroke_line(&ctx->draw_list, nk_vec2(l->begin.x, l->begin.y), - nk_vec2(l->end.x, l->end.y), l->color, l->line_thickness); - } break; - case NK_COMMAND_CURVE: { - const struct nk_command_curve *q = (const struct nk_command_curve*)cmd; - nk_draw_list_stroke_curve(&ctx->draw_list, nk_vec2(q->begin.x, q->begin.y), - nk_vec2(q->ctrl[0].x, q->ctrl[0].y), nk_vec2(q->ctrl[1].x, - q->ctrl[1].y), nk_vec2(q->end.x, q->end.y), q->color, - config->curve_segment_count, q->line_thickness); - } break; - case NK_COMMAND_RECT: { - const struct nk_command_rect *r = (const struct nk_command_rect*)cmd; - nk_draw_list_stroke_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), - r->color, (float)r->rounding, r->line_thickness); - } break; - case NK_COMMAND_RECT_FILLED: { - const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled*)cmd; - nk_draw_list_fill_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), - r->color, (float)r->rounding); - } break; - case NK_COMMAND_RECT_MULTI_COLOR: { - const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color*)cmd; - nk_draw_list_fill_rect_multi_color(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), - r->left, r->top, r->right, r->bottom); - } break; - case NK_COMMAND_CIRCLE: { - const struct nk_command_circle *c = (const struct nk_command_circle*)cmd; - nk_draw_list_stroke_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2, - (float)c->y + (float)c->h/2), (float)c->w/2, c->color, - config->circle_segment_count, c->line_thickness); - } break; - case NK_COMMAND_CIRCLE_FILLED: { - const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd; - nk_draw_list_fill_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2, - (float)c->y + (float)c->h/2), (float)c->w/2, c->color, - config->circle_segment_count); - } break; - case NK_COMMAND_ARC: { - const struct nk_command_arc *c = (const struct nk_command_arc*)cmd; - nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy)); - nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r, - c->a[0], c->a[1], config->arc_segment_count); - nk_draw_list_path_stroke(&ctx->draw_list, c->color, NK_STROKE_CLOSED, c->line_thickness); - } break; - case NK_COMMAND_ARC_FILLED: { - const struct nk_command_arc_filled *c = (const struct nk_command_arc_filled*)cmd; - nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy)); - nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r, - c->a[0], c->a[1], config->arc_segment_count); - nk_draw_list_path_fill(&ctx->draw_list, c->color); - } break; - case NK_COMMAND_TRIANGLE: { - const struct nk_command_triangle *t = (const struct nk_command_triangle*)cmd; - nk_draw_list_stroke_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y), - nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color, - t->line_thickness); - } break; - case NK_COMMAND_TRIANGLE_FILLED: { - const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled*)cmd; - nk_draw_list_fill_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y), - nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color); - } break; - case NK_COMMAND_POLYGON: { - int i; - const struct nk_command_polygon*p = (const struct nk_command_polygon*)cmd; - for (i = 0; i < p->point_count; ++i) { - struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); - nk_draw_list_path_line_to(&ctx->draw_list, pnt); - } - nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_CLOSED, p->line_thickness); - } break; - case NK_COMMAND_POLYGON_FILLED: { - int i; - const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled*)cmd; - for (i = 0; i < p->point_count; ++i) { - struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); - nk_draw_list_path_line_to(&ctx->draw_list, pnt); - } - nk_draw_list_path_fill(&ctx->draw_list, p->color); - } break; - case NK_COMMAND_POLYLINE: { - int i; - const struct nk_command_polyline *p = (const struct nk_command_polyline*)cmd; - for (i = 0; i < p->point_count; ++i) { - struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); - nk_draw_list_path_line_to(&ctx->draw_list, pnt); - } - nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_OPEN, p->line_thickness); - } break; - case NK_COMMAND_TEXT: { - const struct nk_command_text *t = (const struct nk_command_text*)cmd; - nk_draw_list_add_text(&ctx->draw_list, t->font, nk_rect(t->x, t->y, t->w, t->h), - t->string, t->length, t->height, t->foreground); - } break; - case NK_COMMAND_IMAGE: { - const struct nk_command_image *i = (const struct nk_command_image*)cmd; - nk_draw_list_add_image(&ctx->draw_list, i->img, nk_rect(i->x, i->y, i->w, i->h), i->col); - } break; - case NK_COMMAND_CUSTOM: { - const struct nk_command_custom *c = (const struct nk_command_custom*)cmd; - c->callback(&ctx->draw_list, c->x, c->y, c->w, c->h, c->callback_data); - } break; - default: break; - } - } - res |= (cmds->needed > cmds->allocated + (cmds->memory.size - cmds->size)) ? NK_CONVERT_COMMAND_BUFFER_FULL: 0; - res |= (vertices->needed > vertices->allocated) ? NK_CONVERT_VERTEX_BUFFER_FULL: 0; - res |= (elements->needed > elements->allocated) ? NK_CONVERT_ELEMENT_BUFFER_FULL: 0; - return res; -} -NK_API const struct nk_draw_command* -nk__draw_begin(const struct nk_context *ctx, - const struct nk_buffer *buffer) -{return nk__draw_list_begin(&ctx->draw_list, buffer);} - -NK_API const struct nk_draw_command* -nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buffer) -{return nk__draw_list_end(&ctx->draw_list, buffer);} - -NK_API const struct nk_draw_command* -nk__draw_next(const struct nk_draw_command *cmd, - const struct nk_buffer *buffer, const struct nk_context *ctx) -{return nk__draw_list_next(cmd, buffer, &ctx->draw_list);} - -#endif - -/* - * ============================================================== - * - * FONT HANDLING - * - * =============================================================== - */ -#ifdef NK_INCLUDE_FONT_BAKING -/* ------------------------------------------------------------- - * - * RECT PACK - * - * --------------------------------------------------------------*/ -/* stb_rect_pack.h - v0.05 - public domain - rectangle packing */ -/* Sean Barrett 2014 */ -#define NK_RP__MAXVAL 0xffff -typedef unsigned short nk_rp_coord; - -struct nk_rp_rect { - /* reserved for your use: */ - int id; - /* input: */ - nk_rp_coord w, h; - /* output: */ - nk_rp_coord x, y; - int was_packed; - /* non-zero if valid packing */ -}; /* 16 bytes, nominally */ - -struct nk_rp_node { - nk_rp_coord x,y; - struct nk_rp_node *next; -}; - -struct nk_rp_context { - int width; - int height; - int align; - int init_mode; - int heuristic; - int num_nodes; - struct nk_rp_node *active_head; - struct nk_rp_node *free_head; - struct nk_rp_node extra[2]; - /* we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' */ -}; - -struct nk_rp__findresult { - int x,y; - struct nk_rp_node **prev_link; -}; - -enum NK_RP_HEURISTIC { - NK_RP_HEURISTIC_Skyline_default=0, - NK_RP_HEURISTIC_Skyline_BL_sortHeight = NK_RP_HEURISTIC_Skyline_default, - NK_RP_HEURISTIC_Skyline_BF_sortHeight -}; -enum NK_RP_INIT_STATE{NK_RP__INIT_skyline = 1}; - -NK_INTERN void -nk_rp_setup_allow_out_of_mem(struct nk_rp_context *context, int allow_out_of_mem) -{ - if (allow_out_of_mem) - /* if it's ok to run out of memory, then don't bother aligning them; */ - /* this gives better packing, but may fail due to OOM (even though */ - /* the rectangles easily fit). @TODO a smarter approach would be to only */ - /* quantize once we've hit OOM, then we could get rid of this parameter. */ - context->align = 1; - else { - /* if it's not ok to run out of memory, then quantize the widths */ - /* so that num_nodes is always enough nodes. */ - /* */ - /* I.e. num_nodes * align >= width */ - /* align >= width / num_nodes */ - /* align = ceil(width/num_nodes) */ - context->align = (context->width + context->num_nodes-1) / context->num_nodes; - } -} - -NK_INTERN void -nk_rp_init_target(struct nk_rp_context *context, int width, int height, - struct nk_rp_node *nodes, int num_nodes) -{ - int i; -#ifndef STBRP_LARGE_RECTS - NK_ASSERT(width <= 0xffff && height <= 0xffff); -#endif - - for (i=0; i < num_nodes-1; ++i) - nodes[i].next = &nodes[i+1]; - nodes[i].next = 0; - context->init_mode = NK_RP__INIT_skyline; - context->heuristic = NK_RP_HEURISTIC_Skyline_default; - context->free_head = &nodes[0]; - context->active_head = &context->extra[0]; - context->width = width; - context->height = height; - context->num_nodes = num_nodes; - nk_rp_setup_allow_out_of_mem(context, 0); - - /* node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) */ - context->extra[0].x = 0; - context->extra[0].y = 0; - context->extra[0].next = &context->extra[1]; - context->extra[1].x = (nk_rp_coord) width; - context->extra[1].y = 65535; - context->extra[1].next = 0; -} - -/* find minimum y position if it starts at x1 */ -NK_INTERN int -nk_rp__skyline_find_min_y(struct nk_rp_context *c, struct nk_rp_node *first, - int x0, int width, int *pwaste) -{ - struct nk_rp_node *node = first; - int x1 = x0 + width; - int min_y, visited_width, waste_area; - NK_ASSERT(first->x <= x0); - NK_UNUSED(c); - - NK_ASSERT(node->next->x > x0); - /* we ended up handling this in the caller for efficiency */ - NK_ASSERT(node->x <= x0); - - min_y = 0; - waste_area = 0; - visited_width = 0; - while (node->x < x1) - { - if (node->y > min_y) { - /* raise min_y higher. */ - /* we've accounted for all waste up to min_y, */ - /* but we'll now add more waste for everything we've visited */ - waste_area += visited_width * (node->y - min_y); - min_y = node->y; - /* the first time through, visited_width might be reduced */ - if (node->x < x0) - visited_width += node->next->x - x0; - else - visited_width += node->next->x - node->x; - } else { - /* add waste area */ - int under_width = node->next->x - node->x; - if (under_width + visited_width > width) - under_width = width - visited_width; - waste_area += under_width * (min_y - node->y); - visited_width += under_width; - } - node = node->next; - } - *pwaste = waste_area; - return min_y; -} - -NK_INTERN struct nk_rp__findresult -nk_rp__skyline_find_best_pos(struct nk_rp_context *c, int width, int height) -{ - int best_waste = (1<<30), best_x, best_y = (1 << 30); - struct nk_rp__findresult fr; - struct nk_rp_node **prev, *node, *tail, **best = 0; - - /* align to multiple of c->align */ - width = (width + c->align - 1); - width -= width % c->align; - NK_ASSERT(width % c->align == 0); - - node = c->active_head; - prev = &c->active_head; - while (node->x + width <= c->width) { - int y,waste; - y = nk_rp__skyline_find_min_y(c, node, node->x, width, &waste); - /* actually just want to test BL */ - if (c->heuristic == NK_RP_HEURISTIC_Skyline_BL_sortHeight) { - /* bottom left */ - if (y < best_y) { - best_y = y; - best = prev; - } - } else { - /* best-fit */ - if (y + height <= c->height) { - /* can only use it if it first vertically */ - if (y < best_y || (y == best_y && waste < best_waste)) { - best_y = y; - best_waste = waste; - best = prev; - } - } - } - prev = &node->next; - node = node->next; - } - best_x = (best == 0) ? 0 : (*best)->x; - - /* if doing best-fit (BF), we also have to try aligning right edge to each node position */ - /* */ - /* e.g, if fitting */ - /* */ - /* ____________________ */ - /* |____________________| */ - /* */ - /* into */ - /* */ - /* | | */ - /* | ____________| */ - /* |____________| */ - /* */ - /* then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned */ - /* */ - /* This makes BF take about 2x the time */ - if (c->heuristic == NK_RP_HEURISTIC_Skyline_BF_sortHeight) - { - tail = c->active_head; - node = c->active_head; - prev = &c->active_head; - /* find first node that's admissible */ - while (tail->x < width) - tail = tail->next; - while (tail) - { - int xpos = tail->x - width; - int y,waste; - NK_ASSERT(xpos >= 0); - /* find the left position that matches this */ - while (node->next->x <= xpos) { - prev = &node->next; - node = node->next; - } - NK_ASSERT(node->next->x > xpos && node->x <= xpos); - y = nk_rp__skyline_find_min_y(c, node, xpos, width, &waste); - if (y + height < c->height) { - if (y <= best_y) { - if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { - best_x = xpos; - NK_ASSERT(y <= best_y); - best_y = y; - best_waste = waste; - best = prev; - } - } - } - tail = tail->next; - } - } - fr.prev_link = best; - fr.x = best_x; - fr.y = best_y; - return fr; -} - -NK_INTERN struct nk_rp__findresult -nk_rp__skyline_pack_rectangle(struct nk_rp_context *context, int width, int height) -{ - /* find best position according to heuristic */ - struct nk_rp__findresult res = nk_rp__skyline_find_best_pos(context, width, height); - struct nk_rp_node *node, *cur; - - /* bail if: */ - /* 1. it failed */ - /* 2. the best node doesn't fit (we don't always check this) */ - /* 3. we're out of memory */ - if (res.prev_link == 0 || res.y + height > context->height || context->free_head == 0) { - res.prev_link = 0; - return res; - } - - /* on success, create new node */ - node = context->free_head; - node->x = (nk_rp_coord) res.x; - node->y = (nk_rp_coord) (res.y + height); - - context->free_head = node->next; - - /* insert the new node into the right starting point, and */ - /* let 'cur' point to the remaining nodes needing to be */ - /* stitched back in */ - cur = *res.prev_link; - if (cur->x < res.x) { - /* preserve the existing one, so start testing with the next one */ - struct nk_rp_node *next = cur->next; - cur->next = node; - cur = next; - } else { - *res.prev_link = node; - } - - /* from here, traverse cur and free the nodes, until we get to one */ - /* that shouldn't be freed */ - while (cur->next && cur->next->x <= res.x + width) { - struct nk_rp_node *next = cur->next; - /* move the current node to the free list */ - cur->next = context->free_head; - context->free_head = cur; - cur = next; - } - /* stitch the list back in */ - node->next = cur; - - if (cur->x < res.x + width) - cur->x = (nk_rp_coord) (res.x + width); - return res; -} - -NK_INTERN int -nk_rect_height_compare(const void *a, const void *b) -{ - const struct nk_rp_rect *p = (const struct nk_rp_rect *) a; - const struct nk_rp_rect *q = (const struct nk_rp_rect *) b; - if (p->h > q->h) - return -1; - if (p->h < q->h) - return 1; - return (p->w > q->w) ? -1 : (p->w < q->w); -} - -NK_INTERN int -nk_rect_original_order(const void *a, const void *b) -{ - const struct nk_rp_rect *p = (const struct nk_rp_rect *) a; - const struct nk_rp_rect *q = (const struct nk_rp_rect *) b; - return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); -} - -NK_INTERN void -nk_rp_qsort(struct nk_rp_rect *array, unsigned int len, int(*cmp)(const void*,const void*)) -{ - /* iterative quick sort */ - #define NK_MAX_SORT_STACK 64 - unsigned right, left = 0, stack[NK_MAX_SORT_STACK], pos = 0; - unsigned seed = len/2 * 69069+1; - for (;;) { - for (; left+1 < len; len++) { - struct nk_rp_rect pivot, tmp; - if (pos == NK_MAX_SORT_STACK) len = stack[pos = 0]; - pivot = array[left+seed%(len-left)]; - seed = seed * 69069 + 1; - stack[pos++] = len; - for (right = left-1;;) { - while (cmp(&array[++right], &pivot) < 0); - while (cmp(&pivot, &array[--len]) < 0); - if (right >= len) break; - tmp = array[right]; - array[right] = array[len]; - array[len] = tmp; - } - } - if (pos == 0) break; - left = len; - len = stack[--pos]; - } - #undef NK_MAX_SORT_STACK -} - -NK_INTERN void -nk_rp_pack_rects(struct nk_rp_context *context, struct nk_rp_rect *rects, int num_rects) -{ - int i; - /* we use the 'was_packed' field internally to allow sorting/unsorting */ - for (i=0; i < num_rects; ++i) { - rects[i].was_packed = i; - } - - /* sort according to heuristic */ - nk_rp_qsort(rects, (unsigned)num_rects, nk_rect_height_compare); - - for (i=0; i < num_rects; ++i) { - struct nk_rp__findresult fr = nk_rp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); - if (fr.prev_link) { - rects[i].x = (nk_rp_coord) fr.x; - rects[i].y = (nk_rp_coord) fr.y; - } else { - rects[i].x = rects[i].y = NK_RP__MAXVAL; - } - } - - /* unsort */ - nk_rp_qsort(rects, (unsigned)num_rects, nk_rect_original_order); - - /* set was_packed flags */ - for (i=0; i < num_rects; ++i) - rects[i].was_packed = !(rects[i].x == NK_RP__MAXVAL && rects[i].y == NK_RP__MAXVAL); -} - -/* - * ============================================================== - * - * TRUETYPE - * - * =============================================================== - */ -/* stb_truetype.h - v1.07 - public domain */ -#define NK_TT_MAX_OVERSAMPLE 8 -#define NK_TT__OVER_MASK (NK_TT_MAX_OVERSAMPLE-1) - -struct nk_tt_bakedchar { - unsigned short x0,y0,x1,y1; - /* coordinates of bbox in bitmap */ - float xoff,yoff,xadvance; -}; - -struct nk_tt_aligned_quad{ - float x0,y0,s0,t0; /* top-left */ - float x1,y1,s1,t1; /* bottom-right */ -}; - -struct nk_tt_packedchar { - unsigned short x0,y0,x1,y1; - /* coordinates of bbox in bitmap */ - float xoff,yoff,xadvance; - float xoff2,yoff2; -}; - -struct nk_tt_pack_range { - float font_size; - int first_unicode_codepoint_in_range; - /* if non-zero, then the chars are continuous, and this is the first codepoint */ - int *array_of_unicode_codepoints; - /* if non-zero, then this is an array of unicode codepoints */ - int num_chars; - struct nk_tt_packedchar *chardata_for_range; /* output */ - unsigned char h_oversample, v_oversample; - /* don't set these, they're used internally */ -}; - -struct nk_tt_pack_context { - void *pack_info; - int width; - int height; - int stride_in_bytes; - int padding; - unsigned int h_oversample, v_oversample; - unsigned char *pixels; - void *nodes; -}; - -struct nk_tt_fontinfo { - const unsigned char* data; /* pointer to .ttf file */ - int fontstart;/* offset of start of font */ - int numGlyphs;/* number of glyphs, needed for range checking */ - int loca,head,glyf,hhea,hmtx,kern; /* table locations as offset from start of .ttf */ - int index_map; /* a cmap mapping for our chosen character encoding */ - int indexToLocFormat; /* format needed to map from glyph index to glyph */ -}; - -enum { - NK_TT_vmove=1, - NK_TT_vline, - NK_TT_vcurve -}; - -struct nk_tt_vertex { - short x,y,cx,cy; - unsigned char type,padding; -}; - -struct nk_tt__bitmap{ - int w,h,stride; - unsigned char *pixels; -}; - -struct nk_tt__hheap_chunk { - struct nk_tt__hheap_chunk *next; -}; -struct nk_tt__hheap { - struct nk_allocator alloc; - struct nk_tt__hheap_chunk *head; - void *first_free; - int num_remaining_in_head_chunk; -}; - -struct nk_tt__edge { - float x0,y0, x1,y1; - int invert; -}; - -struct nk_tt__active_edge { - struct nk_tt__active_edge *next; - float fx,fdx,fdy; - float direction; - float sy; - float ey; -}; -struct nk_tt__point {float x,y;}; - -#define NK_TT_MACSTYLE_DONTCARE 0 -#define NK_TT_MACSTYLE_BOLD 1 -#define NK_TT_MACSTYLE_ITALIC 2 -#define NK_TT_MACSTYLE_UNDERSCORE 4 -#define NK_TT_MACSTYLE_NONE 8 -/* <= not same as 0, this makes us check the bitfield is 0 */ - -enum { /* platformID */ - NK_TT_PLATFORM_ID_UNICODE =0, - NK_TT_PLATFORM_ID_MAC =1, - NK_TT_PLATFORM_ID_ISO =2, - NK_TT_PLATFORM_ID_MICROSOFT =3 -}; - -enum { /* encodingID for NK_TT_PLATFORM_ID_UNICODE */ - NK_TT_UNICODE_EID_UNICODE_1_0 =0, - NK_TT_UNICODE_EID_UNICODE_1_1 =1, - NK_TT_UNICODE_EID_ISO_10646 =2, - NK_TT_UNICODE_EID_UNICODE_2_0_BMP=3, - NK_TT_UNICODE_EID_UNICODE_2_0_FULL=4 -}; - -enum { /* encodingID for NK_TT_PLATFORM_ID_MICROSOFT */ - NK_TT_MS_EID_SYMBOL =0, - NK_TT_MS_EID_UNICODE_BMP =1, - NK_TT_MS_EID_SHIFTJIS =2, - NK_TT_MS_EID_UNICODE_FULL =10 -}; - -enum { /* encodingID for NK_TT_PLATFORM_ID_MAC; same as Script Manager codes */ - NK_TT_MAC_EID_ROMAN =0, NK_TT_MAC_EID_ARABIC =4, - NK_TT_MAC_EID_JAPANESE =1, NK_TT_MAC_EID_HEBREW =5, - NK_TT_MAC_EID_CHINESE_TRAD =2, NK_TT_MAC_EID_GREEK =6, - NK_TT_MAC_EID_KOREAN =3, NK_TT_MAC_EID_RUSSIAN =7 -}; - -enum { /* languageID for NK_TT_PLATFORM_ID_MICROSOFT; same as LCID... */ - /* problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs */ - NK_TT_MS_LANG_ENGLISH =0x0409, NK_TT_MS_LANG_ITALIAN =0x0410, - NK_TT_MS_LANG_CHINESE =0x0804, NK_TT_MS_LANG_JAPANESE =0x0411, - NK_TT_MS_LANG_DUTCH =0x0413, NK_TT_MS_LANG_KOREAN =0x0412, - NK_TT_MS_LANG_FRENCH =0x040c, NK_TT_MS_LANG_RUSSIAN =0x0419, - NK_TT_MS_LANG_GERMAN =0x0407, NK_TT_MS_LANG_SPANISH =0x0409, - NK_TT_MS_LANG_HEBREW =0x040d, NK_TT_MS_LANG_SWEDISH =0x041D -}; - -enum { /* languageID for NK_TT_PLATFORM_ID_MAC */ - NK_TT_MAC_LANG_ENGLISH =0 , NK_TT_MAC_LANG_JAPANESE =11, - NK_TT_MAC_LANG_ARABIC =12, NK_TT_MAC_LANG_KOREAN =23, - NK_TT_MAC_LANG_DUTCH =4 , NK_TT_MAC_LANG_RUSSIAN =32, - NK_TT_MAC_LANG_FRENCH =1 , NK_TT_MAC_LANG_SPANISH =6 , - NK_TT_MAC_LANG_GERMAN =2 , NK_TT_MAC_LANG_SWEDISH =5 , - NK_TT_MAC_LANG_HEBREW =10, NK_TT_MAC_LANG_CHINESE_SIMPLIFIED =33, - NK_TT_MAC_LANG_ITALIAN =3 , NK_TT_MAC_LANG_CHINESE_TRAD =19 -}; - -#define nk_ttBYTE(p) (* (const nk_byte *) (p)) -#define nk_ttCHAR(p) (* (const char *) (p)) - -#if defined(NK_BIGENDIAN) && !defined(NK_ALLOW_UNALIGNED_TRUETYPE) - #define nk_ttUSHORT(p) (* (nk_ushort *) (p)) - #define nk_ttSHORT(p) (* (nk_short *) (p)) - #define nk_ttULONG(p) (* (nk_uint *) (p)) - #define nk_ttLONG(p) (* (nk_int *) (p)) -#else - static nk_ushort nk_ttUSHORT(const nk_byte *p) { return (nk_ushort)(p[0]*256 + p[1]); } - static nk_short nk_ttSHORT(const nk_byte *p) { return (nk_short)(p[0]*256 + p[1]); } - static nk_uint nk_ttULONG(const nk_byte *p) { return (nk_uint)((p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]); } -#endif - -#define nk_tt_tag4(p,c0,c1,c2,c3)\ - ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) -#define nk_tt_tag(p,str) nk_tt_tag4(p,str[0],str[1],str[2],str[3]) - -NK_INTERN int nk_tt_GetGlyphShape(const struct nk_tt_fontinfo *info, struct nk_allocator *alloc, - int glyph_index, struct nk_tt_vertex **pvertices); - -NK_INTERN nk_uint -nk_tt__find_table(const nk_byte *data, nk_uint fontstart, const char *tag) -{ - /* @OPTIMIZE: binary search */ - nk_int num_tables = nk_ttUSHORT(data+fontstart+4); - nk_uint tabledir = fontstart + 12; - nk_int i; - for (i = 0; i < num_tables; ++i) { - nk_uint loc = tabledir + (nk_uint)(16*i); - if (nk_tt_tag(data+loc+0, tag)) - return nk_ttULONG(data+loc+8); - } - return 0; -} - -NK_INTERN int -nk_tt_InitFont(struct nk_tt_fontinfo *info, const unsigned char *data2, int fontstart) -{ - nk_uint cmap, t; - nk_int i,numTables; - const nk_byte *data = (const nk_byte *) data2; - - info->data = data; - info->fontstart = fontstart; - - cmap = nk_tt__find_table(data, (nk_uint)fontstart, "cmap"); /* required */ - info->loca = (int)nk_tt__find_table(data, (nk_uint)fontstart, "loca"); /* required */ - info->head = (int)nk_tt__find_table(data, (nk_uint)fontstart, "head"); /* required */ - info->glyf = (int)nk_tt__find_table(data, (nk_uint)fontstart, "glyf"); /* required */ - info->hhea = (int)nk_tt__find_table(data, (nk_uint)fontstart, "hhea"); /* required */ - info->hmtx = (int)nk_tt__find_table(data, (nk_uint)fontstart, "hmtx"); /* required */ - info->kern = (int)nk_tt__find_table(data, (nk_uint)fontstart, "kern"); /* not required */ - if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx) - return 0; - - t = nk_tt__find_table(data, (nk_uint)fontstart, "maxp"); - if (t) info->numGlyphs = nk_ttUSHORT(data+t+4); - else info->numGlyphs = 0xffff; - - /* find a cmap encoding table we understand *now* to avoid searching */ - /* later. (todo: could make this installable) */ - /* the same regardless of glyph. */ - numTables = nk_ttUSHORT(data + cmap + 2); - info->index_map = 0; - for (i=0; i < numTables; ++i) - { - nk_uint encoding_record = cmap + 4 + 8 * (nk_uint)i; - /* find an encoding we understand: */ - switch(nk_ttUSHORT(data+encoding_record)) { - case NK_TT_PLATFORM_ID_MICROSOFT: - switch (nk_ttUSHORT(data+encoding_record+2)) { - case NK_TT_MS_EID_UNICODE_BMP: - case NK_TT_MS_EID_UNICODE_FULL: - /* MS/Unicode */ - info->index_map = (int)(cmap + nk_ttULONG(data+encoding_record+4)); - break; - default: break; - } break; - case NK_TT_PLATFORM_ID_UNICODE: - /* Mac/iOS has these */ - /* all the encodingIDs are unicode, so we don't bother to check it */ - info->index_map = (int)(cmap + nk_ttULONG(data+encoding_record+4)); - break; - default: break; - } - } - if (info->index_map == 0) - return 0; - info->indexToLocFormat = nk_ttUSHORT(data+info->head + 50); - return 1; -} - -NK_INTERN int -nk_tt_FindGlyphIndex(const struct nk_tt_fontinfo *info, int unicode_codepoint) -{ - const nk_byte *data = info->data; - nk_uint index_map = (nk_uint)info->index_map; - - nk_ushort format = nk_ttUSHORT(data + index_map + 0); - if (format == 0) { /* apple byte encoding */ - nk_int bytes = nk_ttUSHORT(data + index_map + 2); - if (unicode_codepoint < bytes-6) - return nk_ttBYTE(data + index_map + 6 + unicode_codepoint); - return 0; - } else if (format == 6) { - nk_uint first = nk_ttUSHORT(data + index_map + 6); - nk_uint count = nk_ttUSHORT(data + index_map + 8); - if ((nk_uint) unicode_codepoint >= first && (nk_uint) unicode_codepoint < first+count) - return nk_ttUSHORT(data + index_map + 10 + (unicode_codepoint - (int)first)*2); - return 0; - } else if (format == 2) { - NK_ASSERT(0); /* @TODO: high-byte mapping for japanese/chinese/korean */ - return 0; - } else if (format == 4) { /* standard mapping for windows fonts: binary search collection of ranges */ - nk_ushort segcount = nk_ttUSHORT(data+index_map+6) >> 1; - nk_ushort searchRange = nk_ttUSHORT(data+index_map+8) >> 1; - nk_ushort entrySelector = nk_ttUSHORT(data+index_map+10); - nk_ushort rangeShift = nk_ttUSHORT(data+index_map+12) >> 1; - - /* do a binary search of the segments */ - nk_uint endCount = index_map + 14; - nk_uint search = endCount; - - if (unicode_codepoint > 0xffff) - return 0; - - /* they lie from endCount .. endCount + segCount */ - /* but searchRange is the nearest power of two, so... */ - if (unicode_codepoint >= nk_ttUSHORT(data + search + rangeShift*2)) - search += (nk_uint)(rangeShift*2); - - /* now decrement to bias correctly to find smallest */ - search -= 2; - while (entrySelector) { - nk_ushort end; - searchRange >>= 1; - end = nk_ttUSHORT(data + search + searchRange*2); - if (unicode_codepoint > end) - search += (nk_uint)(searchRange*2); - --entrySelector; - } - search += 2; - - { - nk_ushort offset, start; - nk_ushort item = (nk_ushort) ((search - endCount) >> 1); - - NK_ASSERT(unicode_codepoint <= nk_ttUSHORT(data + endCount + 2*item)); - start = nk_ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - if (unicode_codepoint < start) - return 0; - - offset = nk_ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); - if (offset == 0) - return (nk_ushort) (unicode_codepoint + nk_ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); - - return nk_ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); - } - } else if (format == 12 || format == 13) { - nk_uint ngroups = nk_ttULONG(data+index_map+12); - nk_int low,high; - low = 0; high = (nk_int)ngroups; - /* Binary search the right group. */ - while (low < high) { - nk_int mid = low + ((high-low) >> 1); /* rounds down, so low <= mid < high */ - nk_uint start_char = nk_ttULONG(data+index_map+16+mid*12); - nk_uint end_char = nk_ttULONG(data+index_map+16+mid*12+4); - if ((nk_uint) unicode_codepoint < start_char) - high = mid; - else if ((nk_uint) unicode_codepoint > end_char) - low = mid+1; - else { - nk_uint start_glyph = nk_ttULONG(data+index_map+16+mid*12+8); - if (format == 12) - return (int)start_glyph + (int)unicode_codepoint - (int)start_char; - else /* format == 13 */ - return (int)start_glyph; - } - } - return 0; /* not found */ - } - /* @TODO */ - NK_ASSERT(0); - return 0; -} - -NK_INTERN void -nk_tt_setvertex(struct nk_tt_vertex *v, nk_byte type, nk_int x, nk_int y, nk_int cx, nk_int cy) -{ - v->type = type; - v->x = (nk_short) x; - v->y = (nk_short) y; - v->cx = (nk_short) cx; - v->cy = (nk_short) cy; -} - -NK_INTERN int -nk_tt__GetGlyfOffset(const struct nk_tt_fontinfo *info, int glyph_index) -{ - int g1,g2; - if (glyph_index >= info->numGlyphs) return -1; /* glyph index out of range */ - if (info->indexToLocFormat >= 2) return -1; /* unknown index->glyph map format */ - - if (info->indexToLocFormat == 0) { - g1 = info->glyf + nk_ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; - g2 = info->glyf + nk_ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; - } else { - g1 = info->glyf + (int)nk_ttULONG (info->data + info->loca + glyph_index * 4); - g2 = info->glyf + (int)nk_ttULONG (info->data + info->loca + glyph_index * 4 + 4); - } - return g1==g2 ? -1 : g1; /* if length is 0, return -1 */ -} - -NK_INTERN int -nk_tt_GetGlyphBox(const struct nk_tt_fontinfo *info, int glyph_index, - int *x0, int *y0, int *x1, int *y1) -{ - int g = nk_tt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 0; - - if (x0) *x0 = nk_ttSHORT(info->data + g + 2); - if (y0) *y0 = nk_ttSHORT(info->data + g + 4); - if (x1) *x1 = nk_ttSHORT(info->data + g + 6); - if (y1) *y1 = nk_ttSHORT(info->data + g + 8); - return 1; -} - -NK_INTERN int -stbtt__close_shape(struct nk_tt_vertex *vertices, int num_vertices, int was_off, - int start_off, nk_int sx, nk_int sy, nk_int scx, nk_int scy, nk_int cx, nk_int cy) -{ - if (start_off) { - if (was_off) - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, sx,sy,scx,scy); - } else { - if (was_off) - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve,sx,sy,cx,cy); - else - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vline,sx,sy,0,0); - } - return num_vertices; -} - -NK_INTERN int -nk_tt_GetGlyphShape(const struct nk_tt_fontinfo *info, struct nk_allocator *alloc, - int glyph_index, struct nk_tt_vertex **pvertices) -{ - nk_short numberOfContours; - const nk_byte *endPtsOfContours; - const nk_byte *data = info->data; - struct nk_tt_vertex *vertices=0; - int num_vertices=0; - int g = nk_tt__GetGlyfOffset(info, glyph_index); - *pvertices = 0; - - if (g < 0) return 0; - numberOfContours = nk_ttSHORT(data + g); - if (numberOfContours > 0) { - nk_byte flags=0,flagcount; - nk_int ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; - nk_int x,y,cx,cy,sx,sy, scx,scy; - const nk_byte *points; - endPtsOfContours = (data + g + 10); - ins = nk_ttUSHORT(data + g + 10 + numberOfContours * 2); - points = data + g + 10 + numberOfContours * 2 + 2 + ins; - - n = 1+nk_ttUSHORT(endPtsOfContours + numberOfContours*2-2); - m = n + 2*numberOfContours; /* a loose bound on how many vertices we might need */ - vertices = (struct nk_tt_vertex *)alloc->alloc(alloc->userdata, 0, (nk_size)m * sizeof(vertices[0])); - if (vertices == 0) - return 0; - - next_move = 0; - flagcount=0; - - /* in first pass, we load uninterpreted data into the allocated array */ - /* above, shifted to the end of the array so we won't overwrite it when */ - /* we create our final data starting from the front */ - off = m - n; /* starting offset for uninterpreted data, regardless of how m ends up being calculated */ - - /* first load flags */ - for (i=0; i < n; ++i) { - if (flagcount == 0) { - flags = *points++; - if (flags & 8) - flagcount = *points++; - } else --flagcount; - vertices[off+i].type = flags; - } - - /* now load x coordinates */ - x=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 2) { - nk_short dx = *points++; - x += (flags & 16) ? dx : -dx; /* ??? */ - } else { - if (!(flags & 16)) { - x = x + (nk_short) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].x = (nk_short) x; - } - - /* now load y coordinates */ - y=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 4) { - nk_short dy = *points++; - y += (flags & 32) ? dy : -dy; /* ??? */ - } else { - if (!(flags & 32)) { - y = y + (nk_short) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].y = (nk_short) y; - } - - /* now convert them to our format */ - num_vertices=0; - sx = sy = cx = cy = scx = scy = 0; - for (i=0; i < n; ++i) - { - flags = vertices[off+i].type; - x = (nk_short) vertices[off+i].x; - y = (nk_short) vertices[off+i].y; - - if (next_move == i) { - if (i != 0) - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - - /* now start the new one */ - start_off = !(flags & 1); - if (start_off) { - /* if we start off with an off-curve point, then when we need to find a point on the curve */ - /* where we can start, and we need to save some state for when we wraparound. */ - scx = x; - scy = y; - if (!(vertices[off+i+1].type & 1)) { - /* next point is also a curve point, so interpolate an on-point curve */ - sx = (x + (nk_int) vertices[off+i+1].x) >> 1; - sy = (y + (nk_int) vertices[off+i+1].y) >> 1; - } else { - /* otherwise just use the next point as our start point */ - sx = (nk_int) vertices[off+i+1].x; - sy = (nk_int) vertices[off+i+1].y; - ++i; /* we're using point i+1 as the starting point, so skip it */ - } - } else { - sx = x; - sy = y; - } - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vmove,sx,sy,0,0); - was_off = 0; - next_move = 1 + nk_ttUSHORT(endPtsOfContours+j*2); - ++j; - } else { - if (!(flags & 1)) - { /* if it's a curve */ - if (was_off) /* two off-curve control points in a row means interpolate an on-curve midpoint */ - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); - cx = x; - cy = y; - was_off = 1; - } else { - if (was_off) - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, x,y, cx, cy); - else nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vline, x,y,0,0); - was_off = 0; - } - } - } - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - } else if (numberOfContours == -1) { - /* Compound shapes. */ - int more = 1; - const nk_byte *comp = data + g + 10; - num_vertices = 0; - vertices = 0; - - while (more) - { - nk_ushort flags, gidx; - int comp_num_verts = 0, i; - struct nk_tt_vertex *comp_verts = 0, *tmp = 0; - float mtx[6] = {1,0,0,1,0,0}, m, n; - - flags = (nk_ushort)nk_ttSHORT(comp); comp+=2; - gidx = (nk_ushort)nk_ttSHORT(comp); comp+=2; - - if (flags & 2) { /* XY values */ - if (flags & 1) { /* shorts */ - mtx[4] = nk_ttSHORT(comp); comp+=2; - mtx[5] = nk_ttSHORT(comp); comp+=2; - } else { - mtx[4] = nk_ttCHAR(comp); comp+=1; - mtx[5] = nk_ttCHAR(comp); comp+=1; - } - } else { - /* @TODO handle matching point */ - NK_ASSERT(0); - } - if (flags & (1<<3)) { /* WE_HAVE_A_SCALE */ - mtx[0] = mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - } else if (flags & (1<<6)) { /* WE_HAVE_AN_X_AND_YSCALE */ - mtx[0] = nk_ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2; - } else if (flags & (1<<7)) { /* WE_HAVE_A_TWO_BY_TWO */ - mtx[0] = nk_ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = nk_ttSHORT(comp)/16384.0f; comp+=2; - mtx[2] = nk_ttSHORT(comp)/16384.0f; comp+=2; - mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2; - } - - /* Find transformation scales. */ - m = (float) NK_SQRT(mtx[0]*mtx[0] + mtx[1]*mtx[1]); - n = (float) NK_SQRT(mtx[2]*mtx[2] + mtx[3]*mtx[3]); - - /* Get indexed glyph. */ - comp_num_verts = nk_tt_GetGlyphShape(info, alloc, gidx, &comp_verts); - if (comp_num_verts > 0) - { - /* Transform vertices. */ - for (i = 0; i < comp_num_verts; ++i) { - struct nk_tt_vertex* v = &comp_verts[i]; - short x,y; - x=v->x; y=v->y; - v->x = (short)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->y = (short)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - x=v->cx; y=v->cy; - v->cx = (short)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->cy = (short)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - } - /* Append vertices. */ - tmp = (struct nk_tt_vertex*)alloc->alloc(alloc->userdata, 0, - (nk_size)(num_vertices+comp_num_verts)*sizeof(struct nk_tt_vertex)); - if (!tmp) { - if (vertices) alloc->free(alloc->userdata, vertices); - if (comp_verts) alloc->free(alloc->userdata, comp_verts); - return 0; - } - if (num_vertices > 0) NK_MEMCPY(tmp, vertices, (nk_size)num_vertices*sizeof(struct nk_tt_vertex)); - NK_MEMCPY(tmp+num_vertices, comp_verts, (nk_size)comp_num_verts*sizeof(struct nk_tt_vertex)); - if (vertices) alloc->free(alloc->userdata,vertices); - vertices = tmp; - alloc->free(alloc->userdata,comp_verts); - num_vertices += comp_num_verts; - } - /* More components ? */ - more = flags & (1<<5); - } - } else if (numberOfContours < 0) { - /* @TODO other compound variations? */ - NK_ASSERT(0); - } else { - /* numberOfCounters == 0, do nothing */ - } - *pvertices = vertices; - return num_vertices; -} - -NK_INTERN void -nk_tt_GetGlyphHMetrics(const struct nk_tt_fontinfo *info, int glyph_index, - int *advanceWidth, int *leftSideBearing) -{ - nk_ushort numOfLongHorMetrics = nk_ttUSHORT(info->data+info->hhea + 34); - if (glyph_index < numOfLongHorMetrics) { - if (advanceWidth) - *advanceWidth = nk_ttSHORT(info->data + info->hmtx + 4*glyph_index); - if (leftSideBearing) - *leftSideBearing = nk_ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); - } else { - if (advanceWidth) - *advanceWidth = nk_ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); - if (leftSideBearing) - *leftSideBearing = nk_ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); - } -} - -NK_INTERN void -nk_tt_GetFontVMetrics(const struct nk_tt_fontinfo *info, - int *ascent, int *descent, int *lineGap) -{ - if (ascent ) *ascent = nk_ttSHORT(info->data+info->hhea + 4); - if (descent) *descent = nk_ttSHORT(info->data+info->hhea + 6); - if (lineGap) *lineGap = nk_ttSHORT(info->data+info->hhea + 8); -} - -NK_INTERN float -nk_tt_ScaleForPixelHeight(const struct nk_tt_fontinfo *info, float height) -{ - int fheight = nk_ttSHORT(info->data + info->hhea + 4) - nk_ttSHORT(info->data + info->hhea + 6); - return (float) height / (float)fheight; -} - -NK_INTERN float -nk_tt_ScaleForMappingEmToPixels(const struct nk_tt_fontinfo *info, float pixels) -{ - int unitsPerEm = nk_ttUSHORT(info->data + info->head + 18); - return pixels / (float)unitsPerEm; -} - -/*------------------------------------------------------------- - * antialiasing software rasterizer - * --------------------------------------------------------------*/ -NK_INTERN void -nk_tt_GetGlyphBitmapBoxSubpixel(const struct nk_tt_fontinfo *font, - int glyph, float scale_x, float scale_y,float shift_x, float shift_y, - int *ix0, int *iy0, int *ix1, int *iy1) -{ - int x0,y0,x1,y1; - if (!nk_tt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { - /* e.g. space character */ - if (ix0) *ix0 = 0; - if (iy0) *iy0 = 0; - if (ix1) *ix1 = 0; - if (iy1) *iy1 = 0; - } else { - /* move to integral bboxes (treating pixels as little squares, what pixels get touched)? */ - if (ix0) *ix0 = nk_ifloorf((float)x0 * scale_x + shift_x); - if (iy0) *iy0 = nk_ifloorf((float)-y1 * scale_y + shift_y); - if (ix1) *ix1 = nk_iceilf ((float)x1 * scale_x + shift_x); - if (iy1) *iy1 = nk_iceilf ((float)-y0 * scale_y + shift_y); - } -} - -NK_INTERN void -nk_tt_GetGlyphBitmapBox(const struct nk_tt_fontinfo *font, int glyph, - float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - nk_tt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); -} - -/*------------------------------------------------------------- - * Rasterizer - * --------------------------------------------------------------*/ -NK_INTERN void* -nk_tt__hheap_alloc(struct nk_tt__hheap *hh, nk_size size) -{ - if (hh->first_free) { - void *p = hh->first_free; - hh->first_free = * (void **) p; - return p; - } else { - if (hh->num_remaining_in_head_chunk == 0) { - int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); - struct nk_tt__hheap_chunk *c = (struct nk_tt__hheap_chunk *) - hh->alloc.alloc(hh->alloc.userdata, 0, - sizeof(struct nk_tt__hheap_chunk) + size * (nk_size)count); - if (c == 0) return 0; - c->next = hh->head; - hh->head = c; - hh->num_remaining_in_head_chunk = count; - } - --hh->num_remaining_in_head_chunk; - return (char *) (hh->head) + size * (nk_size)hh->num_remaining_in_head_chunk; - } -} - -NK_INTERN void -nk_tt__hheap_free(struct nk_tt__hheap *hh, void *p) -{ - *(void **) p = hh->first_free; - hh->first_free = p; -} - -NK_INTERN void -nk_tt__hheap_cleanup(struct nk_tt__hheap *hh) -{ - struct nk_tt__hheap_chunk *c = hh->head; - while (c) { - struct nk_tt__hheap_chunk *n = c->next; - hh->alloc.free(hh->alloc.userdata, c); - c = n; - } -} - -NK_INTERN struct nk_tt__active_edge* -nk_tt__new_active(struct nk_tt__hheap *hh, struct nk_tt__edge *e, - int off_x, float start_point) -{ - struct nk_tt__active_edge *z = (struct nk_tt__active_edge *) - nk_tt__hheap_alloc(hh, sizeof(*z)); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - /*STBTT_assert(e->y0 <= start_point); */ - if (!z) return z; - z->fdx = dxdy; - z->fdy = (dxdy != 0) ? (1/dxdy): 0; - z->fx = e->x0 + dxdy * (start_point - e->y0); - z->fx -= (float)off_x; - z->direction = e->invert ? 1.0f : -1.0f; - z->sy = e->y0; - z->ey = e->y1; - z->next = 0; - return z; -} - -NK_INTERN void -nk_tt__handle_clipped_edge(float *scanline, int x, struct nk_tt__active_edge *e, - float x0, float y0, float x1, float y1) -{ - if (y0 == y1) return; - NK_ASSERT(y0 < y1); - NK_ASSERT(e->sy <= e->ey); - if (y0 > e->ey) return; - if (y1 < e->sy) return; - if (y0 < e->sy) { - x0 += (x1-x0) * (e->sy - y0) / (y1-y0); - y0 = e->sy; - } - if (y1 > e->ey) { - x1 += (x1-x0) * (e->ey - y1) / (y1-y0); - y1 = e->ey; - } - - if (x0 == x) NK_ASSERT(x1 <= x+1); - else if (x0 == x+1) NK_ASSERT(x1 >= x); - else if (x0 <= x) NK_ASSERT(x1 <= x); - else if (x0 >= x+1) NK_ASSERT(x1 >= x+1); - else NK_ASSERT(x1 >= x && x1 <= x+1); - - if (x0 <= x && x1 <= x) - scanline[x] += e->direction * (y1-y0); - else if (x0 >= x+1 && x1 >= x+1); - else { - NK_ASSERT(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); - /* coverage = 1 - average x position */ - scanline[x] += (float)e->direction * (float)(y1-y0) * (1.0f-((x0-(float)x)+(x1-(float)x))/2.0f); - } -} - -NK_INTERN void -nk_tt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, - struct nk_tt__active_edge *e, float y_top) -{ - float y_bottom = y_top+1; - while (e) - { - /* brute force every pixel */ - /* compute intersection points with top & bottom */ - NK_ASSERT(e->ey >= y_top); - if (e->fdx == 0) { - float x0 = e->fx; - if (x0 < len) { - if (x0 >= 0) { - nk_tt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); - nk_tt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); - } else { - nk_tt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); - } - } - } else { - float x0 = e->fx; - float dx = e->fdx; - float xb = x0 + dx; - float x_top, x_bottom; - float y0,y1; - float dy = e->fdy; - NK_ASSERT(e->sy <= y_bottom && e->ey >= y_top); - - /* compute endpoints of line segment clipped to this scanline (if the */ - /* line segment starts on this scanline. x0 is the intersection of the */ - /* line with y_top, but that may be off the line segment. */ - if (e->sy > y_top) { - x_top = x0 + dx * (e->sy - y_top); - y0 = e->sy; - } else { - x_top = x0; - y0 = y_top; - } - - if (e->ey < y_bottom) { - x_bottom = x0 + dx * (e->ey - y_top); - y1 = e->ey; - } else { - x_bottom = xb; - y1 = y_bottom; - } - - if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) - { - /* from here on, we don't have to range check x values */ - if ((int) x_top == (int) x_bottom) { - float height; - /* simple case, only spans one pixel */ - int x = (int) x_top; - height = y1 - y0; - NK_ASSERT(x >= 0 && x < len); - scanline[x] += e->direction * (1.0f-(((float)x_top - (float)x) + ((float)x_bottom-(float)x))/2.0f) * (float)height; - scanline_fill[x] += e->direction * (float)height; /* everything right of this pixel is filled */ - } else { - int x,x1,x2; - float y_crossing, step, sign, area; - /* covers 2+ pixels */ - if (x_top > x_bottom) - { - /* flip scanline vertically; signed area is the same */ - float t; - y0 = y_bottom - (y0 - y_top); - y1 = y_bottom - (y1 - y_top); - t = y0; y0 = y1; y1 = t; - t = x_bottom; x_bottom = x_top; x_top = t; - dx = -dx; - dy = -dy; - t = x0; x0 = xb; xb = t; - } - - x1 = (int) x_top; - x2 = (int) x_bottom; - /* compute intersection with y axis at x1+1 */ - y_crossing = ((float)x1+1 - (float)x0) * (float)dy + (float)y_top; - - sign = e->direction; - /* area of the rectangle covered from y0..y_crossing */ - area = sign * (y_crossing-y0); - /* area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) */ - scanline[x1] += area * (1.0f-((float)((float)x_top - (float)x1)+(float)(x1+1-x1))/2.0f); - - step = sign * dy; - for (x = x1+1; x < x2; ++x) { - scanline[x] += area + step/2; - area += step; - } - y_crossing += (float)dy * (float)(x2 - (x1+1)); - - scanline[x2] += area + sign * (1.0f-((float)(x2-x2)+((float)x_bottom-(float)x2))/2.0f) * (y1-y_crossing); - scanline_fill[x2] += sign * (y1-y0); - } - } - else - { - /* if edge goes outside of box we're drawing, we require */ - /* clipping logic. since this does not match the intended use */ - /* of this library, we use a different, very slow brute */ - /* force implementation */ - int x; - for (x=0; x < len; ++x) - { - /* cases: */ - /* */ - /* there can be up to two intersections with the pixel. any intersection */ - /* with left or right edges can be handled by splitting into two (or three) */ - /* regions. intersections with top & bottom do not necessitate case-wise logic. */ - /* */ - /* the old way of doing this found the intersections with the left & right edges, */ - /* then used some simple logic to produce up to three segments in sorted order */ - /* from top-to-bottom. however, this had a problem: if an x edge was epsilon */ - /* across the x border, then the corresponding y position might not be distinct */ - /* from the other y segment, and it might ignored as an empty segment. to avoid */ - /* that, we need to explicitly produce segments based on x positions. */ - - /* rename variables to clear pairs */ - float ya = y_top; - float x1 = (float) (x); - float x2 = (float) (x+1); - float x3 = xb; - float y3 = y_bottom; - float yb,y2; - - yb = ((float)x - x0) / dx + y_top; - y2 = ((float)x+1 - x0) / dx + y_top; - - if (x0 < x1 && x3 > x2) { /* three segments descending down-right */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb); - nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x2,y2); - nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x1 && x0 > x2) { /* three segments descending down-left */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2); - nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x1,yb); - nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3); - } else if (x0 < x1 && x3 > x1) { /* two segments across x, down-right */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb); - nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3); - } else if (x3 < x1 && x0 > x1) { /* two segments across x, down-left */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb); - nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3); - } else if (x0 < x2 && x3 > x2) { /* two segments across x+1, down-right */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2); - nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x2 && x0 > x2) { /* two segments across x+1, down-left */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2); - nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else { /* one segment */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x3,y3); - } - } - } - } - e = e->next; - } -} - -/* directly AA rasterize edges w/o supersampling */ -NK_INTERN void -nk_tt__rasterize_sorted_edges(struct nk_tt__bitmap *result, struct nk_tt__edge *e, - int n, int vsubsample, int off_x, int off_y, struct nk_allocator *alloc) -{ - struct nk_tt__hheap hh; - struct nk_tt__active_edge *active = 0; - int y,j=0, i; - float scanline_data[129], *scanline, *scanline2; - - NK_UNUSED(vsubsample); - nk_zero_struct(hh); - hh.alloc = *alloc; - - if (result->w > 64) - scanline = (float *) alloc->alloc(alloc->userdata,0, (nk_size)(result->w*2+1) * sizeof(float)); - else scanline = scanline_data; - - scanline2 = scanline + result->w; - y = off_y; - e[n].y0 = (float) (off_y + result->h) + 1; - - while (j < result->h) - { - /* find center of pixel for this scanline */ - float scan_y_top = (float)y + 0.0f; - float scan_y_bottom = (float)y + 1.0f; - struct nk_tt__active_edge **step = &active; - - NK_MEMSET(scanline , 0, (nk_size)result->w*sizeof(scanline[0])); - NK_MEMSET(scanline2, 0, (nk_size)(result->w+1)*sizeof(scanline[0])); - - /* update all active edges; */ - /* remove all active edges that terminate before the top of this scanline */ - while (*step) { - struct nk_tt__active_edge * z = *step; - if (z->ey <= scan_y_top) { - *step = z->next; /* delete from list */ - NK_ASSERT(z->direction); - z->direction = 0; - nk_tt__hheap_free(&hh, z); - } else { - step = &((*step)->next); /* advance through list */ - } - } - - /* insert all edges that start before the bottom of this scanline */ - while (e->y0 <= scan_y_bottom) { - if (e->y0 != e->y1) { - struct nk_tt__active_edge *z = nk_tt__new_active(&hh, e, off_x, scan_y_top); - if (z != 0) { - NK_ASSERT(z->ey >= scan_y_top); - /* insert at front */ - z->next = active; - active = z; - } - } - ++e; - } - - /* now process all active edges */ - if (active) - nk_tt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); - - { - float sum = 0; - for (i=0; i < result->w; ++i) { - float k; - int m; - sum += scanline2[i]; - k = scanline[i] + sum; - k = (float) NK_ABS(k) * 255.0f + 0.5f; - m = (int) k; - if (m > 255) m = 255; - result->pixels[j*result->stride + i] = (unsigned char) m; - } - } - /* advance all the edges */ - step = &active; - while (*step) { - struct nk_tt__active_edge *z = *step; - z->fx += z->fdx; /* advance to position for current scanline */ - step = &((*step)->next); /* advance through list */ - } - ++y; - ++j; - } - nk_tt__hheap_cleanup(&hh); - if (scanline != scanline_data) - alloc->free(alloc->userdata, scanline); -} - -#define NK_TT__COMPARE(a,b) ((a)->y0 < (b)->y0) -NK_INTERN void -nk_tt__sort_edges_ins_sort(struct nk_tt__edge *p, int n) -{ - int i,j; - for (i=1; i < n; ++i) { - struct nk_tt__edge t = p[i], *a = &t; - j = i; - while (j > 0) { - struct nk_tt__edge *b = &p[j-1]; - int c = NK_TT__COMPARE(a,b); - if (!c) break; - p[j] = p[j-1]; - --j; - } - if (i != j) - p[j] = t; - } -} - -NK_INTERN void -nk_tt__sort_edges_quicksort(struct nk_tt__edge *p, int n) -{ - /* threshold for transitioning to insertion sort */ - while (n > 12) { - struct nk_tt__edge t; - int c01,c12,c,m,i,j; - - /* compute median of three */ - m = n >> 1; - c01 = NK_TT__COMPARE(&p[0],&p[m]); - c12 = NK_TT__COMPARE(&p[m],&p[n-1]); - - /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ - if (c01 != c12) { - /* otherwise, we'll need to swap something else to middle */ - int z; - c = NK_TT__COMPARE(&p[0],&p[n-1]); - /* 0>mid && midn => n; 0 0 */ - /* 0n: 0>n => 0; 0 n */ - z = (c == c12) ? 0 : n-1; - t = p[z]; - p[z] = p[m]; - p[m] = t; - } - - /* now p[m] is the median-of-three */ - /* swap it to the beginning so it won't move around */ - t = p[0]; - p[0] = p[m]; - p[m] = t; - - /* partition loop */ - i=1; - j=n-1; - for(;;) { - /* handling of equality is crucial here */ - /* for sentinels & efficiency with duplicates */ - for (;;++i) { - if (!NK_TT__COMPARE(&p[i], &p[0])) break; - } - for (;;--j) { - if (!NK_TT__COMPARE(&p[0], &p[j])) break; - } - - /* make sure we haven't crossed */ - if (i >= j) break; - t = p[i]; - p[i] = p[j]; - p[j] = t; - - ++i; - --j; - - } - - /* recurse on smaller side, iterate on larger */ - if (j < (n-i)) { - nk_tt__sort_edges_quicksort(p,j); - p = p+i; - n = n-i; - } else { - nk_tt__sort_edges_quicksort(p+i, n-i); - n = j; - } - } -} - -NK_INTERN void -nk_tt__sort_edges(struct nk_tt__edge *p, int n) -{ - nk_tt__sort_edges_quicksort(p, n); - nk_tt__sort_edges_ins_sort(p, n); -} - -NK_INTERN void -nk_tt__rasterize(struct nk_tt__bitmap *result, struct nk_tt__point *pts, - int *wcount, int windings, float scale_x, float scale_y, - float shift_x, float shift_y, int off_x, int off_y, int invert, - struct nk_allocator *alloc) -{ - float y_scale_inv = invert ? -scale_y : scale_y; - struct nk_tt__edge *e; - int n,i,j,k,m; - int vsubsample = 1; - /* vsubsample should divide 255 evenly; otherwise we won't reach full opacity */ - - /* now we have to blow out the windings into explicit edge lists */ - n = 0; - for (i=0; i < windings; ++i) - n += wcount[i]; - - e = (struct nk_tt__edge*) - alloc->alloc(alloc->userdata, 0,(sizeof(*e) * (nk_size)(n+1))); - if (e == 0) return; - n = 0; - - m=0; - for (i=0; i < windings; ++i) - { - struct nk_tt__point *p = pts + m; - m += wcount[i]; - j = wcount[i]-1; - for (k=0; k < wcount[i]; j=k++) { - int a=k,b=j; - /* skip the edge if horizontal */ - if (p[j].y == p[k].y) - continue; - - /* add edge from j to k to the list */ - e[n].invert = 0; - if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { - e[n].invert = 1; - a=j,b=k; - } - e[n].x0 = p[a].x * scale_x + shift_x; - e[n].y0 = (p[a].y * y_scale_inv + shift_y) * (float)vsubsample; - e[n].x1 = p[b].x * scale_x + shift_x; - e[n].y1 = (p[b].y * y_scale_inv + shift_y) * (float)vsubsample; - ++n; - } - } - - /* now sort the edges by their highest point (should snap to integer, and then by x) */ - /*STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); */ - nk_tt__sort_edges(e, n); - /* now, traverse the scanlines and find the intersections on each scanline, use xor winding rule */ - nk_tt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, alloc); - alloc->free(alloc->userdata, e); -} - -NK_INTERN void -nk_tt__add_point(struct nk_tt__point *points, int n, float x, float y) -{ - if (!points) return; /* during first pass, it's unallocated */ - points[n].x = x; - points[n].y = y; -} - -NK_INTERN int -nk_tt__tesselate_curve(struct nk_tt__point *points, int *num_points, - float x0, float y0, float x1, float y1, float x2, float y2, - float objspace_flatness_squared, int n) -{ - /* tesselate until threshold p is happy... - * @TODO warped to compensate for non-linear stretching */ - /* midpoint */ - float mx = (x0 + 2*x1 + x2)/4; - float my = (y0 + 2*y1 + y2)/4; - /* versus directly drawn line */ - float dx = (x0+x2)/2 - mx; - float dy = (y0+y2)/2 - my; - if (n > 16) /* 65536 segments on one curve better be enough! */ - return 1; - - /* half-pixel error allowed... need to be smaller if AA */ - if (dx*dx+dy*dy > objspace_flatness_squared) { - nk_tt__tesselate_curve(points, num_points, x0,y0, - (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); - nk_tt__tesselate_curve(points, num_points, mx,my, - (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); - } else { - nk_tt__add_point(points, *num_points,x2,y2); - *num_points = *num_points+1; - } - return 1; -} - -/* returns number of contours */ -NK_INTERN struct nk_tt__point* -nk_tt_FlattenCurves(struct nk_tt_vertex *vertices, int num_verts, - float objspace_flatness, int **contour_lengths, int *num_contours, - struct nk_allocator *alloc) -{ - struct nk_tt__point *points=0; - int num_points=0; - float objspace_flatness_squared = objspace_flatness * objspace_flatness; - int i; - int n=0; - int start=0; - int pass; - - /* count how many "moves" there are to get the contour count */ - for (i=0; i < num_verts; ++i) - if (vertices[i].type == NK_TT_vmove) ++n; - - *num_contours = n; - if (n == 0) return 0; - - *contour_lengths = (int *) - alloc->alloc(alloc->userdata,0, (sizeof(**contour_lengths) * (nk_size)n)); - if (*contour_lengths == 0) { - *num_contours = 0; - return 0; - } - - /* make two passes through the points so we don't need to realloc */ - for (pass=0; pass < 2; ++pass) - { - float x=0,y=0; - if (pass == 1) { - points = (struct nk_tt__point *) - alloc->alloc(alloc->userdata,0, (nk_size)num_points * sizeof(points[0])); - if (points == 0) goto error; - } - num_points = 0; - n= -1; - - for (i=0; i < num_verts; ++i) - { - switch (vertices[i].type) { - case NK_TT_vmove: - /* start the next contour */ - if (n >= 0) - (*contour_lengths)[n] = num_points - start; - ++n; - start = num_points; - - x = vertices[i].x, y = vertices[i].y; - nk_tt__add_point(points, num_points++, x,y); - break; - case NK_TT_vline: - x = vertices[i].x, y = vertices[i].y; - nk_tt__add_point(points, num_points++, x, y); - break; - case NK_TT_vcurve: - nk_tt__tesselate_curve(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - default: break; - } - } - (*contour_lengths)[n] = num_points - start; - } - return points; - -error: - alloc->free(alloc->userdata, points); - alloc->free(alloc->userdata, *contour_lengths); - *contour_lengths = 0; - *num_contours = 0; - return 0; -} - -NK_INTERN void -nk_tt_Rasterize(struct nk_tt__bitmap *result, float flatness_in_pixels, - struct nk_tt_vertex *vertices, int num_verts, - float scale_x, float scale_y, float shift_x, float shift_y, - int x_off, int y_off, int invert, struct nk_allocator *alloc) -{ - float scale = scale_x > scale_y ? scale_y : scale_x; - int winding_count, *winding_lengths; - struct nk_tt__point *windings = nk_tt_FlattenCurves(vertices, num_verts, - flatness_in_pixels / scale, &winding_lengths, &winding_count, alloc); - - NK_ASSERT(alloc); - if (windings) { - nk_tt__rasterize(result, windings, winding_lengths, winding_count, - scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, alloc); - alloc->free(alloc->userdata, winding_lengths); - alloc->free(alloc->userdata, windings); - } -} - -NK_INTERN void -nk_tt_MakeGlyphBitmapSubpixel(const struct nk_tt_fontinfo *info, unsigned char *output, - int out_w, int out_h, int out_stride, float scale_x, float scale_y, - float shift_x, float shift_y, int glyph, struct nk_allocator *alloc) -{ - int ix0,iy0; - struct nk_tt_vertex *vertices; - int num_verts = nk_tt_GetGlyphShape(info, alloc, glyph, &vertices); - struct nk_tt__bitmap gbm; - - nk_tt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, - shift_y, &ix0,&iy0,0,0); - gbm.pixels = output; - gbm.w = out_w; - gbm.h = out_h; - gbm.stride = out_stride; - - if (gbm.w && gbm.h) - nk_tt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, - shift_x, shift_y, ix0,iy0, 1, alloc); - alloc->free(alloc->userdata, vertices); -} - -/*------------------------------------------------------------- - * Bitmap baking - * --------------------------------------------------------------*/ -NK_INTERN int -nk_tt_PackBegin(struct nk_tt_pack_context *spc, unsigned char *pixels, - int pw, int ph, int stride_in_bytes, int padding, struct nk_allocator *alloc) -{ - int num_nodes = pw - padding; - struct nk_rp_context *context = (struct nk_rp_context *) - alloc->alloc(alloc->userdata,0, sizeof(*context)); - struct nk_rp_node *nodes = (struct nk_rp_node*) - alloc->alloc(alloc->userdata,0, (sizeof(*nodes ) * (nk_size)num_nodes)); - - if (context == 0 || nodes == 0) { - if (context != 0) alloc->free(alloc->userdata, context); - if (nodes != 0) alloc->free(alloc->userdata, nodes); - return 0; - } - - spc->width = pw; - spc->height = ph; - spc->pixels = pixels; - spc->pack_info = context; - spc->nodes = nodes; - spc->padding = padding; - spc->stride_in_bytes = (stride_in_bytes != 0) ? stride_in_bytes : pw; - spc->h_oversample = 1; - spc->v_oversample = 1; - - nk_rp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); - if (pixels) - NK_MEMSET(pixels, 0, (nk_size)(pw*ph)); /* background of 0 around pixels */ - return 1; -} - -NK_INTERN void -nk_tt_PackEnd(struct nk_tt_pack_context *spc, struct nk_allocator *alloc) -{ - alloc->free(alloc->userdata, spc->nodes); - alloc->free(alloc->userdata, spc->pack_info); -} - -NK_INTERN void -nk_tt_PackSetOversampling(struct nk_tt_pack_context *spc, - unsigned int h_oversample, unsigned int v_oversample) -{ - NK_ASSERT(h_oversample <= NK_TT_MAX_OVERSAMPLE); - NK_ASSERT(v_oversample <= NK_TT_MAX_OVERSAMPLE); - if (h_oversample <= NK_TT_MAX_OVERSAMPLE) - spc->h_oversample = h_oversample; - if (v_oversample <= NK_TT_MAX_OVERSAMPLE) - spc->v_oversample = v_oversample; -} - -NK_INTERN void -nk_tt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, - int kernel_width) -{ - unsigned char buffer[NK_TT_MAX_OVERSAMPLE]; - int safe_w = w - kernel_width; - int j; - - for (j=0; j < h; ++j) - { - int i; - unsigned int total; - NK_MEMSET(buffer, 0, (nk_size)kernel_width); - - total = 0; - - /* make kernel_width a constant in common cases so compiler can optimize out the divide */ - switch (kernel_width) { - case 2: - for (i=0; i <= safe_w; ++i) { - total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_w; ++i) { - total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_w; ++i) { - total += (unsigned int)pixels[i] - buffer[i & NK_TT__OVER_MASK]; - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_w; ++i) { - total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_w; ++i) { - total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / (unsigned int)kernel_width); - } - break; - } - - for (; i < w; ++i) { - NK_ASSERT(pixels[i] == 0); - total -= (unsigned int)(buffer[i & NK_TT__OVER_MASK]); - pixels[i] = (unsigned char) (total / (unsigned int)kernel_width); - } - pixels += stride_in_bytes; - } -} - -NK_INTERN void -nk_tt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, - int kernel_width) -{ - unsigned char buffer[NK_TT_MAX_OVERSAMPLE]; - int safe_h = h - kernel_width; - int j; - - for (j=0; j < w; ++j) - { - int i; - unsigned int total; - NK_MEMSET(buffer, 0, (nk_size)kernel_width); - - total = 0; - - /* make kernel_width a constant in common cases so compiler can optimize out the divide */ - switch (kernel_width) { - case 2: - for (i=0; i <= safe_h; ++i) { - total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_h; ++i) { - total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_h; ++i) { - total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_h; ++i) { - total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_h; ++i) { - total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / (unsigned int)kernel_width); - } - break; - } - - for (; i < h; ++i) { - NK_ASSERT(pixels[i*stride_in_bytes] == 0); - total -= (unsigned int)(buffer[i & NK_TT__OVER_MASK]); - pixels[i*stride_in_bytes] = (unsigned char) (total / (unsigned int)kernel_width); - } - pixels += 1; - } -} - -NK_INTERN float -nk_tt__oversample_shift(int oversample) -{ - if (!oversample) - return 0.0f; - - /* The prefilter is a box filter of width "oversample", */ - /* which shifts phase by (oversample - 1)/2 pixels in */ - /* oversampled space. We want to shift in the opposite */ - /* direction to counter this. */ - return (float)-(oversample - 1) / (2.0f * (float)oversample); -} - -/* rects array must be big enough to accommodate all characters in the given ranges */ -NK_INTERN int -nk_tt_PackFontRangesGatherRects(struct nk_tt_pack_context *spc, - struct nk_tt_fontinfo *info, struct nk_tt_pack_range *ranges, - int num_ranges, struct nk_rp_rect *rects) -{ - int i,j,k; - k = 0; - - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = (fh > 0) ? nk_tt_ScaleForPixelHeight(info, fh): - nk_tt_ScaleForMappingEmToPixels(info, -fh); - ranges[i].h_oversample = (unsigned char) spc->h_oversample; - ranges[i].v_oversample = (unsigned char) spc->v_oversample; - for (j=0; j < ranges[i].num_chars; ++j) { - int x0,y0,x1,y1; - int codepoint = ranges[i].first_unicode_codepoint_in_range ? - ranges[i].first_unicode_codepoint_in_range + j : - ranges[i].array_of_unicode_codepoints[j]; - - int glyph = nk_tt_FindGlyphIndex(info, codepoint); - nk_tt_GetGlyphBitmapBoxSubpixel(info,glyph, scale * (float)spc->h_oversample, - scale * (float)spc->v_oversample, 0,0, &x0,&y0,&x1,&y1); - rects[k].w = (nk_rp_coord) (x1-x0 + spc->padding + (int)spc->h_oversample-1); - rects[k].h = (nk_rp_coord) (y1-y0 + spc->padding + (int)spc->v_oversample-1); - ++k; - } - } - return k; -} - -NK_INTERN int -nk_tt_PackFontRangesRenderIntoRects(struct nk_tt_pack_context *spc, - struct nk_tt_fontinfo *info, struct nk_tt_pack_range *ranges, - int num_ranges, struct nk_rp_rect *rects, struct nk_allocator *alloc) -{ - int i,j,k, return_value = 1; - /* save current values */ - int old_h_over = (int)spc->h_oversample; - int old_v_over = (int)spc->v_oversample; - /* rects array must be big enough to accommodate all characters in the given ranges */ - - k = 0; - for (i=0; i < num_ranges; ++i) - { - float fh = ranges[i].font_size; - float recip_h,recip_v,sub_x,sub_y; - float scale = fh > 0 ? nk_tt_ScaleForPixelHeight(info, fh): - nk_tt_ScaleForMappingEmToPixels(info, -fh); - - spc->h_oversample = ranges[i].h_oversample; - spc->v_oversample = ranges[i].v_oversample; - - recip_h = 1.0f / (float)spc->h_oversample; - recip_v = 1.0f / (float)spc->v_oversample; - - sub_x = nk_tt__oversample_shift((int)spc->h_oversample); - sub_y = nk_tt__oversample_shift((int)spc->v_oversample); - - for (j=0; j < ranges[i].num_chars; ++j) - { - struct nk_rp_rect *r = &rects[k]; - if (r->was_packed) - { - struct nk_tt_packedchar *bc = &ranges[i].chardata_for_range[j]; - int advance, lsb, x0,y0,x1,y1; - int codepoint = ranges[i].first_unicode_codepoint_in_range ? - ranges[i].first_unicode_codepoint_in_range + j : - ranges[i].array_of_unicode_codepoints[j]; - int glyph = nk_tt_FindGlyphIndex(info, codepoint); - nk_rp_coord pad = (nk_rp_coord) spc->padding; - - /* pad on left and top */ - r->x = (nk_rp_coord)((int)r->x + (int)pad); - r->y = (nk_rp_coord)((int)r->y + (int)pad); - r->w = (nk_rp_coord)((int)r->w - (int)pad); - r->h = (nk_rp_coord)((int)r->h - (int)pad); - - nk_tt_GetGlyphHMetrics(info, glyph, &advance, &lsb); - nk_tt_GetGlyphBitmapBox(info, glyph, scale * (float)spc->h_oversample, - (scale * (float)spc->v_oversample), &x0,&y0,&x1,&y1); - nk_tt_MakeGlyphBitmapSubpixel(info, spc->pixels + r->x + r->y*spc->stride_in_bytes, - (int)(r->w - spc->h_oversample+1), (int)(r->h - spc->v_oversample+1), - spc->stride_in_bytes, scale * (float)spc->h_oversample, - scale * (float)spc->v_oversample, 0,0, glyph, alloc); - - if (spc->h_oversample > 1) - nk_tt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, (int)spc->h_oversample); - - if (spc->v_oversample > 1) - nk_tt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, (int)spc->v_oversample); - - bc->x0 = (nk_ushort) r->x; - bc->y0 = (nk_ushort) r->y; - bc->x1 = (nk_ushort) (r->x + r->w); - bc->y1 = (nk_ushort) (r->y + r->h); - bc->xadvance = scale * (float)advance; - bc->xoff = (float) x0 * recip_h + sub_x; - bc->yoff = (float) y0 * recip_v + sub_y; - bc->xoff2 = ((float)x0 + r->w) * recip_h + sub_x; - bc->yoff2 = ((float)y0 + r->h) * recip_v + sub_y; - } else { - return_value = 0; /* if any fail, report failure */ - } - ++k; - } - } - /* restore original values */ - spc->h_oversample = (unsigned int)old_h_over; - spc->v_oversample = (unsigned int)old_v_over; - return return_value; -} - -NK_INTERN void -nk_tt_GetPackedQuad(struct nk_tt_packedchar *chardata, int pw, int ph, - int char_index, float *xpos, float *ypos, struct nk_tt_aligned_quad *q, - int align_to_integer) -{ - float ipw = 1.0f / (float)pw, iph = 1.0f / (float)ph; - struct nk_tt_packedchar *b = (struct nk_tt_packedchar*)(chardata + char_index); - if (align_to_integer) { - int tx = nk_ifloorf((*xpos + b->xoff) + 0.5f); - int ty = nk_ifloorf((*ypos + b->yoff) + 0.5f); - - float x = (float)tx; - float y = (float)ty; - - q->x0 = x; - q->y0 = y; - q->x1 = x + b->xoff2 - b->xoff; - q->y1 = y + b->yoff2 - b->yoff; - } else { - q->x0 = *xpos + b->xoff; - q->y0 = *ypos + b->yoff; - q->x1 = *xpos + b->xoff2; - q->y1 = *ypos + b->yoff2; - } - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - *xpos += b->xadvance; -} - -/* ------------------------------------------------------------- - * - * FONT BAKING - * - * --------------------------------------------------------------*/ -struct nk_font_bake_data { - struct nk_tt_fontinfo info; - struct nk_rp_rect *rects; - struct nk_tt_pack_range *ranges; - nk_rune range_count; -}; - -struct nk_font_baker { - struct nk_allocator alloc; - struct nk_tt_pack_context spc; - struct nk_font_bake_data *build; - struct nk_tt_packedchar *packed_chars; - struct nk_rp_rect *rects; - struct nk_tt_pack_range *ranges; -}; - -NK_GLOBAL const nk_size nk_rect_align = NK_ALIGNOF(struct nk_rp_rect); -NK_GLOBAL const nk_size nk_range_align = NK_ALIGNOF(struct nk_tt_pack_range); -NK_GLOBAL const nk_size nk_char_align = NK_ALIGNOF(struct nk_tt_packedchar); -NK_GLOBAL const nk_size nk_build_align = NK_ALIGNOF(struct nk_font_bake_data); -NK_GLOBAL const nk_size nk_baker_align = NK_ALIGNOF(struct nk_font_baker); - -NK_INTERN int -nk_range_count(const nk_rune *range) -{ - const nk_rune *iter = range; - NK_ASSERT(range); - if (!range) return 0; - while (*(iter++) != 0); - return (iter == range) ? 0 : (int)((iter - range)/2); -} - -NK_INTERN int -nk_range_glyph_count(const nk_rune *range, int count) -{ - int i = 0; - int total_glyphs = 0; - for (i = 0; i < count; ++i) { - int diff; - nk_rune f = range[(i*2)+0]; - nk_rune t = range[(i*2)+1]; - NK_ASSERT(t >= f); - diff = (int)((t - f) + 1); - total_glyphs += diff; - } - return total_glyphs; -} - -NK_API const nk_rune* -nk_font_default_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = {0x0020, 0x00FF, 0}; - return ranges; -} - -NK_API const nk_rune* -nk_font_chinese_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = { - 0x0020, 0x00FF, - 0x3000, 0x30FF, - 0x31F0, 0x31FF, - 0xFF00, 0xFFEF, - 0x4e00, 0x9FAF, - 0 - }; - return ranges; -} - -NK_API const nk_rune* -nk_font_cyrillic_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = { - 0x0020, 0x00FF, - 0x0400, 0x052F, - 0x2DE0, 0x2DFF, - 0xA640, 0xA69F, - 0 - }; - return ranges; -} - -NK_API const nk_rune* -nk_font_korean_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = { - 0x0020, 0x00FF, - 0x3131, 0x3163, - 0xAC00, 0xD79D, - 0 - }; - return ranges; -} - -NK_INTERN void -nk_font_baker_memory(nk_size *temp, int *glyph_count, - struct nk_font_config *config_list, int count) -{ - int range_count = 0; - int total_range_count = 0; - struct nk_font_config *iter; - - NK_ASSERT(config_list); - NK_ASSERT(glyph_count); - if (!config_list) { - *temp = 0; - *glyph_count = 0; - return; - } - - *glyph_count = 0; - if (!config_list->range) - config_list->range = nk_font_default_glyph_ranges(); - for (iter = config_list; iter; iter = iter->next) { - range_count = nk_range_count(iter->range); - total_range_count += range_count; - *glyph_count += nk_range_glyph_count(iter->range, range_count); - } - - *temp = (nk_size)*glyph_count * sizeof(struct nk_rp_rect); - *temp += (nk_size)total_range_count * sizeof(struct nk_tt_pack_range); - *temp += (nk_size)*glyph_count * sizeof(struct nk_tt_packedchar); - *temp += (nk_size)count * sizeof(struct nk_font_bake_data); - *temp += sizeof(struct nk_font_baker); - *temp += nk_rect_align + nk_range_align + nk_char_align; - *temp += nk_build_align + nk_baker_align; -} - -NK_INTERN struct nk_font_baker* -nk_font_baker(void *memory, int glyph_count, int count, struct nk_allocator *alloc) -{ - struct nk_font_baker *baker; - if (!memory) return 0; - /* setup baker inside a memory block */ - baker = (struct nk_font_baker*)NK_ALIGN_PTR(memory, nk_baker_align); - baker->build = (struct nk_font_bake_data*)NK_ALIGN_PTR((baker + 1), nk_build_align); - baker->packed_chars = (struct nk_tt_packedchar*)NK_ALIGN_PTR((baker->build + count), nk_char_align); - baker->rects = (struct nk_rp_rect*)NK_ALIGN_PTR((baker->packed_chars + glyph_count), nk_rect_align); - baker->ranges = (struct nk_tt_pack_range*)NK_ALIGN_PTR((baker->rects + glyph_count), nk_range_align); - baker->alloc = *alloc; - return baker; -} - -NK_INTERN int -nk_font_bake_pack(struct nk_font_baker *baker, - nk_size *image_memory, int *width, int *height, struct nk_recti *custom, - const struct nk_font_config *config_list, int count, - struct nk_allocator *alloc) -{ - NK_STORAGE const nk_size max_height = 1024 * 32; - const struct nk_font_config *config_iter; - int total_glyph_count = 0; - int total_range_count = 0; - int range_count = 0; - int i = 0; - - NK_ASSERT(image_memory); - NK_ASSERT(width); - NK_ASSERT(height); - NK_ASSERT(config_list); - NK_ASSERT(count); - NK_ASSERT(alloc); - - if (!image_memory || !width || !height || !config_list || !count) return nk_false; - for (config_iter = config_list; config_iter; config_iter = config_iter->next) { - range_count = nk_range_count(config_iter->range); - total_range_count += range_count; - total_glyph_count += nk_range_glyph_count(config_iter->range, range_count); - } - - /* setup font baker from temporary memory */ - for (config_iter = config_list; config_iter; config_iter = config_iter->next) { - const struct nk_font_config *cfg = config_iter; - if (!nk_tt_InitFont(&baker->build[i++].info, (const unsigned char*)cfg->ttf_blob, 0)) - return nk_false; - } - - *height = 0; - *width = (total_glyph_count > 1000) ? 1024 : 512; - nk_tt_PackBegin(&baker->spc, 0, (int)*width, (int)max_height, 0, 1, alloc); - { - int input_i = 0; - int range_n = 0; - int rect_n = 0; - int char_n = 0; - - if (custom) { - /* pack custom user data first so it will be in the upper left corner*/ - struct nk_rp_rect custom_space; - nk_zero(&custom_space, sizeof(custom_space)); - custom_space.w = (nk_rp_coord)((custom->w * 2) + 1); - custom_space.h = (nk_rp_coord)(custom->h + 1); - - nk_tt_PackSetOversampling(&baker->spc, 1, 1); - nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, &custom_space, 1); - *height = NK_MAX(*height, (int)(custom_space.y + custom_space.h)); - - custom->x = (short)custom_space.x; - custom->y = (short)custom_space.y; - custom->w = (short)custom_space.w; - custom->h = (short)custom_space.h; - } - - /* first font pass: pack all glyphs */ - for (input_i = 0, config_iter = config_list; input_i < count && config_iter; - input_i++, config_iter = config_iter->next) - { - int n = 0; - int glyph_count; - const nk_rune *in_range; - const struct nk_font_config *cfg = config_iter; - struct nk_font_bake_data *tmp = &baker->build[input_i]; - - /* count glyphs + ranges in current font */ - glyph_count = 0; range_count = 0; - for (in_range = cfg->range; in_range[0] && in_range[1]; in_range += 2) { - glyph_count += (int)(in_range[1] - in_range[0]) + 1; - range_count++; - } - - /* setup ranges */ - tmp->ranges = baker->ranges + range_n; - tmp->range_count = (nk_rune)range_count; - range_n += range_count; - for (i = 0; i < range_count; ++i) { - in_range = &cfg->range[i * 2]; - tmp->ranges[i].font_size = cfg->size; - tmp->ranges[i].first_unicode_codepoint_in_range = (int)in_range[0]; - tmp->ranges[i].num_chars = (int)(in_range[1]- in_range[0]) + 1; - tmp->ranges[i].chardata_for_range = baker->packed_chars + char_n; - char_n += tmp->ranges[i].num_chars; - } - - /* pack */ - tmp->rects = baker->rects + rect_n; - rect_n += glyph_count; - nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); - n = nk_tt_PackFontRangesGatherRects(&baker->spc, &tmp->info, - tmp->ranges, (int)tmp->range_count, tmp->rects); - nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, tmp->rects, (int)n); - - /* texture height */ - for (i = 0; i < n; ++i) { - if (tmp->rects[i].was_packed) - *height = NK_MAX(*height, tmp->rects[i].y + tmp->rects[i].h); - } - } - NK_ASSERT(rect_n == total_glyph_count); - NK_ASSERT(char_n == total_glyph_count); - NK_ASSERT(range_n == total_range_count); - } - *height = (int)nk_round_up_pow2((nk_uint)*height); - *image_memory = (nk_size)(*width) * (nk_size)(*height); - return nk_true; -} - -NK_INTERN void -nk_font_bake(struct nk_font_baker *baker, void *image_memory, int width, int height, - struct nk_font_glyph *glyphs, int glyphs_count, - const struct nk_font_config *config_list, int font_count) -{ - int input_i = 0; - nk_rune glyph_n = 0; - const struct nk_font_config *config_iter; - - NK_ASSERT(image_memory); - NK_ASSERT(width); - NK_ASSERT(height); - NK_ASSERT(config_list); - NK_ASSERT(baker); - NK_ASSERT(font_count); - NK_ASSERT(glyphs_count); - if (!image_memory || !width || !height || !config_list || - !font_count || !glyphs || !glyphs_count) - return; - - /* second font pass: render glyphs */ - nk_zero(image_memory, (nk_size)((nk_size)width * (nk_size)height)); - baker->spc.pixels = (unsigned char*)image_memory; - baker->spc.height = (int)height; - for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter; - ++input_i, config_iter = config_iter->next) - { - const struct nk_font_config *cfg = config_iter; - struct nk_font_bake_data *tmp = &baker->build[input_i]; - nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); - nk_tt_PackFontRangesRenderIntoRects(&baker->spc, &tmp->info, tmp->ranges, - (int)tmp->range_count, tmp->rects, &baker->alloc); - } - nk_tt_PackEnd(&baker->spc, &baker->alloc); - - /* third pass: setup font and glyphs */ - for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter; - ++input_i, config_iter = config_iter->next) - { - nk_size i = 0; - int char_idx = 0; - nk_rune glyph_count = 0; - const struct nk_font_config *cfg = config_iter; - struct nk_font_bake_data *tmp = &baker->build[input_i]; - struct nk_baked_font *dst_font = cfg->font; - - float font_scale = nk_tt_ScaleForPixelHeight(&tmp->info, cfg->size); - int unscaled_ascent, unscaled_descent, unscaled_line_gap; - nk_tt_GetFontVMetrics(&tmp->info, &unscaled_ascent, &unscaled_descent, - &unscaled_line_gap); - - /* fill baked font */ - if (!cfg->merge_mode) { - dst_font->ranges = cfg->range; - dst_font->height = cfg->size; - dst_font->ascent = ((float)unscaled_ascent * font_scale); - dst_font->descent = ((float)unscaled_descent * font_scale); - dst_font->glyph_offset = glyph_n; - } - - /* fill own baked font glyph array */ - for (i = 0; i < tmp->range_count; ++i) - { - struct nk_tt_pack_range *range = &tmp->ranges[i]; - for (char_idx = 0; char_idx < range->num_chars; char_idx++) - { - nk_rune codepoint = 0; - float dummy_x = 0, dummy_y = 0; - struct nk_tt_aligned_quad q; - struct nk_font_glyph *glyph; - - /* query glyph bounds from stb_truetype */ - const struct nk_tt_packedchar *pc = &range->chardata_for_range[char_idx]; - if (!pc->x0 && !pc->x1 && !pc->y0 && !pc->y1) continue; - codepoint = (nk_rune)(range->first_unicode_codepoint_in_range + char_idx); - nk_tt_GetPackedQuad(range->chardata_for_range, (int)width, - (int)height, char_idx, &dummy_x, &dummy_y, &q, 0); - - /* fill own glyph type with data */ - glyph = &glyphs[dst_font->glyph_offset + (unsigned int)glyph_count]; - glyph->codepoint = codepoint; - glyph->x0 = q.x0; glyph->y0 = q.y0; - glyph->x1 = q.x1; glyph->y1 = q.y1; - glyph->y0 += (dst_font->ascent + 0.5f); - glyph->y1 += (dst_font->ascent + 0.5f); - glyph->w = glyph->x1 - glyph->x0 + 0.5f; - glyph->h = glyph->y1 - glyph->y0; - - if (cfg->coord_type == NK_COORD_PIXEL) { - glyph->u0 = q.s0 * (float)width; - glyph->v0 = q.t0 * (float)height; - glyph->u1 = q.s1 * (float)width; - glyph->v1 = q.t1 * (float)height; - } else { - glyph->u0 = q.s0; - glyph->v0 = q.t0; - glyph->u1 = q.s1; - glyph->v1 = q.t1; - } - glyph->xadvance = (pc->xadvance + cfg->spacing.x); - if (cfg->pixel_snap) - glyph->xadvance = (float)(int)(glyph->xadvance + 0.5f); - glyph_count++; - } - } - dst_font->glyph_count = glyph_count; - glyph_n += dst_font->glyph_count; - } -} - -NK_INTERN void -nk_font_bake_custom_data(void *img_memory, int img_width, int img_height, - struct nk_recti img_dst, const char *texture_data_mask, int tex_width, - int tex_height, char white, char black) -{ - nk_byte *pixels; - int y = 0; - int x = 0; - int n = 0; - - NK_ASSERT(img_memory); - NK_ASSERT(img_width); - NK_ASSERT(img_height); - NK_ASSERT(texture_data_mask); - NK_UNUSED(tex_height); - if (!img_memory || !img_width || !img_height || !texture_data_mask) - return; - - pixels = (nk_byte*)img_memory; - for (y = 0, n = 0; y < tex_height; ++y) { - for (x = 0; x < tex_width; ++x, ++n) { - const int off0 = ((img_dst.x + x) + (img_dst.y + y) * img_width); - const int off1 = off0 + 1 + tex_width; - pixels[off0] = (texture_data_mask[n] == white) ? 0xFF : 0x00; - pixels[off1] = (texture_data_mask[n] == black) ? 0xFF : 0x00; - } - } -} - -NK_INTERN void -nk_font_bake_convert(void *out_memory, int img_width, int img_height, - const void *in_memory) -{ - int n = 0; - nk_rune *dst; - const nk_byte *src; - - NK_ASSERT(out_memory); - NK_ASSERT(in_memory); - NK_ASSERT(img_width); - NK_ASSERT(img_height); - if (!out_memory || !in_memory || !img_height || !img_width) return; - - dst = (nk_rune*)out_memory; - src = (const nk_byte*)in_memory; - for (n = (int)(img_width * img_height); n > 0; n--) - *dst++ = ((nk_rune)(*src++) << 24) | 0x00FFFFFF; -} - -/* ------------------------------------------------------------- - * - * FONT - * - * --------------------------------------------------------------*/ -NK_INTERN float -nk_font_text_width(nk_handle handle, float height, const char *text, int len) -{ - nk_rune unicode; - int text_len = 0; - float text_width = 0; - int glyph_len = 0; - float scale = 0; - - struct nk_font *font = (struct nk_font*)handle.ptr; - NK_ASSERT(font); - NK_ASSERT(font->glyphs); - if (!font || !text || !len) - return 0; - - scale = height/font->info.height; - glyph_len = text_len = nk_utf_decode(text, &unicode, (int)len); - if (!glyph_len) return 0; - while (text_len <= (int)len && glyph_len) { - const struct nk_font_glyph *g; - if (unicode == NK_UTF_INVALID) break; - - /* query currently drawn glyph information */ - g = nk_font_find_glyph(font, unicode); - text_width += g->xadvance * scale; - - /* offset next glyph */ - glyph_len = nk_utf_decode(text + text_len, &unicode, (int)len - text_len); - text_len += glyph_len; - } - return text_width; -} - -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -NK_INTERN void -nk_font_query_font_glyph(nk_handle handle, float height, - struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint) -{ - float scale; - const struct nk_font_glyph *g; - struct nk_font *font; - - NK_ASSERT(glyph); - NK_UNUSED(next_codepoint); - - font = (struct nk_font*)handle.ptr; - NK_ASSERT(font); - NK_ASSERT(font->glyphs); - if (!font || !glyph) - return; - - scale = height/font->info.height; - g = nk_font_find_glyph(font, codepoint); - glyph->width = (g->x1 - g->x0) * scale; - glyph->height = (g->y1 - g->y0) * scale; - glyph->offset = nk_vec2(g->x0 * scale, g->y0 * scale); - glyph->xadvance = (g->xadvance * scale); - glyph->uv[0] = nk_vec2(g->u0, g->v0); - glyph->uv[1] = nk_vec2(g->u1, g->v1); -} -#endif - -NK_API const struct nk_font_glyph* -nk_font_find_glyph(struct nk_font *font, nk_rune unicode) -{ - int i = 0; - int count; - int total_glyphs = 0; - const struct nk_font_glyph *glyph = 0; - - NK_ASSERT(font); - NK_ASSERT(font->glyphs); - NK_ASSERT(font->info.ranges); - if (!font || !font->glyphs) return 0; - - glyph = font->fallback; - count = nk_range_count(font->info.ranges); - for (i = 0; i < count; ++i) { - nk_rune f = font->info.ranges[(i*2)+0]; - nk_rune t = font->info.ranges[(i*2)+1]; - int diff = (int)((t - f) + 1); - if (unicode >= f && unicode <= t) - return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))]; - total_glyphs += diff; - } - return glyph; -} - -NK_INTERN void -nk_font_init(struct nk_font *font, float pixel_height, - nk_rune fallback_codepoint, struct nk_font_glyph *glyphs, - const struct nk_baked_font *baked_font, nk_handle atlas) -{ - struct nk_baked_font baked; - NK_ASSERT(font); - NK_ASSERT(glyphs); - NK_ASSERT(baked_font); - if (!font || !glyphs || !baked_font) - return; - - baked = *baked_font; - font->fallback = 0; - font->info = baked; - font->scale = (float)pixel_height / (float)font->info.height; - font->glyphs = &glyphs[baked_font->glyph_offset]; - font->texture = atlas; - font->fallback_codepoint = fallback_codepoint; - font->fallback = nk_font_find_glyph(font, fallback_codepoint); - - font->handle.height = font->info.height * font->scale; - font->handle.width = nk_font_text_width; - font->handle.userdata.ptr = font; -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - font->handle.query = nk_font_query_font_glyph; - font->handle.texture = font->texture; -#endif -} - -/* --------------------------------------------------------------------------- - * - * DEFAULT FONT - * - * ProggyClean.ttf - * Copyright (c) 2004, 2005 Tristan Grimmer - * MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip) - * Download and more information at http://upperbounds.net - *-----------------------------------------------------------------------------*/ -#ifdef NK_INCLUDE_DEFAULT_FONT - - #ifdef __clang__ -#pragma clang diagnostic push - -#pragma clang diagnostic ignored "-Woverlength-strings" -#elif defined(__GNUC__) || defined(__GNUG__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Woverlength-strings" -#endif - -NK_GLOBAL const char nk_proggy_clean_ttf_compressed_data_base85[11980+1] = - "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" - "2*>]b(MC;$jPfY.;h^`IWM9Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1=Ke$$'5F%)]0^#0X@U.a$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;--VsM.M0rJfLH2eTM`*oJMHRC`N" - "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa&VZ>1i%h1S9u5o@YaaW$e+bROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc." - "x]Ip.PH^'/aqUO/$1WxLoW0[iLAw=4h(9.`G" - "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?Ggv:[7MI2k).'2($5FNP&EQ(,)" - "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#" - "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM" - "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu" - "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/" - "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[Ket`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO" - "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%" - "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$MhLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]" - "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" - "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" - "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VBpqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<-+k?'(^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" - "D?@f&1'BW-)Ju#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(" - "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs" - "bIu)'Z,*[>br5fX^:FPAWr-m2KgLQ_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q" - "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aege0jT6'N#(q%.O=?2S]u*(m<-" - "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i" - "sZ88+dKQ)W6>J%CL`.d*(B`-n8D9oK-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P r+$%CE=68>K8r0=dSC%%(@p7" - ".m7jilQ02'0-VWAgTlGW'b)Tq7VT9q^*^$$.:&N@@" - "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*" - "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u" - "@-W$U%VEQ/,,>>#)D#%8cY#YZ?=,`Wdxu/ae&#" - "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$so8lKN%5/$(vdfq7+ebA#" - "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8" - "6e%B/:=>)N4xeW.*wft-;$'58-ESqr#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#" - "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjLV#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#SfD07&6D@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5" - "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%" - "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;" - "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmLq9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:" - "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3$U4O]GKx'm9)b@p7YsvK3w^YR-" - "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*" - "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdFTi1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IXSsDiWP,##P`%/L-" - "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdFl*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj" - "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#$(>.Z-I&J(Q0Hd5Q%7Co-b`-cP)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8WlA2);Sa" - ">gXm8YB`1d@K#n]76-a$U,mF%Ul:#/'xoFM9QX-$.QN'>" - "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I" - "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-uW%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)" - "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo" - "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P" - "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*'IAO" - "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#" - ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T" - "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4" - "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#" - "/QHC#3^ZC#7jmC#;v)D#?,)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP" - "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp" - "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#"; -#endif /* NK_INCLUDE_DEFAULT_FONT */ - -#define NK_CURSOR_DATA_W 90 -#define NK_CURSOR_DATA_H 27 -NK_GLOBAL const char nk_custom_cursor_data[NK_CURSOR_DATA_W * NK_CURSOR_DATA_H + 1] = -{ - "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX" - "..- -X.....X- X.X - X.X -X.....X - X.....X" - "--- -XXX.XXX- X...X - X...X -X....X - X....X" - "X - X.X - X.....X - X.....X -X...X - X...X" - "XX - X.X -X.......X- X.......X -X..X.X - X.X..X" - "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X" - "X..X - X.X - X.X - X.X -XX X.X - X.X XX" - "X...X - X.X - X.X - XX X.X XX - X.X - X.X " - "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X " - "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X " - "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X " - "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X " - "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X " - "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X " - "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X " - "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X " - "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX " - "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------" - "X.X X..X - -X.......X- X.......X - XX XX - " - "XX X..X - - X.....X - X.....X - X.X X.X - " - " X..X - X...X - X...X - X..X X..X - " - " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - " - "------------ - X - X -X.....................X- " - " ----------------------------------- X...XXXXXXXXXXXXX...X - " - " - X..X X..X - " - " - X.X X.X - " - " - XX XX - " -}; - -#ifdef __clang__ -#pragma clang diagnostic pop -#elif defined(__GNUC__) || defined(__GNUG__) -#pragma GCC diagnostic pop -#endif - -NK_INTERN unsigned int -nk_decompress_length(unsigned char *input) -{ - return (unsigned int)((input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]); -} - -NK_GLOBAL unsigned char *nk__barrier; -NK_GLOBAL unsigned char *nk__barrier2; -NK_GLOBAL unsigned char *nk__barrier3; -NK_GLOBAL unsigned char *nk__barrier4; -NK_GLOBAL unsigned char *nk__dout; - -NK_INTERN void -nk__match(unsigned char *data, unsigned int length) -{ - /* INVERSE of memmove... write each byte before copying the next...*/ - NK_ASSERT (nk__dout + length <= nk__barrier); - if (nk__dout + length > nk__barrier) { nk__dout += length; return; } - if (data < nk__barrier4) { nk__dout = nk__barrier+1; return; } - while (length--) *nk__dout++ = *data++; -} - -NK_INTERN void -nk__lit(unsigned char *data, unsigned int length) -{ - NK_ASSERT (nk__dout + length <= nk__barrier); - if (nk__dout + length > nk__barrier) { nk__dout += length; return; } - if (data < nk__barrier2) { nk__dout = nk__barrier+1; return; } - NK_MEMCPY(nk__dout, data, length); - nk__dout += length; -} - -#define nk__in2(x) ((i[x] << 8) + i[(x)+1]) -#define nk__in3(x) ((i[x] << 16) + nk__in2((x)+1)) -#define nk__in4(x) ((i[x] << 24) + nk__in3((x)+1)) - -NK_INTERN unsigned char* -nk_decompress_token(unsigned char *i) -{ - if (*i >= 0x20) { /* use fewer if's for cases that expand small */ - if (*i >= 0x80) nk__match(nk__dout-i[1]-1, (unsigned int)i[0] - 0x80 + 1), i += 2; - else if (*i >= 0x40) nk__match(nk__dout-(nk__in2(0) - 0x4000 + 1), (unsigned int)i[2]+1), i += 3; - else /* *i >= 0x20 */ nk__lit(i+1, (unsigned int)i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); - } else { /* more ifs for cases that expand large, since overhead is amortized */ - if (*i >= 0x18) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x180000 + 1), (unsigned int)i[3]+1), i += 4; - else if (*i >= 0x10) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x100000 + 1), (unsigned int)nk__in2(3)+1), i += 5; - else if (*i >= 0x08) nk__lit(i+2, (unsigned int)nk__in2(0) - 0x0800 + 1), i += 2 + (nk__in2(0) - 0x0800 + 1); - else if (*i == 0x07) nk__lit(i+3, (unsigned int)nk__in2(1) + 1), i += 3 + (nk__in2(1) + 1); - else if (*i == 0x06) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), i[4]+1u), i += 5; - else if (*i == 0x04) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), (unsigned int)nk__in2(4)+1u), i += 6; - } - return i; -} - -NK_INTERN unsigned int -nk_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen) -{ - const unsigned long ADLER_MOD = 65521; - unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; - unsigned long blocklen, i; - - blocklen = buflen % 5552; - while (buflen) { - for (i=0; i + 7 < blocklen; i += 8) { - s1 += buffer[0]; s2 += s1; - s1 += buffer[1]; s2 += s1; - s1 += buffer[2]; s2 += s1; - s1 += buffer[3]; s2 += s1; - s1 += buffer[4]; s2 += s1; - s1 += buffer[5]; s2 += s1; - s1 += buffer[6]; s2 += s1; - s1 += buffer[7]; s2 += s1; - buffer += 8; - } - for (; i < blocklen; ++i) { - s1 += *buffer++; s2 += s1; - } - - s1 %= ADLER_MOD; s2 %= ADLER_MOD; - buflen -= (unsigned int)blocklen; - blocklen = 5552; - } - return (unsigned int)(s2 << 16) + (unsigned int)s1; -} - -NK_INTERN unsigned int -nk_decompress(unsigned char *output, unsigned char *i, unsigned int length) -{ - unsigned int olen; - if (nk__in4(0) != 0x57bC0000) return 0; - if (nk__in4(4) != 0) return 0; /* error! stream is > 4GB */ - olen = nk_decompress_length(i); - nk__barrier2 = i; - nk__barrier3 = i+length; - nk__barrier = output + olen; - nk__barrier4 = output; - i += 16; - - nk__dout = output; - for (;;) { - unsigned char *old_i = i; - i = nk_decompress_token(i); - if (i == old_i) { - if (*i == 0x05 && i[1] == 0xfa) { - NK_ASSERT(nk__dout == output + olen); - if (nk__dout != output + olen) return 0; - if (nk_adler32(1, output, olen) != (unsigned int) nk__in4(2)) - return 0; - return olen; - } else { - NK_ASSERT(0); /* NOTREACHED */ - return 0; - } - } - NK_ASSERT(nk__dout <= output + olen); - if (nk__dout > output + olen) - return 0; - } -} - -NK_INTERN unsigned int -nk_decode_85_byte(char c) -{ return (unsigned int)((c >= '\\') ? c-36 : c-35); } - -NK_INTERN void -nk_decode_85(unsigned char* dst, const unsigned char* src) -{ - while (*src) - { - unsigned int tmp = - nk_decode_85_byte((char)src[0]) + - 85 * (nk_decode_85_byte((char)src[1]) + - 85 * (nk_decode_85_byte((char)src[2]) + - 85 * (nk_decode_85_byte((char)src[3]) + - 85 * nk_decode_85_byte((char)src[4])))); - - /* we can't assume little-endianess. */ - dst[0] = (unsigned char)((tmp >> 0) & 0xFF); - dst[1] = (unsigned char)((tmp >> 8) & 0xFF); - dst[2] = (unsigned char)((tmp >> 16) & 0xFF); - dst[3] = (unsigned char)((tmp >> 24) & 0xFF); - - src += 5; - dst += 4; - } -} - -/* ------------------------------------------------------------- - * - * FONT ATLAS - * - * --------------------------------------------------------------*/ -NK_API struct nk_font_config -nk_font_config(float pixel_height) -{ - struct nk_font_config cfg; - nk_zero_struct(cfg); - cfg.ttf_blob = 0; - cfg.ttf_size = 0; - cfg.ttf_data_owned_by_atlas = 0; - cfg.size = pixel_height; - cfg.oversample_h = 3; - cfg.oversample_v = 1; - cfg.pixel_snap = 0; - cfg.coord_type = NK_COORD_UV; - cfg.spacing = nk_vec2(0,0); - cfg.range = nk_font_default_glyph_ranges(); - cfg.merge_mode = 0; - cfg.fallback_glyph = '?'; - cfg.font = 0; - return cfg; -} - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void -nk_font_atlas_init_default(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - if (!atlas) return; - nk_zero_struct(*atlas); - atlas->temporary.userdata.ptr = 0; - atlas->temporary.alloc = nk_malloc; - atlas->temporary.free = nk_mfree; - atlas->permanent.userdata.ptr = 0; - atlas->permanent.alloc = nk_malloc; - atlas->permanent.free = nk_mfree; -} -#endif - -NK_API void -nk_font_atlas_init(struct nk_font_atlas *atlas, struct nk_allocator *alloc) -{ - NK_ASSERT(atlas); - NK_ASSERT(alloc); - if (!atlas || !alloc) return; - nk_zero_struct(*atlas); - atlas->permanent = *alloc; - atlas->temporary = *alloc; -} - -NK_API void -nk_font_atlas_init_custom(struct nk_font_atlas *atlas, - struct nk_allocator *permanent, struct nk_allocator *temporary) -{ - NK_ASSERT(atlas); - NK_ASSERT(permanent); - NK_ASSERT(temporary); - if (!atlas || !permanent || !temporary) return; - nk_zero_struct(*atlas); - atlas->permanent = *permanent; - atlas->temporary = *temporary; -} - -NK_API void -nk_font_atlas_begin(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc && atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc && atlas->permanent.free); - if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free || - !atlas->temporary.alloc || !atlas->temporary.free) return; - if (atlas->glyphs) { - atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); - atlas->glyphs = 0; - } - if (atlas->pixel) { - atlas->permanent.free(atlas->permanent.userdata, atlas->pixel); - atlas->pixel = 0; - } -} - -NK_API struct nk_font* -nk_font_atlas_add(struct nk_font_atlas *atlas, const struct nk_font_config *config) -{ - struct nk_font *font = 0; - struct nk_font_config *cfg; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - - NK_ASSERT(config); - NK_ASSERT(config->ttf_blob); - NK_ASSERT(config->ttf_size); - NK_ASSERT(config->size > 0.0f); - - if (!atlas || !config || !config->ttf_blob || !config->ttf_size || config->size <= 0.0f|| - !atlas->permanent.alloc || !atlas->permanent.free || - !atlas->temporary.alloc || !atlas->temporary.free) - return 0; - - /* allocate and insert font config into list */ - cfg = (struct nk_font_config*) - atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font_config)); - NK_MEMCPY(cfg, config, sizeof(*config)); - if (!atlas->config) { - atlas->config = cfg; - cfg->next = 0; - } else { - cfg->next = atlas->config; - atlas->config = cfg; - } - - /* allocate new font */ - if (!config->merge_mode) { - font = (struct nk_font*) - atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font)); - NK_ASSERT(font); - if (!font) return 0; - font->config = cfg; - } else { - NK_ASSERT(atlas->font_num); - font = atlas->fonts; - font->config = cfg; - } - - /* insert font into list */ - if (!config->merge_mode) { - if (!atlas->fonts) { - atlas->fonts = font; - font->next = 0; - } else { - font->next = atlas->fonts; - atlas->fonts = font; - } - cfg->font = &font->info; - } - - /* create own copy of .TTF font blob */ - if (!config->ttf_data_owned_by_atlas) { - cfg->ttf_blob = atlas->permanent.alloc(atlas->permanent.userdata,0, cfg->ttf_size); - NK_ASSERT(cfg->ttf_blob); - if (!cfg->ttf_blob) { - atlas->font_num++; - return 0; - } - NK_MEMCPY(cfg->ttf_blob, config->ttf_blob, cfg->ttf_size); - cfg->ttf_data_owned_by_atlas = 1; - } - atlas->font_num++; - return font; -} - -NK_API struct nk_font* -nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, - nk_size size, float height, const struct nk_font_config *config) -{ - struct nk_font_config cfg; - NK_ASSERT(memory); - NK_ASSERT(size); - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - if (!atlas || !atlas->temporary.alloc || !atlas->temporary.free || !memory || !size || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - - cfg = (config) ? *config: nk_font_config(height); - cfg.ttf_blob = memory; - cfg.ttf_size = size; - cfg.size = height; - cfg.ttf_data_owned_by_atlas = 0; - return nk_font_atlas_add(atlas, &cfg); -} - -#ifdef NK_INCLUDE_STANDARD_IO -NK_API struct nk_font* -nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, - float height, const struct nk_font_config *config) -{ - nk_size size; - char *memory; - struct nk_font_config cfg; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - if (!atlas || !file_path) return 0; - memory = nk_file_load(file_path, &size, &atlas->permanent); - if (!memory) return 0; - - cfg = (config) ? *config: nk_font_config(height); - cfg.ttf_blob = memory; - cfg.ttf_size = size; - cfg.size = height; - cfg.ttf_data_owned_by_atlas = 1; - return nk_font_atlas_add(atlas, &cfg); -} -#endif - -NK_API struct nk_font* -nk_font_atlas_add_compressed(struct nk_font_atlas *atlas, - void *compressed_data, nk_size compressed_size, float height, - const struct nk_font_config *config) -{ - unsigned int decompressed_size; - void *decompressed_data; - struct nk_font_config cfg; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - NK_ASSERT(compressed_data); - NK_ASSERT(compressed_size); - if (!atlas || !compressed_data || !atlas->temporary.alloc || !atlas->temporary.free || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - - decompressed_size = nk_decompress_length((unsigned char*)compressed_data); - decompressed_data = atlas->permanent.alloc(atlas->permanent.userdata,0,decompressed_size); - NK_ASSERT(decompressed_data); - if (!decompressed_data) return 0; - nk_decompress((unsigned char*)decompressed_data, (unsigned char*)compressed_data, - (unsigned int)compressed_size); - - cfg = (config) ? *config: nk_font_config(height); - cfg.ttf_blob = decompressed_data; - cfg.ttf_size = decompressed_size; - cfg.size = height; - cfg.ttf_data_owned_by_atlas = 1; - return nk_font_atlas_add(atlas, &cfg); -} - -NK_API struct nk_font* -nk_font_atlas_add_compressed_base85(struct nk_font_atlas *atlas, - const char *data_base85, float height, const struct nk_font_config *config) -{ - int compressed_size; - void *compressed_data; - struct nk_font *font; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - NK_ASSERT(data_base85); - if (!atlas || !data_base85 || !atlas->temporary.alloc || !atlas->temporary.free || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - - compressed_size = (((int)nk_strlen(data_base85) + 4) / 5) * 4; - compressed_data = atlas->temporary.alloc(atlas->temporary.userdata,0, (nk_size)compressed_size); - NK_ASSERT(compressed_data); - if (!compressed_data) return 0; - nk_decode_85((unsigned char*)compressed_data, (const unsigned char*)data_base85); - font = nk_font_atlas_add_compressed(atlas, compressed_data, - (nk_size)compressed_size, height, config); - atlas->temporary.free(atlas->temporary.userdata, compressed_data); - return font; -} - -#ifdef NK_INCLUDE_DEFAULT_FONT -NK_API struct nk_font* -nk_font_atlas_add_default(struct nk_font_atlas *atlas, - float pixel_height, const struct nk_font_config *config) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - return nk_font_atlas_add_compressed_base85(atlas, - nk_proggy_clean_ttf_compressed_data_base85, pixel_height, config); -} -#endif - -NK_API const void* -nk_font_atlas_bake(struct nk_font_atlas *atlas, int *width, int *height, - enum nk_font_atlas_format fmt) -{ - int i = 0; - void *tmp = 0; - nk_size tmp_size, img_size; - struct nk_font *font_iter; - struct nk_font_baker *baker; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - NK_ASSERT(width); - NK_ASSERT(height); - if (!atlas || !width || !height || - !atlas->temporary.alloc || !atlas->temporary.free || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - -#ifdef NK_INCLUDE_DEFAULT_FONT - /* no font added so just use default font */ - if (!atlas->font_num) - atlas->default_font = nk_font_atlas_add_default(atlas, 13.0f, 0); -#endif - NK_ASSERT(atlas->font_num); - if (!atlas->font_num) return 0; - - /* allocate temporary baker memory required for the baking process */ - nk_font_baker_memory(&tmp_size, &atlas->glyph_count, atlas->config, atlas->font_num); - tmp = atlas->temporary.alloc(atlas->temporary.userdata,0, tmp_size); - NK_ASSERT(tmp); - if (!tmp) goto failed; - - /* allocate glyph memory for all fonts */ - baker = nk_font_baker(tmp, atlas->glyph_count, atlas->font_num, &atlas->temporary); - atlas->glyphs = (struct nk_font_glyph*)atlas->permanent.alloc( - atlas->permanent.userdata,0, sizeof(struct nk_font_glyph)*(nk_size)atlas->glyph_count); - NK_ASSERT(atlas->glyphs); - if (!atlas->glyphs) - goto failed; - - /* pack all glyphs into a tight fit space */ - atlas->custom.w = (NK_CURSOR_DATA_W*2)+1; - atlas->custom.h = NK_CURSOR_DATA_H + 1; - if (!nk_font_bake_pack(baker, &img_size, width, height, &atlas->custom, - atlas->config, atlas->font_num, &atlas->temporary)) - goto failed; - - /* allocate memory for the baked image font atlas */ - atlas->pixel = atlas->temporary.alloc(atlas->temporary.userdata,0, img_size); - NK_ASSERT(atlas->pixel); - if (!atlas->pixel) - goto failed; - - /* bake glyphs and custom white pixel into image */ - nk_font_bake(baker, atlas->pixel, *width, *height, - atlas->glyphs, atlas->glyph_count, atlas->config, atlas->font_num); - nk_font_bake_custom_data(atlas->pixel, *width, *height, atlas->custom, - nk_custom_cursor_data, NK_CURSOR_DATA_W, NK_CURSOR_DATA_H, '.', 'X'); - - if (fmt == NK_FONT_ATLAS_RGBA32) { - /* convert alpha8 image into rgba32 image */ - void *img_rgba = atlas->temporary.alloc(atlas->temporary.userdata,0, - (nk_size)(*width * *height * 4)); - NK_ASSERT(img_rgba); - if (!img_rgba) goto failed; - nk_font_bake_convert(img_rgba, *width, *height, atlas->pixel); - atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); - atlas->pixel = img_rgba; - } - atlas->tex_width = *width; - atlas->tex_height = *height; - - /* initialize each font */ - for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) { - struct nk_font *font = font_iter; - struct nk_font_config *config = font->config; - nk_font_init(font, config->size, config->fallback_glyph, atlas->glyphs, - config->font, nk_handle_ptr(0)); - } - - /* initialize each cursor */ - {NK_STORAGE const struct nk_vec2 nk_cursor_data[NK_CURSOR_COUNT][3] = { - /* Pos ----- Size ------- Offset --*/ - {{ 0, 3}, {12,19}, { 0, 0}}, - {{13, 0}, { 7,16}, { 4, 8}}, - {{31, 0}, {23,23}, {11,11}}, - {{21, 0}, { 9, 23}, { 5,11}}, - {{55,18}, {23, 9}, {11, 5}}, - {{73, 0}, {17,17}, { 9, 9}}, - {{55, 0}, {17,17}, { 9, 9}} - }; - for (i = 0; i < NK_CURSOR_COUNT; ++i) { - struct nk_cursor *cursor = &atlas->cursors[i]; - cursor->img.w = (unsigned short)*width; - cursor->img.h = (unsigned short)*height; - cursor->img.region[0] = (unsigned short)(atlas->custom.x + nk_cursor_data[i][0].x); - cursor->img.region[1] = (unsigned short)(atlas->custom.y + nk_cursor_data[i][0].y); - cursor->img.region[2] = (unsigned short)nk_cursor_data[i][1].x; - cursor->img.region[3] = (unsigned short)nk_cursor_data[i][1].y; - cursor->size = nk_cursor_data[i][1]; - cursor->offset = nk_cursor_data[i][2]; - }} - /* free temporary memory */ - atlas->temporary.free(atlas->temporary.userdata, tmp); - return atlas->pixel; - -failed: - /* error so cleanup all memory */ - if (tmp) atlas->temporary.free(atlas->temporary.userdata, tmp); - if (atlas->glyphs) { - atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); - atlas->glyphs = 0; - } - if (atlas->pixel) { - atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); - atlas->pixel = 0; - } - return 0; -} - -NK_API void -nk_font_atlas_end(struct nk_font_atlas *atlas, nk_handle texture, - struct nk_draw_null_texture *null) -{ - int i = 0; - struct nk_font *font_iter; - NK_ASSERT(atlas); - if (!atlas) { - if (!null) return; - null->texture = texture; - null->uv = nk_vec2(0.5f,0.5f); - } - if (null) { - null->texture = texture; - null->uv.x = (atlas->custom.x + 0.5f)/(float)atlas->tex_width; - null->uv.y = (atlas->custom.y + 0.5f)/(float)atlas->tex_height; - } - for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) { - font_iter->texture = texture; -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - font_iter->handle.texture = texture; -#endif - } - for (i = 0; i < NK_CURSOR_COUNT; ++i) - atlas->cursors[i].img.handle = texture; - - atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); - atlas->pixel = 0; - atlas->tex_width = 0; - atlas->tex_height = 0; - atlas->custom.x = 0; - atlas->custom.y = 0; - atlas->custom.w = 0; - atlas->custom.h = 0; -} - -NK_API void -nk_font_atlas_cleanup(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return; - if (atlas->config) { - struct nk_font_config *iter, *next; - for (iter = atlas->config; iter; iter = next) { - next = iter->next; - atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob); - atlas->permanent.free(atlas->permanent.userdata, iter); - } - atlas->config = 0; - } -} - -NK_API void -nk_font_atlas_clear(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return; - - nk_font_atlas_cleanup(atlas); - if (atlas->fonts) { - struct nk_font *iter, *next; - for (iter = atlas->fonts; iter; iter = next) { - next = iter->next; - atlas->permanent.free(atlas->permanent.userdata, iter); - } - atlas->fonts = 0; - } - if (atlas->glyphs) - atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); - nk_zero_struct(*atlas); -} -#endif -/* ============================================================== - * - * INPUT - * - * ===============================================================*/ -NK_API void -nk_input_begin(struct nk_context *ctx) -{ - int i; - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - for (i = 0; i < NK_BUTTON_MAX; ++i) - in->mouse.buttons[i].clicked = 0; - - in->keyboard.text_len = 0; - in->mouse.scroll_delta = nk_vec2(0,0); - in->mouse.prev.x = in->mouse.pos.x; - in->mouse.prev.y = in->mouse.pos.y; - in->mouse.delta.x = 0; - in->mouse.delta.y = 0; - for (i = 0; i < NK_KEY_MAX; i++) - in->keyboard.keys[i].clicked = 0; -} - -NK_API void -nk_input_end(struct nk_context *ctx) -{ - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - if (in->mouse.grab) - in->mouse.grab = 0; - if (in->mouse.ungrab) { - in->mouse.grabbed = 0; - in->mouse.ungrab = 0; - in->mouse.grab = 0; - } -} - -NK_API void -nk_input_motion(struct nk_context *ctx, int x, int y) -{ - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - in->mouse.pos.x = (float)x; - in->mouse.pos.y = (float)y; - in->mouse.delta.x = in->mouse.pos.x - in->mouse.prev.x; - in->mouse.delta.y = in->mouse.pos.y - in->mouse.prev.y; -} - -NK_API void -nk_input_key(struct nk_context *ctx, enum nk_keys key, int down) -{ - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - if (in->keyboard.keys[key].down != down) - in->keyboard.keys[key].clicked++; - in->keyboard.keys[key].down = down; -} - -NK_API void -nk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, int down) -{ - struct nk_mouse_button *btn; - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - if (in->mouse.buttons[id].down == down) return; - - btn = &in->mouse.buttons[id]; - btn->clicked_pos.x = (float)x; - btn->clicked_pos.y = (float)y; - btn->down = down; - btn->clicked++; -} - -NK_API void -nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val) -{ - NK_ASSERT(ctx); - if (!ctx) return; - ctx->input.mouse.scroll_delta.x += val.x; - ctx->input.mouse.scroll_delta.y += val.y; -} - -NK_API void -nk_input_glyph(struct nk_context *ctx, const nk_glyph glyph) -{ - int len = 0; - nk_rune unicode; - struct nk_input *in; - - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - - len = nk_utf_decode(glyph, &unicode, NK_UTF_SIZE); - if (len && ((in->keyboard.text_len + len) < NK_INPUT_MAX)) { - nk_utf_encode(unicode, &in->keyboard.text[in->keyboard.text_len], - NK_INPUT_MAX - in->keyboard.text_len); - in->keyboard.text_len += len; - } -} - -NK_API void -nk_input_char(struct nk_context *ctx, char c) -{ - nk_glyph glyph; - NK_ASSERT(ctx); - if (!ctx) return; - glyph[0] = c; - nk_input_glyph(ctx, glyph); -} - -NK_API void -nk_input_unicode(struct nk_context *ctx, nk_rune unicode) -{ - nk_glyph rune; - NK_ASSERT(ctx); - if (!ctx) return; - nk_utf_encode(unicode, rune, NK_UTF_SIZE); - nk_input_glyph(ctx, rune); -} - -NK_API int -nk_input_has_mouse_click(const struct nk_input *i, enum nk_buttons id) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return (btn->clicked && btn->down == nk_false) ? nk_true : nk_false; -} - -NK_API int -nk_input_has_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h)) - return nk_false; - return nk_true; -} - -NK_API int -nk_input_has_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b, int down) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return nk_input_has_mouse_click_in_rect(i, id, b) && (btn->down == down); -} - -NK_API int -nk_input_is_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return (nk_input_has_mouse_click_down_in_rect(i, id, b, nk_false) && - btn->clicked) ? nk_true : nk_false; -} - -NK_API int -nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b, int down) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return (nk_input_has_mouse_click_down_in_rect(i, id, b, down) && - btn->clicked) ? nk_true : nk_false; -} - -NK_API int -nk_input_any_mouse_click_in_rect(const struct nk_input *in, struct nk_rect b) -{ - int i, down = 0; - for (i = 0; i < NK_BUTTON_MAX; ++i) - down = down || nk_input_is_mouse_click_in_rect(in, (enum nk_buttons)i, b); - return down; -} - -NK_API int -nk_input_is_mouse_hovering_rect(const struct nk_input *i, struct nk_rect rect) -{ - if (!i) return nk_false; - return NK_INBOX(i->mouse.pos.x, i->mouse.pos.y, rect.x, rect.y, rect.w, rect.h); -} - -NK_API int -nk_input_is_mouse_prev_hovering_rect(const struct nk_input *i, struct nk_rect rect) -{ - if (!i) return nk_false; - return NK_INBOX(i->mouse.prev.x, i->mouse.prev.y, rect.x, rect.y, rect.w, rect.h); -} - -NK_API int -nk_input_mouse_clicked(const struct nk_input *i, enum nk_buttons id, struct nk_rect rect) -{ - if (!i) return nk_false; - if (!nk_input_is_mouse_hovering_rect(i, rect)) return nk_false; - return nk_input_is_mouse_click_in_rect(i, id, rect); -} - -NK_API int -nk_input_is_mouse_down(const struct nk_input *i, enum nk_buttons id) -{ - if (!i) return nk_false; - return i->mouse.buttons[id].down; -} - -NK_API int -nk_input_is_mouse_pressed(const struct nk_input *i, enum nk_buttons id) -{ - const struct nk_mouse_button *b; - if (!i) return nk_false; - b = &i->mouse.buttons[id]; - if (b->down && b->clicked) - return nk_true; - return nk_false; -} - -NK_API int -nk_input_is_mouse_released(const struct nk_input *i, enum nk_buttons id) -{ - if (!i) return nk_false; - return (!i->mouse.buttons[id].down && i->mouse.buttons[id].clicked); -} - -NK_API int -nk_input_is_key_pressed(const struct nk_input *i, enum nk_keys key) -{ - const struct nk_key *k; - if (!i) return nk_false; - k = &i->keyboard.keys[key]; - if ((k->down && k->clicked) || (!k->down && k->clicked >= 2)) - return nk_true; - return nk_false; -} - -NK_API int -nk_input_is_key_released(const struct nk_input *i, enum nk_keys key) -{ - const struct nk_key *k; - if (!i) return nk_false; - k = &i->keyboard.keys[key]; - if ((!k->down && k->clicked) || (k->down && k->clicked >= 2)) - return nk_true; - return nk_false; -} - -NK_API int -nk_input_is_key_down(const struct nk_input *i, enum nk_keys key) -{ - const struct nk_key *k; - if (!i) return nk_false; - k = &i->keyboard.keys[key]; - if (k->down) return nk_true; - return nk_false; -} - -/* - * ============================================================== - * - * TEXT EDITOR - * - * =============================================================== - */ -/* stb_textedit.h - v1.8 - public domain - Sean Barrett */ -struct nk_text_find { - float x,y; /* position of n'th character */ - float height; /* height of line */ - int first_char, length; /* first char of row, and length */ - int prev_first; /*_ first char of previous row */ -}; - -struct nk_text_edit_row { - float x0,x1; - /* starting x location, end x location (allows for align=right, etc) */ - float baseline_y_delta; - /* position of baseline relative to previous row's baseline*/ - float ymin,ymax; - /* height of row above and below baseline */ - int num_chars; -}; - -/* forward declarations */ -NK_INTERN void nk_textedit_makeundo_delete(struct nk_text_edit*, int, int); -NK_INTERN void nk_textedit_makeundo_insert(struct nk_text_edit*, int, int); -NK_INTERN void nk_textedit_makeundo_replace(struct nk_text_edit*, int, int, int); -#define NK_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) - -NK_INTERN float -nk_textedit_get_width(const struct nk_text_edit *edit, int line_start, int char_id, - const struct nk_user_font *font) -{ - int len = 0; - nk_rune unicode = 0; - const char *str = nk_str_at_const(&edit->string, line_start + char_id, &unicode, &len); - return font->width(font->userdata, font->height, str, len); -} - -NK_INTERN void -nk_textedit_layout_row(struct nk_text_edit_row *r, struct nk_text_edit *edit, - int line_start_id, float row_height, const struct nk_user_font *font) -{ - int l; - int glyphs = 0; - nk_rune unicode; - const char *remaining; - int len = nk_str_len_char(&edit->string); - const char *end = nk_str_get_const(&edit->string) + len; - const char *text = nk_str_at_const(&edit->string, line_start_id, &unicode, &l); - const struct nk_vec2 size = nk_text_calculate_text_bounds(font, - text, (int)(end - text), row_height, &remaining, 0, &glyphs, NK_STOP_ON_NEW_LINE); - - r->x0 = 0.0f; - r->x1 = size.x; - r->baseline_y_delta = size.y; - r->ymin = 0.0f; - r->ymax = size.y; - r->num_chars = glyphs; -} - -NK_INTERN int -nk_textedit_locate_coord(struct nk_text_edit *edit, float x, float y, - const struct nk_user_font *font, float row_height) -{ - struct nk_text_edit_row r; - int n = edit->string.len; - float base_y = 0, prev_x; - int i=0, k; - - r.x0 = r.x1 = 0; - r.ymin = r.ymax = 0; - r.num_chars = 0; - - /* search rows to find one that straddles 'y' */ - while (i < n) { - nk_textedit_layout_row(&r, edit, i, row_height, font); - if (r.num_chars <= 0) - return n; - - if (i==0 && y < base_y + r.ymin) - return 0; - - if (y < base_y + r.ymax) - break; - - i += r.num_chars; - base_y += r.baseline_y_delta; - } - - /* below all text, return 'after' last character */ - if (i >= n) - return n; - - /* check if it's before the beginning of the line */ - if (x < r.x0) - return i; - - /* check if it's before the end of the line */ - if (x < r.x1) { - /* search characters in row for one that straddles 'x' */ - k = i; - prev_x = r.x0; - for (i=0; i < r.num_chars; ++i) { - float w = nk_textedit_get_width(edit, k, i, font); - if (x < prev_x+w) { - if (x < prev_x+w/2) - return k+i; - else return k+i+1; - } - prev_x += w; - } - /* shouldn't happen, but if it does, fall through to end-of-line case */ - } - - /* if the last character is a newline, return that. - * otherwise return 'after' the last character */ - if (nk_str_rune_at(&edit->string, i+r.num_chars-1) == '\n') - return i+r.num_chars-1; - else return i+r.num_chars; -} - -NK_INTERN void -nk_textedit_click(struct nk_text_edit *state, float x, float y, - const struct nk_user_font *font, float row_height) -{ - /* API click: on mouse down, move the cursor to the clicked location, - * and reset the selection */ - state->cursor = nk_textedit_locate_coord(state, x, y, font, row_height); - state->select_start = state->cursor; - state->select_end = state->cursor; - state->has_preferred_x = 0; -} - -NK_INTERN void -nk_textedit_drag(struct nk_text_edit *state, float x, float y, - const struct nk_user_font *font, float row_height) -{ - /* API drag: on mouse drag, move the cursor and selection endpoint - * to the clicked location */ - int p = nk_textedit_locate_coord(state, x, y, font, row_height); - if (state->select_start == state->select_end) - state->select_start = state->cursor; - state->cursor = state->select_end = p; -} - -NK_INTERN void -nk_textedit_find_charpos(struct nk_text_find *find, struct nk_text_edit *state, - int n, int single_line, const struct nk_user_font *font, float row_height) -{ - /* find the x/y location of a character, and remember info about the previous - * row in case we get a move-up event (for page up, we'll have to rescan) */ - struct nk_text_edit_row r; - int prev_start = 0; - int z = state->string.len; - int i=0, first; - - nk_zero_struct(r); - if (n == z) { - /* if it's at the end, then find the last line -- simpler than trying to - explicitly handle this case in the regular code */ - nk_textedit_layout_row(&r, state, 0, row_height, font); - if (single_line) { - find->first_char = 0; - find->length = z; - } else { - while (i < z) { - prev_start = i; - i += r.num_chars; - nk_textedit_layout_row(&r, state, i, row_height, font); - } - - find->first_char = i; - find->length = r.num_chars; - } - find->x = r.x1; - find->y = r.ymin; - find->height = r.ymax - r.ymin; - find->prev_first = prev_start; - return; - } - - /* search rows to find the one that straddles character n */ - find->y = 0; - - for(;;) { - nk_textedit_layout_row(&r, state, i, row_height, font); - if (n < i + r.num_chars) break; - prev_start = i; - i += r.num_chars; - find->y += r.baseline_y_delta; - } - - find->first_char = first = i; - find->length = r.num_chars; - find->height = r.ymax - r.ymin; - find->prev_first = prev_start; - - /* now scan to find xpos */ - find->x = r.x0; - for (i=0; first+i < n; ++i) - find->x += nk_textedit_get_width(state, first, i, font); -} - -NK_INTERN void -nk_textedit_clamp(struct nk_text_edit *state) -{ - /* make the selection/cursor state valid if client altered the string */ - int n = state->string.len; - if (NK_TEXT_HAS_SELECTION(state)) { - if (state->select_start > n) state->select_start = n; - if (state->select_end > n) state->select_end = n; - /* if clamping forced them to be equal, move the cursor to match */ - if (state->select_start == state->select_end) - state->cursor = state->select_start; - } - if (state->cursor > n) state->cursor = n; -} - -NK_API void -nk_textedit_delete(struct nk_text_edit *state, int where, int len) -{ - /* delete characters while updating undo */ - nk_textedit_makeundo_delete(state, where, len); - nk_str_delete_runes(&state->string, where, len); - state->has_preferred_x = 0; -} - -NK_API void -nk_textedit_delete_selection(struct nk_text_edit *state) -{ - /* delete the section */ - nk_textedit_clamp(state); - if (NK_TEXT_HAS_SELECTION(state)) { - if (state->select_start < state->select_end) { - nk_textedit_delete(state, state->select_start, - state->select_end - state->select_start); - state->select_end = state->cursor = state->select_start; - } else { - nk_textedit_delete(state, state->select_end, - state->select_start - state->select_end); - state->select_start = state->cursor = state->select_end; - } - state->has_preferred_x = 0; - } -} - -NK_INTERN void -nk_textedit_sortselection(struct nk_text_edit *state) -{ - /* canonicalize the selection so start <= end */ - if (state->select_end < state->select_start) { - int temp = state->select_end; - state->select_end = state->select_start; - state->select_start = temp; - } -} - -NK_INTERN void -nk_textedit_move_to_first(struct nk_text_edit *state) -{ - /* move cursor to first character of selection */ - if (NK_TEXT_HAS_SELECTION(state)) { - nk_textedit_sortselection(state); - state->cursor = state->select_start; - state->select_end = state->select_start; - state->has_preferred_x = 0; - } -} - -NK_INTERN void -nk_textedit_move_to_last(struct nk_text_edit *state) -{ - /* move cursor to last character of selection */ - if (NK_TEXT_HAS_SELECTION(state)) { - nk_textedit_sortselection(state); - nk_textedit_clamp(state); - state->cursor = state->select_end; - state->select_start = state->select_end; - state->has_preferred_x = 0; - } -} - -NK_INTERN int -nk_is_word_boundary( struct nk_text_edit *state, int idx) -{ - int len; - nk_rune c; - if (idx <= 0) return 1; - if (!nk_str_at_rune(&state->string, idx, &c, &len)) return 1; - return (c == ' ' || c == '\t' ||c == 0x3000 || c == ',' || c == ';' || - c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' || - c == '|'); -} - -NK_INTERN int -nk_textedit_move_to_word_previous(struct nk_text_edit *state) -{ - int c = state->cursor - 1; - while( c >= 0 && !nk_is_word_boundary(state, c)) - --c; - - if( c < 0 ) - c = 0; - - return c; -} - -NK_INTERN int -nk_textedit_move_to_word_next(struct nk_text_edit *state) -{ - const int len = state->string.len; - int c = state->cursor+1; - while( c < len && !nk_is_word_boundary(state, c)) - ++c; - - if( c > len ) - c = len; - - return c; -} - -NK_INTERN void -nk_textedit_prep_selection_at_cursor(struct nk_text_edit *state) -{ - /* update selection and cursor to match each other */ - if (!NK_TEXT_HAS_SELECTION(state)) - state->select_start = state->select_end = state->cursor; - else state->cursor = state->select_end; -} - -NK_API int -nk_textedit_cut(struct nk_text_edit *state) -{ - /* API cut: delete selection */ - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - return 0; - if (NK_TEXT_HAS_SELECTION(state)) { - nk_textedit_delete_selection(state); /* implicitly clamps */ - state->has_preferred_x = 0; - return 1; - } - return 0; -} - -NK_API int -nk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len) -{ - /* API paste: replace existing selection with passed-in text */ - int glyphs; - const char *text = (const char *) ctext; - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) return 0; - - /* if there's a selection, the paste should delete it */ - nk_textedit_clamp(state); - nk_textedit_delete_selection(state); - - /* try to insert the characters */ - glyphs = nk_utf_len(ctext, len); - if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) { - nk_textedit_makeundo_insert(state, state->cursor, glyphs); - state->cursor += len; - state->has_preferred_x = 0; - return 1; - } - /* remove the undo since we didn't actually insert the characters */ - if (state->undo.undo_point) - --state->undo.undo_point; - return 0; -} - -NK_API void -nk_textedit_text(struct nk_text_edit *state, const char *text, int total_len) -{ - nk_rune unicode; - int glyph_len; - int text_len = 0; - - NK_ASSERT(state); - NK_ASSERT(text); - if (!text || !total_len || state->mode == NK_TEXT_EDIT_MODE_VIEW) return; - - glyph_len = nk_utf_decode(text, &unicode, total_len); - while ((text_len < total_len) && glyph_len) - { - /* don't insert a backward delete, just process the event */ - if (unicode == 127) goto next; - /* can't add newline in single-line mode */ - if (unicode == '\n' && state->single_line) goto next; - /* filter incoming text */ - if (state->filter && !state->filter(state, unicode)) goto next; - - if (!NK_TEXT_HAS_SELECTION(state) && - state->cursor < state->string.len) - { - if (state->mode == NK_TEXT_EDIT_MODE_REPLACE) { - nk_textedit_makeundo_replace(state, state->cursor, 1, 1); - nk_str_delete_runes(&state->string, state->cursor, 1); - } - if (nk_str_insert_text_utf8(&state->string, state->cursor, - text+text_len, 1)) - { - ++state->cursor; - state->has_preferred_x = 0; - } - } else { - nk_textedit_delete_selection(state); /* implicitly clamps */ - if (nk_str_insert_text_utf8(&state->string, state->cursor, - text+text_len, 1)) - { - nk_textedit_makeundo_insert(state, state->cursor, 1); - ++state->cursor; - state->has_preferred_x = 0; - } - } - next: - text_len += glyph_len; - glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len); - } -} - -NK_INTERN void -nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod, - const struct nk_user_font *font, float row_height) -{ -retry: - switch (key) - { - case NK_KEY_NONE: - case NK_KEY_CTRL: - case NK_KEY_ENTER: - case NK_KEY_SHIFT: - case NK_KEY_TAB: - case NK_KEY_COPY: - case NK_KEY_CUT: - case NK_KEY_PASTE: - case NK_KEY_MAX: - default: break; - case NK_KEY_TEXT_UNDO: - nk_textedit_undo(state); - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_REDO: - nk_textedit_redo(state); - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_SELECT_ALL: - nk_textedit_select_all(state); - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_INSERT_MODE: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - state->mode = NK_TEXT_EDIT_MODE_INSERT; - break; - case NK_KEY_TEXT_REPLACE_MODE: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - state->mode = NK_TEXT_EDIT_MODE_REPLACE; - break; - case NK_KEY_TEXT_RESET_MODE: - if (state->mode == NK_TEXT_EDIT_MODE_INSERT || - state->mode == NK_TEXT_EDIT_MODE_REPLACE) - state->mode = NK_TEXT_EDIT_MODE_VIEW; - break; - - case NK_KEY_LEFT: - if (shift_mod) { - nk_textedit_clamp(state); - nk_textedit_prep_selection_at_cursor(state); - /* move selection left */ - if (state->select_end > 0) - --state->select_end; - state->cursor = state->select_end; - state->has_preferred_x = 0; - } else { - /* if currently there's a selection, - * move cursor to start of selection */ - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_first(state); - else if (state->cursor > 0) - --state->cursor; - state->has_preferred_x = 0; - } break; - - case NK_KEY_RIGHT: - if (shift_mod) { - nk_textedit_prep_selection_at_cursor(state); - /* move selection right */ - ++state->select_end; - nk_textedit_clamp(state); - state->cursor = state->select_end; - state->has_preferred_x = 0; - } else { - /* if currently there's a selection, - * move cursor to end of selection */ - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_last(state); - else ++state->cursor; - nk_textedit_clamp(state); - state->has_preferred_x = 0; - } break; - - case NK_KEY_TEXT_WORD_LEFT: - if (shift_mod) { - if( !NK_TEXT_HAS_SELECTION( state ) ) - nk_textedit_prep_selection_at_cursor(state); - state->cursor = nk_textedit_move_to_word_previous(state); - state->select_end = state->cursor; - nk_textedit_clamp(state ); - } else { - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_first(state); - else { - state->cursor = nk_textedit_move_to_word_previous(state); - nk_textedit_clamp(state ); - } - } break; - - case NK_KEY_TEXT_WORD_RIGHT: - if (shift_mod) { - if( !NK_TEXT_HAS_SELECTION( state ) ) - nk_textedit_prep_selection_at_cursor(state); - state->cursor = nk_textedit_move_to_word_next(state); - state->select_end = state->cursor; - nk_textedit_clamp(state); - } else { - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_last(state); - else { - state->cursor = nk_textedit_move_to_word_next(state); - nk_textedit_clamp(state ); - } - } break; - - case NK_KEY_DOWN: { - struct nk_text_find find; - struct nk_text_edit_row row; - int i, sel = shift_mod; - - if (state->single_line) { - /* on windows, up&down in single-line behave like left&right */ - key = NK_KEY_RIGHT; - goto retry; - } - - if (sel) - nk_textedit_prep_selection_at_cursor(state); - else if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_last(state); - - /* compute current position of cursor point */ - nk_textedit_clamp(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - - /* now find character position down a row */ - if (find.length) - { - float x; - float goal_x = state->has_preferred_x ? state->preferred_x : find.x; - int start = find.first_char + find.length; - - state->cursor = start; - nk_textedit_layout_row(&row, state, state->cursor, row_height, font); - x = row.x0; - - for (i=0; i < row.num_chars && x < row.x1; ++i) { - float dx = nk_textedit_get_width(state, start, i, font); - x += dx; - if (x > goal_x) - break; - ++state->cursor; - } - nk_textedit_clamp(state); - - state->has_preferred_x = 1; - state->preferred_x = goal_x; - if (sel) - state->select_end = state->cursor; - } - } break; - - case NK_KEY_UP: { - struct nk_text_find find; - struct nk_text_edit_row row; - int i, sel = shift_mod; - - if (state->single_line) { - /* on windows, up&down become left&right */ - key = NK_KEY_LEFT; - goto retry; - } - - if (sel) - nk_textedit_prep_selection_at_cursor(state); - else if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_first(state); - - /* compute current position of cursor point */ - nk_textedit_clamp(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - - /* can only go up if there's a previous row */ - if (find.prev_first != find.first_char) { - /* now find character position up a row */ - float x; - float goal_x = state->has_preferred_x ? state->preferred_x : find.x; - - state->cursor = find.prev_first; - nk_textedit_layout_row(&row, state, state->cursor, row_height, font); - x = row.x0; - - for (i=0; i < row.num_chars && x < row.x1; ++i) { - float dx = nk_textedit_get_width(state, find.prev_first, i, font); - x += dx; - if (x > goal_x) - break; - ++state->cursor; - } - nk_textedit_clamp(state); - - state->has_preferred_x = 1; - state->preferred_x = goal_x; - if (sel) state->select_end = state->cursor; - } - } break; - - case NK_KEY_DEL: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - break; - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_delete_selection(state); - else { - int n = state->string.len; - if (state->cursor < n) - nk_textedit_delete(state, state->cursor, 1); - } - state->has_preferred_x = 0; - break; - - case NK_KEY_BACKSPACE: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - break; - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_delete_selection(state); - else { - nk_textedit_clamp(state); - if (state->cursor > 0) { - nk_textedit_delete(state, state->cursor-1, 1); - --state->cursor; - } - } - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_START: - if (shift_mod) { - nk_textedit_prep_selection_at_cursor(state); - state->cursor = state->select_end = 0; - state->has_preferred_x = 0; - } else { - state->cursor = state->select_start = state->select_end = 0; - state->has_preferred_x = 0; - } - break; - - case NK_KEY_TEXT_END: - if (shift_mod) { - nk_textedit_prep_selection_at_cursor(state); - state->cursor = state->select_end = state->string.len; - state->has_preferred_x = 0; - } else { - state->cursor = state->string.len; - state->select_start = state->select_end = 0; - state->has_preferred_x = 0; - } - break; - - case NK_KEY_TEXT_LINE_START: { - if (shift_mod) { - struct nk_text_find find; - nk_textedit_clamp(state); - nk_textedit_prep_selection_at_cursor(state); - if (state->string.len && state->cursor == state->string.len) - --state->cursor; - nk_textedit_find_charpos(&find, state,state->cursor, state->single_line, - font, row_height); - state->cursor = state->select_end = find.first_char; - state->has_preferred_x = 0; - } else { - struct nk_text_find find; - if (state->string.len && state->cursor == state->string.len) - --state->cursor; - nk_textedit_clamp(state); - nk_textedit_move_to_first(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - state->cursor = find.first_char; - state->has_preferred_x = 0; - } - } break; - - case NK_KEY_TEXT_LINE_END: { - if (shift_mod) { - struct nk_text_find find; - nk_textedit_clamp(state); - nk_textedit_prep_selection_at_cursor(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - state->has_preferred_x = 0; - state->cursor = find.first_char + find.length; - if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n') - --state->cursor; - state->select_end = state->cursor; - } else { - struct nk_text_find find; - nk_textedit_clamp(state); - nk_textedit_move_to_first(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - - state->has_preferred_x = 0; - state->cursor = find.first_char + find.length; - if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n') - --state->cursor; - }} break; - } -} - -NK_INTERN void -nk_textedit_flush_redo(struct nk_text_undo_state *state) -{ - state->redo_point = NK_TEXTEDIT_UNDOSTATECOUNT; - state->redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT; -} - -NK_INTERN void -nk_textedit_discard_undo(struct nk_text_undo_state *state) -{ - /* discard the oldest entry in the undo list */ - if (state->undo_point > 0) { - /* if the 0th undo state has characters, clean those up */ - if (state->undo_rec[0].char_storage >= 0) { - int n = state->undo_rec[0].insert_length, i; - /* delete n characters from all other records */ - state->undo_char_point = (short)(state->undo_char_point - n); - NK_MEMCPY(state->undo_char, state->undo_char + n, - (nk_size)state->undo_char_point*sizeof(nk_rune)); - for (i=0; i < state->undo_point; ++i) { - if (state->undo_rec[i].char_storage >= 0) - state->undo_rec[i].char_storage = (short) - (state->undo_rec[i].char_storage - n); - } - } - --state->undo_point; - NK_MEMCPY(state->undo_rec, state->undo_rec+1, - (nk_size)((nk_size)state->undo_point * sizeof(state->undo_rec[0]))); - } -} - -NK_INTERN void -nk_textedit_discard_redo(struct nk_text_undo_state *state) -{ -/* discard the oldest entry in the redo list--it's bad if this - ever happens, but because undo & redo have to store the actual - characters in different cases, the redo character buffer can - fill up even though the undo buffer didn't */ - nk_size num; - int k = NK_TEXTEDIT_UNDOSTATECOUNT-1; - if (state->redo_point <= k) { - /* if the k'th undo state has characters, clean those up */ - if (state->undo_rec[k].char_storage >= 0) { - int n = state->undo_rec[k].insert_length, i; - /* delete n characters from all other records */ - state->redo_char_point = (short)(state->redo_char_point + n); - num = (nk_size)(NK_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point); - NK_MEMCPY(state->undo_char + state->redo_char_point, - state->undo_char + state->redo_char_point-n, num * sizeof(char)); - for (i = state->redo_point; i < k; ++i) { - if (state->undo_rec[i].char_storage >= 0) { - state->undo_rec[i].char_storage = (short) - (state->undo_rec[i].char_storage + n); - } - } - } - ++state->redo_point; - num = (nk_size)(NK_TEXTEDIT_UNDOSTATECOUNT - state->redo_point); - if (num) NK_MEMCPY(state->undo_rec + state->redo_point-1, - state->undo_rec + state->redo_point, num * sizeof(state->undo_rec[0])); - } -} - -NK_INTERN struct nk_text_undo_record* -nk_textedit_create_undo_record(struct nk_text_undo_state *state, int numchars) -{ - /* any time we create a new undo record, we discard redo*/ - nk_textedit_flush_redo(state); - - /* if we have no free records, we have to make room, - * by sliding the existing records down */ - if (state->undo_point == NK_TEXTEDIT_UNDOSTATECOUNT) - nk_textedit_discard_undo(state); - - /* if the characters to store won't possibly fit in the buffer, - * we can't undo */ - if (numchars > NK_TEXTEDIT_UNDOCHARCOUNT) { - state->undo_point = 0; - state->undo_char_point = 0; - return 0; - } - - /* if we don't have enough free characters in the buffer, - * we have to make room */ - while (state->undo_char_point + numchars > NK_TEXTEDIT_UNDOCHARCOUNT) - nk_textedit_discard_undo(state); - return &state->undo_rec[state->undo_point++]; -} - -NK_INTERN nk_rune* -nk_textedit_createundo(struct nk_text_undo_state *state, int pos, - int insert_len, int delete_len) -{ - struct nk_text_undo_record *r = nk_textedit_create_undo_record(state, insert_len); - if (r == 0) - return 0; - - r->where = pos; - r->insert_length = (short) insert_len; - r->delete_length = (short) delete_len; - - if (insert_len == 0) { - r->char_storage = -1; - return 0; - } else { - r->char_storage = state->undo_char_point; - state->undo_char_point = (short)(state->undo_char_point + insert_len); - return &state->undo_char[r->char_storage]; - } -} - -NK_API void -nk_textedit_undo(struct nk_text_edit *state) -{ - struct nk_text_undo_state *s = &state->undo; - struct nk_text_undo_record u, *r; - if (s->undo_point == 0) - return; - - /* we need to do two things: apply the undo record, and create a redo record */ - u = s->undo_rec[s->undo_point-1]; - r = &s->undo_rec[s->redo_point-1]; - r->char_storage = -1; - - r->insert_length = u.delete_length; - r->delete_length = u.insert_length; - r->where = u.where; - - if (u.delete_length) - { - /* if the undo record says to delete characters, then the redo record will - need to re-insert the characters that get deleted, so we need to store - them. - there are three cases: - - there's enough room to store the characters - - characters stored for *redoing* don't leave room for redo - - characters stored for *undoing* don't leave room for redo - if the last is true, we have to bail */ - if (s->undo_char_point + u.delete_length >= NK_TEXTEDIT_UNDOCHARCOUNT) { - /* the undo records take up too much character space; there's no space - * to store the redo characters */ - r->insert_length = 0; - } else { - int i; - /* there's definitely room to store the characters eventually */ - while (s->undo_char_point + u.delete_length > s->redo_char_point) { - /* there's currently not enough room, so discard a redo record */ - nk_textedit_discard_redo(s); - /* should never happen: */ - if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT) - return; - } - - r = &s->undo_rec[s->redo_point-1]; - r->char_storage = (short)(s->redo_char_point - u.delete_length); - s->redo_char_point = (short)(s->redo_char_point - u.delete_length); - - /* now save the characters */ - for (i=0; i < u.delete_length; ++i) - s->undo_char[r->char_storage + i] = - nk_str_rune_at(&state->string, u.where + i); - } - /* now we can carry out the deletion */ - nk_str_delete_runes(&state->string, u.where, u.delete_length); - } - - /* check type of recorded action: */ - if (u.insert_length) { - /* easy case: was a deletion, so we need to insert n characters */ - nk_str_insert_text_runes(&state->string, u.where, - &s->undo_char[u.char_storage], u.insert_length); - s->undo_char_point = (short)(s->undo_char_point - u.insert_length); - } - state->cursor = (short)(u.where + u.insert_length); - - s->undo_point--; - s->redo_point--; -} - -NK_API void -nk_textedit_redo(struct nk_text_edit *state) -{ - struct nk_text_undo_state *s = &state->undo; - struct nk_text_undo_record *u, r; - if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT) - return; - - /* we need to do two things: apply the redo record, and create an undo record */ - u = &s->undo_rec[s->undo_point]; - r = s->undo_rec[s->redo_point]; - - /* we KNOW there must be room for the undo record, because the redo record - was derived from an undo record */ - u->delete_length = r.insert_length; - u->insert_length = r.delete_length; - u->where = r.where; - u->char_storage = -1; - - if (r.delete_length) { - /* the redo record requires us to delete characters, so the undo record - needs to store the characters */ - if (s->undo_char_point + u->insert_length > s->redo_char_point) { - u->insert_length = 0; - u->delete_length = 0; - } else { - int i; - u->char_storage = s->undo_char_point; - s->undo_char_point = (short)(s->undo_char_point + u->insert_length); - - /* now save the characters */ - for (i=0; i < u->insert_length; ++i) { - s->undo_char[u->char_storage + i] = - nk_str_rune_at(&state->string, u->where + i); - } - } - nk_str_delete_runes(&state->string, r.where, r.delete_length); - } - - if (r.insert_length) { - /* easy case: need to insert n characters */ - nk_str_insert_text_runes(&state->string, r.where, - &s->undo_char[r.char_storage], r.insert_length); - } - state->cursor = r.where + r.insert_length; - - s->undo_point++; - s->redo_point++; -} - -NK_INTERN void -nk_textedit_makeundo_insert(struct nk_text_edit *state, int where, int length) -{ - nk_textedit_createundo(&state->undo, where, 0, length); -} - -NK_INTERN void -nk_textedit_makeundo_delete(struct nk_text_edit *state, int where, int length) -{ - int i; - nk_rune *p = nk_textedit_createundo(&state->undo, where, length, 0); - if (p) { - for (i=0; i < length; ++i) - p[i] = nk_str_rune_at(&state->string, where+i); - } -} - -NK_INTERN void -nk_textedit_makeundo_replace(struct nk_text_edit *state, int where, - int old_length, int new_length) -{ - int i; - nk_rune *p = nk_textedit_createundo(&state->undo, where, old_length, new_length); - if (p) { - for (i=0; i < old_length; ++i) - p[i] = nk_str_rune_at(&state->string, where+i); - } -} - -NK_INTERN void -nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type, - nk_plugin_filter filter) -{ - /* reset the state to default */ - state->undo.undo_point = 0; - state->undo.undo_char_point = 0; - state->undo.redo_point = NK_TEXTEDIT_UNDOSTATECOUNT; - state->undo.redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT; - state->select_end = state->select_start = 0; - state->cursor = 0; - state->has_preferred_x = 0; - state->preferred_x = 0; - state->cursor_at_end_of_line = 0; - state->initialized = 1; - state->single_line = (unsigned char)(type == NK_TEXT_EDIT_SINGLE_LINE); - state->mode = NK_TEXT_EDIT_MODE_VIEW; - state->filter = filter; - state->scrollbar = nk_vec2(0,0); -} - -NK_API void -nk_textedit_init_fixed(struct nk_text_edit *state, void *memory, nk_size size) -{ - NK_ASSERT(state); - NK_ASSERT(memory); - if (!state || !memory || !size) return; - NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); - nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); - nk_str_init_fixed(&state->string, memory, size); -} - -NK_API void -nk_textedit_init(struct nk_text_edit *state, struct nk_allocator *alloc, nk_size size) -{ - NK_ASSERT(state); - NK_ASSERT(alloc); - if (!state || !alloc) return; - NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); - nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); - nk_str_init(&state->string, alloc, size); -} - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void -nk_textedit_init_default(struct nk_text_edit *state) -{ - NK_ASSERT(state); - if (!state) return; - NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); - nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); - nk_str_init_default(&state->string); -} -#endif - -NK_API void -nk_textedit_select_all(struct nk_text_edit *state) -{ - NK_ASSERT(state); - state->select_start = 0; - state->select_end = state->string.len; -} - -NK_API void -nk_textedit_free(struct nk_text_edit *state) -{ - NK_ASSERT(state); - if (!state) return; - nk_str_free(&state->string); -} - -/* =============================================================== - * - * TEXT WIDGET - * - * ===============================================================*/ -#define nk_widget_state_reset(s)\ - if ((*(s)) & NK_WIDGET_STATE_MODIFIED)\ - (*(s)) = NK_WIDGET_STATE_INACTIVE|NK_WIDGET_STATE_MODIFIED;\ - else (*(s)) = NK_WIDGET_STATE_INACTIVE; - -struct nk_text { - struct nk_vec2 padding; - struct nk_color background; - struct nk_color text; -}; - -NK_INTERN void -nk_widget_text(struct nk_command_buffer *o, struct nk_rect b, - const char *string, int len, const struct nk_text *t, - nk_flags a, const struct nk_user_font *f) -{ - struct nk_rect label; - float text_width; - - NK_ASSERT(o); - NK_ASSERT(t); - if (!o || !t) return; - - b.h = NK_MAX(b.h, 2 * t->padding.y); - label.x = 0; label.w = 0; - label.y = b.y + t->padding.y; - label.h = NK_MIN(f->height, b.h - 2 * t->padding.y); - - text_width = f->width(f->userdata, f->height, (const char*)string, len); - text_width += (2.0f * t->padding.x); - - /* align in x-axis */ - if (a & NK_TEXT_ALIGN_LEFT) { - label.x = b.x + t->padding.x; - label.w = NK_MAX(0, b.w - 2 * t->padding.x); - } else if (a & NK_TEXT_ALIGN_CENTERED) { - label.w = NK_MAX(1, 2 * t->padding.x + (float)text_width); - label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x) - label.w) / 2); - label.x = NK_MAX(b.x + t->padding.x, label.x); - label.w = NK_MIN(b.x + b.w, label.x + label.w); - if (label.w >= label.x) label.w -= label.x; - } else if (a & NK_TEXT_ALIGN_RIGHT) { - label.x = NK_MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width)); - label.w = (float)text_width + 2 * t->padding.x; - } else return; - - /* align in y-axis */ - if (a & NK_TEXT_ALIGN_MIDDLE) { - label.y = b.y + b.h/2.0f - (float)f->height/2.0f; - label.h = NK_MAX(b.h/2.0f, b.h - (b.h/2.0f + f->height/2.0f)); - } else if (a & NK_TEXT_ALIGN_BOTTOM) { - label.y = b.y + b.h - f->height; - label.h = f->height; - } - nk_draw_text(o, label, (const char*)string, - len, f, t->background, t->text); -} - -NK_INTERN void -nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b, - const char *string, int len, const struct nk_text *t, - const struct nk_user_font *f) -{ - float width; - int glyphs = 0; - int fitting = 0; - int done = 0; - struct nk_rect line; - struct nk_text text; - NK_INTERN nk_rune seperator[] = {' '}; - - NK_ASSERT(o); - NK_ASSERT(t); - if (!o || !t) return; - - text.padding = nk_vec2(0,0); - text.background = t->background; - text.text = t->text; - - b.w = NK_MAX(b.w, 2 * t->padding.x); - b.h = NK_MAX(b.h, 2 * t->padding.y); - b.h = b.h - 2 * t->padding.y; - - line.x = b.x + t->padding.x; - line.y = b.y + t->padding.y; - line.w = b.w - 2 * t->padding.x; - line.h = 2 * t->padding.y + f->height; - - fitting = nk_text_clamp(f, string, len, line.w, &glyphs, &width, seperator,NK_LEN(seperator)); - while (done < len) { - if (!fitting || line.y + line.h >= (b.y + b.h)) break; - nk_widget_text(o, line, &string[done], fitting, &text, NK_TEXT_LEFT, f); - done += fitting; - line.y += f->height + 2 * t->padding.y; - fitting = nk_text_clamp(f, &string[done], len - done, line.w, &glyphs, &width, seperator,NK_LEN(seperator)); - } -} - -/* =============================================================== - * - * BUTTON - * - * ===============================================================*/ -NK_INTERN void -nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type, - struct nk_rect content, struct nk_color background, struct nk_color foreground, - float border_width, const struct nk_user_font *font) -{ - switch (type) { - case NK_SYMBOL_X: - case NK_SYMBOL_UNDERSCORE: - case NK_SYMBOL_PLUS: - case NK_SYMBOL_MINUS: { - /* single character text symbol */ - const char *X = (type == NK_SYMBOL_X) ? "x": - (type == NK_SYMBOL_UNDERSCORE) ? "_": - (type == NK_SYMBOL_PLUS) ? "+": "-"; - struct nk_text text; - text.padding = nk_vec2(0,0); - text.background = background; - text.text = foreground; - nk_widget_text(out, content, X, 1, &text, NK_TEXT_CENTERED, font); - } break; - case NK_SYMBOL_CIRCLE_SOLID: - case NK_SYMBOL_CIRCLE_OUTLINE: - case NK_SYMBOL_RECT_SOLID: - case NK_SYMBOL_RECT_OUTLINE: { - /* simple empty/filled shapes */ - if (type == NK_SYMBOL_RECT_SOLID || type == NK_SYMBOL_RECT_OUTLINE) { - nk_fill_rect(out, content, 0, foreground); - if (type == NK_SYMBOL_RECT_OUTLINE) - nk_fill_rect(out, nk_shrink_rect(content, border_width), 0, background); - } else { - nk_fill_circle(out, content, foreground); - if (type == NK_SYMBOL_CIRCLE_OUTLINE) - nk_fill_circle(out, nk_shrink_rect(content, 1), background); - } - } break; - case NK_SYMBOL_TRIANGLE_UP: - case NK_SYMBOL_TRIANGLE_DOWN: - case NK_SYMBOL_TRIANGLE_LEFT: - case NK_SYMBOL_TRIANGLE_RIGHT: { - enum nk_heading heading; - struct nk_vec2 points[3]; - heading = (type == NK_SYMBOL_TRIANGLE_RIGHT) ? NK_RIGHT : - (type == NK_SYMBOL_TRIANGLE_LEFT) ? NK_LEFT: - (type == NK_SYMBOL_TRIANGLE_UP) ? NK_UP: NK_DOWN; - nk_triangle_from_direction(points, content, 0, 0, heading); - nk_fill_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y, - points[2].x, points[2].y, foreground); - } break; - default: - case NK_SYMBOL_NONE: - case NK_SYMBOL_MAX: break; - } -} - -NK_INTERN int -nk_button_behavior(nk_flags *state, struct nk_rect r, - const struct nk_input *i, enum nk_button_behavior behavior) -{ - int ret = 0; - nk_widget_state_reset(state); - if (!i) return 0; - if (nk_input_is_mouse_hovering_rect(i, r)) { - *state = NK_WIDGET_STATE_HOVERED; - if (nk_input_is_mouse_down(i, NK_BUTTON_LEFT)) - *state = NK_WIDGET_STATE_ACTIVE; - if (nk_input_has_mouse_click_in_rect(i, NK_BUTTON_LEFT, r)) { - ret = (behavior != NK_BUTTON_DEFAULT) ? - nk_input_is_mouse_down(i, NK_BUTTON_LEFT): -#ifdef NK_BUTTON_TRIGGER_ON_RELEASE - nk_input_is_mouse_released(i, NK_BUTTON_LEFT); -#else - nk_input_is_mouse_pressed(i, NK_BUTTON_LEFT); -#endif - } - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(i, r)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(i, r)) - *state |= NK_WIDGET_STATE_LEFT; - return ret; -} - -NK_INTERN const struct nk_style_item* -nk_draw_button(struct nk_command_buffer *out, - const struct nk_rect *bounds, nk_flags state, - const struct nk_style_button *style) -{ - const struct nk_style_item *background; - if (state & NK_WIDGET_STATE_HOVER) - background = &style->hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - background = &style->active; - else background = &style->normal; - - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - } else { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } - return background; -} - -NK_INTERN int -nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, - const struct nk_style_button *style, const struct nk_input *in, - enum nk_button_behavior behavior, struct nk_rect *content) -{ - struct nk_rect bounds; - NK_ASSERT(style); - NK_ASSERT(state); - NK_ASSERT(out); - if (!out || !style) - return nk_false; - - /* calculate button content space */ - content->x = r.x + style->padding.x + style->border + style->rounding; - content->y = r.y + style->padding.y + style->border + style->rounding; - content->w = r.w - (2 * style->padding.x + style->border + style->rounding*2); - content->h = r.h - (2 * style->padding.y + style->border + style->rounding*2); - - /* execute button behavior */ - bounds.x = r.x - style->touch_padding.x; - bounds.y = r.y - style->touch_padding.y; - bounds.w = r.w + 2 * style->touch_padding.x; - bounds.h = r.h + 2 * style->touch_padding.y; - return nk_button_behavior(state, bounds, in, behavior); -} - -NK_INTERN void -nk_draw_button_text(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, - const struct nk_style_button *style, const char *txt, int len, - nk_flags text_alignment, const struct nk_user_font *font) -{ - struct nk_text text; - const struct nk_style_item *background; - background = nk_draw_button(out, bounds, state, style); - - /* select correct colors/images */ - if (background->type == NK_STYLE_ITEM_COLOR) - text.background = background->data.color; - else text.background = style->text_background; - if (state & NK_WIDGET_STATE_HOVER) - text.text = style->text_hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - text.text = style->text_active; - else text.text = style->text_normal; - - text.padding = nk_vec2(0,0); - nk_widget_text(out, *content, txt, len, &text, text_alignment, font); -} - -NK_INTERN int -nk_do_button_text(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - const char *string, int len, nk_flags align, enum nk_button_behavior behavior, - const struct nk_style_button *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - struct nk_rect content; - int ret = nk_false; - - NK_ASSERT(state); - NK_ASSERT(style); - NK_ASSERT(out); - NK_ASSERT(string); - NK_ASSERT(font); - if (!out || !style || !font || !string) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_text(out, &bounds, &content, *state, style, string, len, align, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} - -NK_INTERN void -nk_draw_button_symbol(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *content, - nk_flags state, const struct nk_style_button *style, - enum nk_symbol_type type, const struct nk_user_font *font) -{ - struct nk_color sym, bg; - const struct nk_style_item *background; - - /* select correct colors/images */ - background = nk_draw_button(out, bounds, state, style); - if (background->type == NK_STYLE_ITEM_COLOR) - bg = background->data.color; - else bg = style->text_background; - - if (state & NK_WIDGET_STATE_HOVER) - sym = style->text_hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - sym = style->text_active; - else sym = style->text_normal; - nk_draw_symbol(out, type, *content, bg, sym, 1, font); -} - -NK_INTERN int -nk_do_button_symbol(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - enum nk_symbol_type symbol, enum nk_button_behavior behavior, - const struct nk_style_button *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - int ret; - struct nk_rect content; - - NK_ASSERT(state); - NK_ASSERT(style); - NK_ASSERT(font); - NK_ASSERT(out); - if (!out || !style || !font || !state) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_symbol(out, &bounds, &content, *state, style, symbol, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} - -NK_INTERN void -nk_draw_button_image(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *content, - nk_flags state, const struct nk_style_button *style, const struct nk_image *img) -{ - nk_draw_button(out, bounds, state, style); - nk_draw_image(out, *content, img, nk_white); -} - -NK_INTERN int -nk_do_button_image(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - struct nk_image img, enum nk_button_behavior b, - const struct nk_style_button *style, const struct nk_input *in) -{ - int ret; - struct nk_rect content; - - NK_ASSERT(state); - NK_ASSERT(style); - NK_ASSERT(out); - if (!out || !style || !state) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, b, &content); - content.x += style->image_padding.x; - content.y += style->image_padding.y; - content.w -= 2 * style->image_padding.x; - content.h -= 2 * style->image_padding.y; - - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_image(out, &bounds, &content, *state, style, &img); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} - -NK_INTERN void -nk_draw_button_text_symbol(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *label, - const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style, - const char *str, int len, enum nk_symbol_type type, - const struct nk_user_font *font) -{ - struct nk_color sym; - struct nk_text text; - const struct nk_style_item *background; - - /* select correct background colors/images */ - background = nk_draw_button(out, bounds, state, style); - if (background->type == NK_STYLE_ITEM_COLOR) - text.background = background->data.color; - else text.background = style->text_background; - - /* select correct text colors */ - if (state & NK_WIDGET_STATE_HOVER) { - sym = style->text_hover; - text.text = style->text_hover; - } else if (state & NK_WIDGET_STATE_ACTIVED) { - sym = style->text_active; - text.text = style->text_active; - } else { - sym = style->text_normal; - text.text = style->text_normal; - } - - text.padding = nk_vec2(0,0); - nk_draw_symbol(out, type, *symbol, style->text_background, sym, 0, font); - nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font); -} - -NK_INTERN int -nk_do_button_text_symbol(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - enum nk_symbol_type symbol, const char *str, int len, nk_flags align, - enum nk_button_behavior behavior, const struct nk_style_button *style, - const struct nk_user_font *font, const struct nk_input *in) -{ - int ret; - struct nk_rect tri = {0,0,0,0}; - struct nk_rect content; - - NK_ASSERT(style); - NK_ASSERT(out); - NK_ASSERT(font); - if (!out || !style || !font) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - tri.y = content.y + (content.h/2) - font->height/2; - tri.w = font->height; tri.h = font->height; - if (align & NK_TEXT_ALIGN_LEFT) { - tri.x = (content.x + content.w) - (2 * style->padding.x + tri.w); - tri.x = NK_MAX(tri.x, 0); - } else tri.x = content.x + 2 * style->padding.x; - - /* draw button */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_text_symbol(out, &bounds, &content, &tri, - *state, style, str, len, symbol, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} - -NK_INTERN void -nk_draw_button_text_image(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *label, - const struct nk_rect *image, nk_flags state, const struct nk_style_button *style, - const char *str, int len, const struct nk_user_font *font, - const struct nk_image *img) -{ - struct nk_text text; - const struct nk_style_item *background; - background = nk_draw_button(out, bounds, state, style); - - /* select correct colors */ - if (background->type == NK_STYLE_ITEM_COLOR) - text.background = background->data.color; - else text.background = style->text_background; - if (state & NK_WIDGET_STATE_HOVER) - text.text = style->text_hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - text.text = style->text_active; - else text.text = style->text_normal; - - text.padding = nk_vec2(0,0); - nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font); - nk_draw_image(out, *image, img, nk_white); -} - -NK_INTERN int -nk_do_button_text_image(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - struct nk_image img, const char* str, int len, nk_flags align, - enum nk_button_behavior behavior, const struct nk_style_button *style, - const struct nk_user_font *font, const struct nk_input *in) -{ - int ret; - struct nk_rect icon; - struct nk_rect content; - - NK_ASSERT(style); - NK_ASSERT(state); - NK_ASSERT(font); - NK_ASSERT(out); - if (!out || !font || !style || !str) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - icon.y = bounds.y + style->padding.y; - icon.w = icon.h = bounds.h - 2 * style->padding.y; - if (align & NK_TEXT_ALIGN_LEFT) { - icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w); - icon.x = NK_MAX(icon.x, 0); - } else icon.x = bounds.x + 2 * style->padding.x; - - icon.x += style->image_padding.x; - icon.y += style->image_padding.y; - icon.w -= 2 * style->image_padding.x; - icon.h -= 2 * style->image_padding.y; - - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_text_image(out, &bounds, &content, &icon, *state, style, str, len, font, &img); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} - -/* =============================================================== - * - * TOGGLE - * - * ===============================================================*/ -enum nk_toggle_type { - NK_TOGGLE_CHECK, - NK_TOGGLE_OPTION -}; - -NK_INTERN int -nk_toggle_behavior(const struct nk_input *in, struct nk_rect select, - nk_flags *state, int active) -{ - nk_widget_state_reset(state); - if (nk_button_behavior(state, select, in, NK_BUTTON_DEFAULT)) { - *state = NK_WIDGET_STATE_ACTIVE; - active = !active; - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, select)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, select)) - *state |= NK_WIDGET_STATE_LEFT; - return active; -} - -NK_INTERN void -nk_draw_checkbox(struct nk_command_buffer *out, - nk_flags state, const struct nk_style_toggle *style, int active, - const struct nk_rect *label, const struct nk_rect *selector, - const struct nk_rect *cursors, const char *string, int len, - const struct nk_user_font *font) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - struct nk_text text; - - /* select correct colors/images */ - if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_hover; - } else if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_active; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - text.text = style->text_normal; - } - - /* draw background and cursor */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *selector, 0, style->border_color); - nk_fill_rect(out, nk_shrink_rect(*selector, style->border), 0, background->data.color); - } else nk_draw_image(out, *selector, &background->data.image, nk_white); - if (active) { - if (cursor->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, *cursors, &cursor->data.image, nk_white); - else nk_fill_rect(out, *cursors, 0, cursor->data.color); - } - - text.padding.x = 0; - text.padding.y = 0; - text.background = style->text_background; - nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font); -} - -NK_INTERN void -nk_draw_option(struct nk_command_buffer *out, - nk_flags state, const struct nk_style_toggle *style, int active, - const struct nk_rect *label, const struct nk_rect *selector, - const struct nk_rect *cursors, const char *string, int len, - const struct nk_user_font *font) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - struct nk_text text; - - /* select correct colors/images */ - if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_hover; - } else if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_active; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - text.text = style->text_normal; - } - - /* draw background and cursor */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_circle(out, *selector, style->border_color); - nk_fill_circle(out, nk_shrink_rect(*selector, style->border), background->data.color); - } else nk_draw_image(out, *selector, &background->data.image, nk_white); - if (active) { - if (cursor->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, *cursors, &cursor->data.image, nk_white); - else nk_fill_circle(out, *cursors, cursor->data.color); - } - - text.padding.x = 0; - text.padding.y = 0; - text.background = style->text_background; - nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font); -} - -NK_INTERN int -nk_do_toggle(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect r, - int *active, const char *str, int len, enum nk_toggle_type type, - const struct nk_style_toggle *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - int was_active; - struct nk_rect bounds; - struct nk_rect select; - struct nk_rect cursor; - struct nk_rect label; - - NK_ASSERT(style); - NK_ASSERT(out); - NK_ASSERT(font); - if (!out || !style || !font || !active) - return 0; - - r.w = NK_MAX(r.w, font->height + 2 * style->padding.x); - r.h = NK_MAX(r.h, font->height + 2 * style->padding.y); - - /* add additional touch padding for touch screen devices */ - bounds.x = r.x - style->touch_padding.x; - bounds.y = r.y - style->touch_padding.y; - bounds.w = r.w + 2 * style->touch_padding.x; - bounds.h = r.h + 2 * style->touch_padding.y; - - /* calculate the selector space */ - select.w = font->height; - select.h = select.w; - select.y = r.y + r.h/2.0f - select.h/2.0f; - select.x = r.x; - - /* calculate the bounds of the cursor inside the selector */ - cursor.x = select.x + style->padding.x + style->border; - cursor.y = select.y + style->padding.y + style->border; - cursor.w = select.w - (2 * style->padding.x + 2 * style->border); - cursor.h = select.h - (2 * style->padding.y + 2 * style->border); - - /* label behind the selector */ - label.x = select.x + select.w + style->spacing; - label.y = select.y; - label.w = NK_MAX(r.x + r.w, label.x) - label.x; - label.h = select.w; - - /* update selector */ - was_active = *active; - *active = nk_toggle_behavior(in, bounds, state, *active); - - /* draw selector */ - if (style->draw_begin) - style->draw_begin(out, style->userdata); - if (type == NK_TOGGLE_CHECK) { - nk_draw_checkbox(out, *state, style, *active, &label, &select, &cursor, str, len, font); - } else { - nk_draw_option(out, *state, style, *active, &label, &select, &cursor, str, len, font); - } - if (style->draw_end) - style->draw_end(out, style->userdata); - return (was_active != *active); -} - -/* =============================================================== - * - * SELECTABLE - * - * ===============================================================*/ -NK_INTERN void -nk_draw_selectable(struct nk_command_buffer *out, - nk_flags state, const struct nk_style_selectable *style, int active, - const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img, - const char *string, int len, nk_flags align, const struct nk_user_font *font) -{ - const struct nk_style_item *background; - struct nk_text text; - text.padding = style->padding; - - /* select correct colors/images */ - if (!active) { - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->pressed; - text.text = style->text_pressed; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text.text = style->text_hover; - } else { - background = &style->normal; - text.text = style->text_normal; - } - } else { - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->pressed_active; - text.text = style->text_pressed_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover_active; - text.text = style->text_hover_active; - } else { - background = &style->normal_active; - text.text = style->text_normal_active; - } - } - - - /* draw selectable background and text */ - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - text.background = nk_rgba(0,0,0,0); - } else { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - text.background = background->data.color; - } - if (img && icon) nk_draw_image(out, *icon, img, nk_white); - nk_widget_text(out, *bounds, string, len, &text, align, font); -} - -NK_INTERN int -nk_do_selectable(nk_flags *state, struct nk_command_buffer *out, - struct nk_rect bounds, const char *str, int len, nk_flags align, int *value, - const struct nk_style_selectable *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - int old_value; - struct nk_rect touch; - - NK_ASSERT(state); - NK_ASSERT(out); - NK_ASSERT(str); - NK_ASSERT(len); - NK_ASSERT(value); - NK_ASSERT(style); - NK_ASSERT(font); - - if (!state || !out || !str || !len || !value || !style || !font) return 0; - old_value = *value; - - /* remove padding */ - touch.x = bounds.x - style->touch_padding.x; - touch.y = bounds.y - style->touch_padding.y; - touch.w = bounds.w + style->touch_padding.x * 2; - touch.h = bounds.h + style->touch_padding.y * 2; - - /* update button */ - if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT)) - *value = !(*value); - - /* draw selectable */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_selectable(out, *state, style, *value, &bounds, 0,0, str, len, align, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return old_value != *value; -} - -NK_INTERN int -nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out, - struct nk_rect bounds, const char *str, int len, nk_flags align, int *value, - const struct nk_image *img, const struct nk_style_selectable *style, - const struct nk_input *in, const struct nk_user_font *font) -{ - int old_value; - struct nk_rect touch; - struct nk_rect icon; - - NK_ASSERT(state); - NK_ASSERT(out); - NK_ASSERT(str); - NK_ASSERT(len); - NK_ASSERT(value); - NK_ASSERT(style); - NK_ASSERT(font); - - if (!state || !out || !str || !len || !value || !style || !font) return 0; - old_value = *value; - - /* toggle behavior */ - touch.x = bounds.x - style->touch_padding.x; - touch.y = bounds.y - style->touch_padding.y; - touch.w = bounds.w + style->touch_padding.x * 2; - touch.h = bounds.h + style->touch_padding.y * 2; - if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT)) - *value = !(*value); - - icon.y = bounds.y + style->padding.y; - icon.w = icon.h = bounds.h - 2 * style->padding.y; - if (align & NK_TEXT_ALIGN_LEFT) { - icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w); - icon.x = NK_MAX(icon.x, 0); - } else icon.x = bounds.x + 2 * style->padding.x; - - icon.x += style->image_padding.x; - icon.y += style->image_padding.y; - icon.w -= 2 * style->image_padding.x; - icon.h -= 2 * style->image_padding.y; - - /* draw selectable */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_selectable(out, *state, style, *value, &bounds, &icon, img, str, len, align, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return old_value != *value; -} - - -/* =============================================================== - * - * SLIDER - * - * ===============================================================*/ -NK_INTERN float -nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor, - struct nk_rect *visual_cursor, struct nk_input *in, - struct nk_rect bounds, float slider_min, float slider_max, float slider_value, - float slider_step, float slider_steps) -{ - int left_mouse_down; - int left_mouse_click_in_cursor; - - /* check if visual cursor is being dragged */ - nk_widget_state_reset(state); - left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down; - left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, *visual_cursor, nk_true); - - if (left_mouse_down && left_mouse_click_in_cursor) - { - float ratio = 0; - const float d = in->mouse.pos.x - (visual_cursor->x+visual_cursor->w*0.5f); - const float pxstep = bounds.w / slider_steps; - - /* only update value if the next slider step is reached */ - *state = NK_WIDGET_STATE_ACTIVE; - if (NK_ABS(d) >= pxstep) { - const float steps = (float)((int)(NK_ABS(d) / pxstep)); - slider_value += (d > 0) ? (slider_step*steps) : -(slider_step*steps); - slider_value = NK_CLAMP(slider_min, slider_value, slider_max); - ratio = (slider_value - slider_min)/slider_step; - logical_cursor->x = bounds.x + (logical_cursor->w * ratio); - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = logical_cursor->x; - } - } - - /* slider widget state */ - if (nk_input_is_mouse_hovering_rect(in, bounds)) - *state = NK_WIDGET_STATE_HOVERED; - if (*state & NK_WIDGET_STATE_HOVER && - !nk_input_is_mouse_prev_hovering_rect(in, bounds)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, bounds)) - *state |= NK_WIDGET_STATE_LEFT; - return slider_value; -} - -NK_INTERN void -nk_draw_slider(struct nk_command_buffer *out, nk_flags state, - const struct nk_style_slider *style, const struct nk_rect *bounds, - const struct nk_rect *visual_cursor, float min, float value, float max) -{ - struct nk_rect fill; - struct nk_rect bar; - const struct nk_style_item *background; - - /* select correct slider images/colors */ - struct nk_color bar_color; - const struct nk_style_item *cursor; - - NK_UNUSED(min); - NK_UNUSED(max); - NK_UNUSED(value); - - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - bar_color = style->bar_active; - cursor = &style->cursor_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - bar_color = style->bar_hover; - cursor = &style->cursor_hover; - } else { - background = &style->normal; - bar_color = style->bar_normal; - cursor = &style->cursor_normal; - } - - /* calculate slider background bar */ - bar.x = bounds->x; - bar.y = (visual_cursor->y + visual_cursor->h/2) - bounds->h/12; - bar.w = bounds->w; - bar.h = bounds->h/6; - - /* filled background bar style */ - fill.w = (visual_cursor->x + (visual_cursor->w/2.0f)) - bar.x; - fill.x = bar.x; - fill.y = bar.y; - fill.h = bar.h; - - /* draw background */ - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - } else { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } - - /* draw slider bar */ - nk_fill_rect(out, bar, style->rounding, bar_color); - nk_fill_rect(out, fill, style->rounding, style->bar_filled); - - /* draw cursor */ - if (cursor->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, *visual_cursor, &cursor->data.image, nk_white); - else nk_fill_circle(out, *visual_cursor, cursor->data.color); -} - -NK_INTERN float -nk_do_slider(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - float min, float val, float max, float step, - const struct nk_style_slider *style, struct nk_input *in, - const struct nk_user_font *font) -{ - float slider_range; - float slider_min; - float slider_max; - float slider_value; - float slider_steps; - float cursor_offset; - - struct nk_rect visual_cursor; - struct nk_rect logical_cursor; - - NK_ASSERT(style); - NK_ASSERT(out); - if (!out || !style) - return 0; - - /* remove padding from slider bounds */ - bounds.x = bounds.x + style->padding.x; - bounds.y = bounds.y + style->padding.y; - bounds.h = NK_MAX(bounds.h, 2*style->padding.y); - bounds.w = NK_MAX(bounds.w, 2*style->padding.x + style->cursor_size.x); - bounds.w -= 2 * style->padding.x; - bounds.h -= 2 * style->padding.y; - - /* optional buttons */ - if (style->show_buttons) { - nk_flags ws; - struct nk_rect button; - button.y = bounds.y; - button.w = bounds.h; - button.h = bounds.h; - - /* decrement button */ - button.x = bounds.x; - if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, NK_BUTTON_DEFAULT, - &style->dec_button, in, font)) - val -= step; - - /* increment button */ - button.x = (bounds.x + bounds.w) - button.w; - if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, NK_BUTTON_DEFAULT, - &style->inc_button, in, font)) - val += step; - - bounds.x = bounds.x + button.w + style->spacing.x; - bounds.w = bounds.w - (2*button.w + 2*style->spacing.x); - } - - /* remove one cursor size to support visual cursor */ - bounds.x += style->cursor_size.x*0.5f; - bounds.w -= style->cursor_size.x; - - /* make sure the provided values are correct */ - slider_max = NK_MAX(min, max); - slider_min = NK_MIN(min, max); - slider_value = NK_CLAMP(slider_min, val, slider_max); - slider_range = slider_max - slider_min; - slider_steps = slider_range / step; - cursor_offset = (slider_value - slider_min) / step; - - /* calculate cursor - Basically you have two cursors. One for visual representation and interaction - and one for updating the actual cursor value. */ - logical_cursor.h = bounds.h; - logical_cursor.w = bounds.w / slider_steps; - logical_cursor.x = bounds.x + (logical_cursor.w * cursor_offset); - logical_cursor.y = bounds.y; - - visual_cursor.h = style->cursor_size.y; - visual_cursor.w = style->cursor_size.x; - visual_cursor.y = (bounds.y + bounds.h*0.5f) - visual_cursor.h*0.5f; - visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f; - - slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor, - in, bounds, slider_min, slider_max, slider_value, step, slider_steps); - visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f; - - /* draw slider */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_slider(out, *state, style, &bounds, &visual_cursor, slider_min, slider_value, slider_max); - if (style->draw_end) style->draw_end(out, style->userdata); - return slider_value; -} - -/* =============================================================== - * - * PROGRESSBAR - * - * ===============================================================*/ -NK_INTERN nk_size -nk_progress_behavior(nk_flags *state, const struct nk_input *in, - struct nk_rect r, nk_size max, nk_size value, int modifiable) -{ - nk_widget_state_reset(state); - if (in && modifiable && nk_input_is_mouse_hovering_rect(in, r)) { - int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; - int left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, r, nk_true); - - if (left_mouse_down && left_mouse_click_in_cursor) { - float ratio = NK_MAX(0, (float)(in->mouse.pos.x - r.x)) / (float)r.w; - value = (nk_size)NK_MAX(0,((float)max * ratio)); - *state = NK_WIDGET_STATE_ACTIVE; - } else *state = NK_WIDGET_STATE_HOVERED; - } - - /* set progressbar widget state */ - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, r)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, r)) - *state |= NK_WIDGET_STATE_LEFT; - - if (!max) return value; - value = NK_MIN(value, max); - return value; -} - -NK_INTERN void -nk_draw_progress(struct nk_command_buffer *out, nk_flags state, - const struct nk_style_progress *style, const struct nk_rect *bounds, - const struct nk_rect *scursor, nk_size value, nk_size max) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - - NK_UNUSED(max); - NK_UNUSED(value); - - /* select correct colors/images to draw */ - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - cursor = &style->cursor_active; - } else if (state & NK_WIDGET_STATE_HOVER){ - background = &style->hover; - cursor = &style->cursor_hover; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - } - - /* draw background */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } else nk_draw_image(out, *bounds, &background->data.image, nk_white); - - /* draw cursor */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *scursor, style->rounding, cursor->data.color); - nk_stroke_rect(out, *scursor, style->rounding, style->border, style->border_color); - } else nk_draw_image(out, *scursor, &cursor->data.image, nk_white); -} - -NK_INTERN nk_size -nk_do_progress(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - nk_size value, nk_size max, int modifiable, - const struct nk_style_progress *style, const struct nk_input *in) -{ - float prog_scale; - nk_size prog_value; - struct nk_rect cursor; - - NK_ASSERT(style); - NK_ASSERT(out); - if (!out || !style) return 0; - - /* calculate progressbar cursor */ - cursor.w = NK_MAX(bounds.w, 2 * style->padding.x + 2 * style->border); - cursor.h = NK_MAX(bounds.h, 2 * style->padding.y + 2 * style->border); - cursor = nk_pad_rect(bounds, nk_vec2(style->padding.x + style->border, style->padding.y + style->border)); - prog_scale = (float)value / (float)max; - cursor.w = (bounds.w - 2) * prog_scale; - - /* update progressbar */ - prog_value = NK_MIN(value, max); - prog_value = nk_progress_behavior(state, in, bounds, max, prog_value, modifiable); - - /* draw progressbar */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_progress(out, *state, style, &bounds, &cursor, value, max); - if (style->draw_end) style->draw_end(out, style->userdata); - return prog_value; -} - -/* =============================================================== - * - * SCROLLBAR - * - * ===============================================================*/ -NK_INTERN float -nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, - int has_scrolling, const struct nk_rect *scroll, - const struct nk_rect *cursor, const struct nk_rect *empty0, - const struct nk_rect *empty1, float scroll_offset, - float target, float scroll_step, enum nk_orientation o) -{ - nk_flags ws = 0; - int left_mouse_down; - int left_mouse_click_in_cursor; - float scroll_delta; - - nk_widget_state_reset(state); - if (!in) return scroll_offset; - - left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; - left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, *cursor, nk_true); - if (nk_input_is_mouse_hovering_rect(in, *scroll)) - *state = NK_WIDGET_STATE_HOVERED; - - scroll_delta = (o == NK_VERTICAL) ? in->mouse.scroll_delta.y: in->mouse.scroll_delta.x; - if (left_mouse_down && left_mouse_click_in_cursor) { - /* update cursor by mouse dragging */ - float pixel, delta; - *state = NK_WIDGET_STATE_ACTIVE; - if (o == NK_VERTICAL) { - float cursor_y; - pixel = in->mouse.delta.y; - delta = (pixel / scroll->h) * target; - scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->h); - cursor_y = scroll->y + ((scroll_offset/target) * scroll->h); - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = cursor_y + cursor->h/2.0f; - } else { - float cursor_x; - pixel = in->mouse.delta.x; - delta = (pixel / scroll->w) * target; - scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->w); - cursor_x = scroll->x + ((scroll_offset/target) * scroll->w); - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor_x + cursor->w/2.0f; - } - } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_UP) && o == NK_VERTICAL && has_scrolling)|| - nk_button_behavior(&ws, *empty0, in, NK_BUTTON_DEFAULT)) { - /* scroll page up by click on empty space or shortcut */ - if (o == NK_VERTICAL) - scroll_offset = NK_MAX(0, scroll_offset - scroll->h); - else scroll_offset = NK_MAX(0, scroll_offset - scroll->w); - } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_DOWN) && o == NK_VERTICAL && has_scrolling) || - nk_button_behavior(&ws, *empty1, in, NK_BUTTON_DEFAULT)) { - /* scroll page down by click on empty space or shortcut */ - if (o == NK_VERTICAL) - scroll_offset = NK_MIN(scroll_offset + scroll->h, target - scroll->h); - else scroll_offset = NK_MIN(scroll_offset + scroll->w, target - scroll->w); - } else if (has_scrolling) { - if ((scroll_delta < 0 || (scroll_delta > 0))) { - /* update cursor by mouse scrolling */ - scroll_offset = scroll_offset + scroll_step * (-scroll_delta); - if (o == NK_VERTICAL) - scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->h); - else scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->w); - } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_START)) { - /* update cursor to the beginning */ - if (o == NK_VERTICAL) scroll_offset = 0; - } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_END)) { - /* update cursor to the end */ - if (o == NK_VERTICAL) scroll_offset = target - scroll->h; - } - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *scroll)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, *scroll)) - *state |= NK_WIDGET_STATE_LEFT; - return scroll_offset; -} - -NK_INTERN void -nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state, - const struct nk_style_scrollbar *style, const struct nk_rect *bounds, - const struct nk_rect *scroll) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - - /* select correct colors/images to draw */ - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - cursor = &style->cursor_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - cursor = &style->cursor_hover; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - } - - /* draw background */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } else { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - } - - /* draw cursor */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *scroll, style->rounding_cursor, cursor->data.color); - nk_stroke_rect(out, *scroll, style->rounding_cursor, style->border_cursor, style->cursor_border_color); - } else nk_draw_image(out, *scroll, &cursor->data.image, nk_white); -} - -NK_INTERN float -nk_do_scrollbarv(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, - float offset, float target, float step, float button_pixel_inc, - const struct nk_style_scrollbar *style, struct nk_input *in, - const struct nk_user_font *font) -{ - struct nk_rect empty_north; - struct nk_rect empty_south; - struct nk_rect cursor; - - float scroll_step; - float scroll_offset; - float scroll_off; - float scroll_ratio; - - NK_ASSERT(out); - NK_ASSERT(style); - NK_ASSERT(state); - if (!out || !style) return 0; - - scroll.w = NK_MAX(scroll.w, 1); - scroll.h = NK_MAX(scroll.h, 0); - if (target <= scroll.h) return 0; - - /* optional scrollbar buttons */ - if (style->show_buttons) { - nk_flags ws; - float scroll_h; - struct nk_rect button; - - button.x = scroll.x; - button.w = scroll.w; - button.h = scroll.w; - - scroll_h = NK_MAX(scroll.h - 2 * button.h,0); - scroll_step = NK_MIN(step, button_pixel_inc); - - /* decrement button */ - button.y = scroll.y; - if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, - NK_BUTTON_REPEATER, &style->dec_button, in, font)) - offset = offset - scroll_step; - - /* increment button */ - button.y = scroll.y + scroll.h - button.h; - if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, - NK_BUTTON_REPEATER, &style->inc_button, in, font)) - offset = offset + scroll_step; - - scroll.y = scroll.y + button.h; - scroll.h = scroll_h; - } - - /* calculate scrollbar constants */ - scroll_step = NK_MIN(step, scroll.h); - scroll_offset = NK_CLAMP(0, offset, target - scroll.h); - scroll_ratio = scroll.h / target; - scroll_off = scroll_offset / target; - - /* calculate scrollbar cursor bounds */ - cursor.h = NK_MAX((scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y), 0); - cursor.y = scroll.y + (scroll_off * scroll.h) + style->border + style->padding.y; - cursor.w = scroll.w - (2 * style->border + 2 * style->padding.x); - cursor.x = scroll.x + style->border + style->padding.x; - - /* calculate empty space around cursor */ - empty_north.x = scroll.x; - empty_north.y = scroll.y; - empty_north.w = scroll.w; - empty_north.h = NK_MAX(cursor.y - scroll.y, 0); - - empty_south.x = scroll.x; - empty_south.y = cursor.y + cursor.h; - empty_south.w = scroll.w; - empty_south.h = NK_MAX((scroll.y + scroll.h) - (cursor.y + cursor.h), 0); - - /* update scrollbar */ - scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor, - &empty_north, &empty_south, scroll_offset, target, scroll_step, NK_VERTICAL); - scroll_off = scroll_offset / target; - cursor.y = scroll.y + (scroll_off * scroll.h) + style->border_cursor + style->padding.y; - - /* draw scrollbar */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_scrollbar(out, *state, style, &scroll, &cursor); - if (style->draw_end) style->draw_end(out, style->userdata); - return scroll_offset; -} - -NK_INTERN float -nk_do_scrollbarh(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, - float offset, float target, float step, float button_pixel_inc, - const struct nk_style_scrollbar *style, struct nk_input *in, - const struct nk_user_font *font) -{ - struct nk_rect cursor; - struct nk_rect empty_west; - struct nk_rect empty_east; - - float scroll_step; - float scroll_offset; - float scroll_off; - float scroll_ratio; - - NK_ASSERT(out); - NK_ASSERT(style); - if (!out || !style) return 0; - - /* scrollbar background */ - scroll.h = NK_MAX(scroll.h, 1); - scroll.w = NK_MAX(scroll.w, 2 * scroll.h); - if (target <= scroll.w) return 0; - - /* optional scrollbar buttons */ - if (style->show_buttons) { - nk_flags ws; - float scroll_w; - struct nk_rect button; - button.y = scroll.y; - button.w = scroll.h; - button.h = scroll.h; - - scroll_w = scroll.w - 2 * button.w; - scroll_step = NK_MIN(step, button_pixel_inc); - - /* decrement button */ - button.x = scroll.x; - if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, - NK_BUTTON_REPEATER, &style->dec_button, in, font)) - offset = offset - scroll_step; - - /* increment button */ - button.x = scroll.x + scroll.w - button.w; - if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, - NK_BUTTON_REPEATER, &style->inc_button, in, font)) - offset = offset + scroll_step; - - scroll.x = scroll.x + button.w; - scroll.w = scroll_w; - } - - /* calculate scrollbar constants */ - scroll_step = NK_MIN(step, scroll.w); - scroll_offset = NK_CLAMP(0, offset, target - scroll.w); - scroll_ratio = scroll.w / target; - scroll_off = scroll_offset / target; - - /* calculate cursor bounds */ - cursor.w = (scroll_ratio * scroll.w) - (2*style->border + 2*style->padding.x); - cursor.x = scroll.x + (scroll_off * scroll.w) + style->border + style->padding.x; - cursor.h = scroll.h - (2 * style->border + 2 * style->padding.y); - cursor.y = scroll.y + style->border + style->padding.y; - - /* calculate empty space around cursor */ - empty_west.x = scroll.x; - empty_west.y = scroll.y; - empty_west.w = cursor.x - scroll.x; - empty_west.h = scroll.h; - - empty_east.x = cursor.x + cursor.w; - empty_east.y = scroll.y; - empty_east.w = (scroll.x + scroll.w) - (cursor.x + cursor.w); - empty_east.h = scroll.h; - - /* update scrollbar */ - scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor, - &empty_west, &empty_east, scroll_offset, target, scroll_step, NK_HORIZONTAL); - scroll_off = scroll_offset / target; - cursor.x = scroll.x + (scroll_off * scroll.w); - - /* draw scrollbar */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_scrollbar(out, *state, style, &scroll, &cursor); - if (style->draw_end) style->draw_end(out, style->userdata); - return scroll_offset; -} - -/* =============================================================== - * - * FILTER - * - * ===============================================================*/ -NK_API int nk_filter_default(const struct nk_text_edit *box, nk_rune unicode) -{(void)unicode;NK_UNUSED(box);return nk_true;} - -NK_API int -nk_filter_ascii(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if (unicode > 128) return nk_false; - else return nk_true; -} - -NK_API int -nk_filter_float(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-') - return nk_false; - else return nk_true; -} - -NK_API int -nk_filter_decimal(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if ((unicode < '0' || unicode > '9') && unicode != '-') - return nk_false; - else return nk_true; -} - -NK_API int -nk_filter_hex(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if ((unicode < '0' || unicode > '9') && - (unicode < 'a' || unicode > 'f') && - (unicode < 'A' || unicode > 'F')) - return nk_false; - else return nk_true; -} - -NK_API int -nk_filter_oct(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if (unicode < '0' || unicode > '7') - return nk_false; - else return nk_true; -} - -NK_API int -nk_filter_binary(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if (unicode != '0' && unicode != '1') - return nk_false; - else return nk_true; -} - -/* =============================================================== - * - * EDIT - * - * ===============================================================*/ -NK_INTERN void -nk_edit_draw_text(struct nk_command_buffer *out, - const struct nk_style_edit *style, float pos_x, float pos_y, - float x_offset, const char *text, int byte_len, float row_height, - const struct nk_user_font *font, struct nk_color background, - struct nk_color foreground, int is_selected) -{ - NK_ASSERT(out); - NK_ASSERT(font); - NK_ASSERT(style); - if (!text || !byte_len || !out || !style) return; - - {int glyph_len = 0; - nk_rune unicode = 0; - int text_len = 0; - float line_width = 0; - float glyph_width; - const char *line = text; - float line_offset = 0; - int line_count = 0; - - struct nk_text txt; - txt.padding = nk_vec2(0,0); - txt.background = background; - txt.text = foreground; - - glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len); - if (!glyph_len) return; - while ((text_len < byte_len) && glyph_len) - { - if (unicode == '\n') { - /* new line sepeator so draw previous line */ - struct nk_rect label; - label.y = pos_y + line_offset; - label.h = row_height; - label.w = line_width; - label.x = pos_x; - if (!line_count) - label.x += x_offset; - - if (is_selected) /* selection needs to draw different background color */ - nk_fill_rect(out, label, 0, background); - nk_widget_text(out, label, line, (int)((text + text_len) - line), - &txt, NK_TEXT_CENTERED, font); - - text_len++; - line_count++; - line_width = 0; - line = text + text_len; - line_offset += row_height; - glyph_len = nk_utf_decode(text + text_len, &unicode, (int)(byte_len-text_len)); - continue; - } - if (unicode == '\r') { - text_len++; - glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len); - continue; - } - glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len); - line_width += (float)glyph_width; - text_len += glyph_len; - glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len); - continue; - } - if (line_width > 0) { - /* draw last line */ - struct nk_rect label; - label.y = pos_y + line_offset; - label.h = row_height; - label.w = line_width; - label.x = pos_x; - if (!line_count) - label.x += x_offset; - - if (is_selected) - nk_fill_rect(out, label, 0, background); - nk_widget_text(out, label, line, (int)((text + text_len) - line), - &txt, NK_TEXT_LEFT, font); - }} -} - -NK_INTERN nk_flags -nk_do_edit(nk_flags *state, struct nk_command_buffer *out, - struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter, - struct nk_text_edit *edit, const struct nk_style_edit *style, - struct nk_input *in, const struct nk_user_font *font) -{ - struct nk_rect area; - nk_flags ret = 0; - float row_height; - char prev_state = 0; - char is_hovered = 0; - char select_all = 0; - char cursor_follow = 0; - struct nk_rect old_clip; - struct nk_rect clip; - - NK_ASSERT(state); - NK_ASSERT(out); - NK_ASSERT(style); - if (!state || !out || !style) - return ret; - - /* visible text area calculation */ - area.x = bounds.x + style->padding.x + style->border; - area.y = bounds.y + style->padding.y + style->border; - area.w = bounds.w - (2.0f * style->padding.x + 2 * style->border); - area.h = bounds.h - (2.0f * style->padding.y + 2 * style->border); - if (flags & NK_EDIT_MULTILINE) - area.w = NK_MAX(0, area.w - style->scrollbar_size.x); - row_height = (flags & NK_EDIT_MULTILINE)? font->height + style->row_padding: area.h; - - /* calculate clipping rectangle */ - old_clip = out->clip; - nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h); - - /* update edit state */ - prev_state = (char)edit->active; - is_hovered = (char)nk_input_is_mouse_hovering_rect(in, bounds); - if (in && in->mouse.buttons[NK_BUTTON_LEFT].clicked && in->mouse.buttons[NK_BUTTON_LEFT].down) { - edit->active = NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, - bounds.x, bounds.y, bounds.w, bounds.h); - } - - /* (de)activate text editor */ - if (!prev_state && edit->active) { - const enum nk_text_edit_type type = (flags & NK_EDIT_MULTILINE) ? - NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE; - nk_textedit_clear_state(edit, type, filter); - if (flags & NK_EDIT_ALWAYS_INSERT_MODE) - edit->mode = NK_TEXT_EDIT_MODE_INSERT; - if (flags & NK_EDIT_AUTO_SELECT) - select_all = nk_true; - if (flags & NK_EDIT_GOTO_END_ON_ACTIVATE) { - edit->cursor = edit->string.len; - in = 0; - } - } else if (!edit->active) edit->mode = NK_TEXT_EDIT_MODE_VIEW; - if (flags & NK_EDIT_READ_ONLY) - edit->mode = NK_TEXT_EDIT_MODE_VIEW; - - ret = (edit->active) ? NK_EDIT_ACTIVE: NK_EDIT_INACTIVE; - if (prev_state != edit->active) - ret |= (edit->active) ? NK_EDIT_ACTIVATED: NK_EDIT_DEACTIVATED; - - /* handle user input */ - if (edit->active && in) - { - int shift_mod = in->keyboard.keys[NK_KEY_SHIFT].down; - const float mouse_x = (in->mouse.pos.x - area.x) + edit->scrollbar.x; - const float mouse_y = (in->mouse.pos.y - area.y) + edit->scrollbar.y; - - /* mouse click handler */ - is_hovered = (char)nk_input_is_mouse_hovering_rect(in, area); - if (select_all) { - nk_textedit_select_all(edit); - } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down && - in->mouse.buttons[NK_BUTTON_LEFT].clicked) { - nk_textedit_click(edit, mouse_x, mouse_y, font, row_height); - } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down && - (in->mouse.delta.x != 0.0f || in->mouse.delta.y != 0.0f)) { - nk_textedit_drag(edit, mouse_x, mouse_y, font, row_height); - cursor_follow = nk_true; - } else if (is_hovered && in->mouse.buttons[NK_BUTTON_RIGHT].clicked && - in->mouse.buttons[NK_BUTTON_RIGHT].down) { - nk_textedit_key(edit, NK_KEY_TEXT_WORD_LEFT, nk_false, font, row_height); - nk_textedit_key(edit, NK_KEY_TEXT_WORD_RIGHT, nk_true, font, row_height); - cursor_follow = nk_true; - } - - {int i; /* keyboard input */ - int old_mode = edit->mode; - for (i = 0; i < NK_KEY_MAX; ++i) { - if (i == NK_KEY_ENTER || i == NK_KEY_TAB) continue; /* special case */ - if (nk_input_is_key_pressed(in, (enum nk_keys)i)) { - nk_textedit_key(edit, (enum nk_keys)i, shift_mod, font, row_height); - cursor_follow = nk_true; - } - } - if (old_mode != edit->mode) { - in->keyboard.text_len = 0; - }} - - /* text input */ - edit->filter = filter; - if (in->keyboard.text_len) { - nk_textedit_text(edit, in->keyboard.text, in->keyboard.text_len); - cursor_follow = nk_true; - in->keyboard.text_len = 0; - } - - /* enter key handler */ - if (nk_input_is_key_pressed(in, NK_KEY_ENTER)) { - cursor_follow = nk_true; - if (flags & NK_EDIT_CTRL_ENTER_NEWLINE && shift_mod) - nk_textedit_text(edit, "\n", 1); - else if (flags & NK_EDIT_SIG_ENTER) - ret |= NK_EDIT_COMMITED; - else nk_textedit_text(edit, "\n", 1); - } - - /* cut & copy handler */ - {int copy= nk_input_is_key_pressed(in, NK_KEY_COPY); - int cut = nk_input_is_key_pressed(in, NK_KEY_CUT); - if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD)) - { - int glyph_len; - nk_rune unicode; - const char *text; - int b = edit->select_start; - int e = edit->select_end; - - int begin = NK_MIN(b, e); - int end = NK_MAX(b, e); - text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len); - if (edit->clip.copy) - edit->clip.copy(edit->clip.userdata, text, end - begin); - if (cut && !(flags & NK_EDIT_READ_ONLY)){ - nk_textedit_cut(edit); - cursor_follow = nk_true; - } - }} - - /* paste handler */ - {int paste = nk_input_is_key_pressed(in, NK_KEY_PASTE); - if (paste && (flags & NK_EDIT_CLIPBOARD) && edit->clip.paste) { - edit->clip.paste(edit->clip.userdata, edit); - cursor_follow = nk_true; - }} - - /* tab handler */ - {int tab = nk_input_is_key_pressed(in, NK_KEY_TAB); - if (tab && (flags & NK_EDIT_ALLOW_TAB)) { - nk_textedit_text(edit, " ", 4); - cursor_follow = nk_true; - }} - } - - /* set widget state */ - if (edit->active) - *state = NK_WIDGET_STATE_ACTIVE; - else nk_widget_state_reset(state); - - if (is_hovered) - *state |= NK_WIDGET_STATE_HOVERED; - - /* DRAW EDIT */ - {const char *text = nk_str_get_const(&edit->string); - int len = nk_str_len_char(&edit->string); - - {/* select background colors/images */ - const struct nk_style_item *background; - if (*state & NK_WIDGET_STATE_ACTIVED) - background = &style->active; - else if (*state & NK_WIDGET_STATE_HOVER) - background = &style->hover; - else background = &style->normal; - - /* draw background frame */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_stroke_rect(out, bounds, style->rounding, style->border, style->border_color); - nk_fill_rect(out, bounds, style->rounding, background->data.color); - } else nk_draw_image(out, bounds, &background->data.image, nk_white);} - - area.w = NK_MAX(0, area.w - style->cursor_size); - if (edit->active) - { - int total_lines = 1; - struct nk_vec2 text_size = nk_vec2(0,0); - - /* text pointer positions */ - const char *cursor_ptr = 0; - const char *select_begin_ptr = 0; - const char *select_end_ptr = 0; - - /* 2D pixel positions */ - struct nk_vec2 cursor_pos = nk_vec2(0,0); - struct nk_vec2 selection_offset_start = nk_vec2(0,0); - struct nk_vec2 selection_offset_end = nk_vec2(0,0); - - int selection_begin = NK_MIN(edit->select_start, edit->select_end); - int selection_end = NK_MAX(edit->select_start, edit->select_end); - - /* calculate total line count + total space + cursor/selection position */ - float line_width = 0.0f; - if (text && len) - { - /* utf8 encoding */ - float glyph_width; - int glyph_len = 0; - nk_rune unicode = 0; - int text_len = 0; - int glyphs = 0; - int row_begin = 0; - - glyph_len = nk_utf_decode(text, &unicode, len); - glyph_width = font->width(font->userdata, font->height, text, glyph_len); - line_width = 0; - - /* iterate all lines */ - while ((text_len < len) && glyph_len) - { - /* set cursor 2D position and line */ - if (!cursor_ptr && glyphs == edit->cursor) - { - int glyph_offset; - struct nk_vec2 out_offset; - struct nk_vec2 row_size; - const char *remaining; - - /* calculate 2d position */ - cursor_pos.y = (float)(total_lines-1) * row_height; - row_size = nk_text_calculate_text_bounds(font, text+row_begin, - text_len-row_begin, row_height, &remaining, - &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); - cursor_pos.x = row_size.x; - cursor_ptr = text + text_len; - } - - /* set start selection 2D position and line */ - if (!select_begin_ptr && edit->select_start != edit->select_end && - glyphs == selection_begin) - { - int glyph_offset; - struct nk_vec2 out_offset; - struct nk_vec2 row_size; - const char *remaining; - - /* calculate 2d position */ - selection_offset_start.y = (float)(NK_MAX(total_lines-1,0)) * row_height; - row_size = nk_text_calculate_text_bounds(font, text+row_begin, - text_len-row_begin, row_height, &remaining, - &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); - selection_offset_start.x = row_size.x; - select_begin_ptr = text + text_len; - } - - /* set end selection 2D position and line */ - if (!select_end_ptr && edit->select_start != edit->select_end && - glyphs == selection_end) - { - int glyph_offset; - struct nk_vec2 out_offset; - struct nk_vec2 row_size; - const char *remaining; - - /* calculate 2d position */ - selection_offset_end.y = (float)(total_lines-1) * row_height; - row_size = nk_text_calculate_text_bounds(font, text+row_begin, - text_len-row_begin, row_height, &remaining, - &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); - selection_offset_end.x = row_size.x; - select_end_ptr = text + text_len; - } - if (unicode == '\n') { - text_size.x = NK_MAX(text_size.x, line_width); - total_lines++; - line_width = 0; - text_len++; - glyphs++; - row_begin = text_len; - glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len); - glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len); - continue; - } - - glyphs++; - text_len += glyph_len; - line_width += (float)glyph_width; - - glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len); - glyph_width = font->width(font->userdata, font->height, - text+text_len, glyph_len); - continue; - } - text_size.y = (float)total_lines * row_height; - - /* handle case when cursor is at end of text buffer */ - if (!cursor_ptr && edit->cursor == edit->string.len) { - cursor_pos.x = line_width; - cursor_pos.y = text_size.y - row_height; - } - } - { - /* scrollbar */ - if (cursor_follow) - { - /* update scrollbar to follow cursor */ - if (!(flags & NK_EDIT_NO_HORIZONTAL_SCROLL)) { - /* horizontal scroll */ - const float scroll_increment = area.w * 0.25f; - if (cursor_pos.x < edit->scrollbar.x) - edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - scroll_increment); - if (cursor_pos.x >= edit->scrollbar.x + area.w) - edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x); - } else edit->scrollbar.x = 0; - - if (flags & NK_EDIT_MULTILINE) { - /* vertical scroll */ - if (cursor_pos.y < edit->scrollbar.y) - edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y - row_height); - if (cursor_pos.y >= edit->scrollbar.y + area.h) - edit->scrollbar.y = edit->scrollbar.y + row_height; - } else edit->scrollbar.y = 0; - } - - /* scrollbar widget */ - if (flags & NK_EDIT_MULTILINE) - { - nk_flags ws; - struct nk_rect scroll; - float scroll_target; - float scroll_offset; - float scroll_step; - float scroll_inc; - - scroll = area; - scroll.x = (bounds.x + bounds.w - style->border) - style->scrollbar_size.x; - scroll.w = style->scrollbar_size.x; - - scroll_offset = edit->scrollbar.y; - scroll_step = scroll.h * 0.10f; - scroll_inc = scroll.h * 0.01f; - scroll_target = text_size.y; - edit->scrollbar.y = nk_do_scrollbarv(&ws, out, scroll, 0, - scroll_offset, scroll_target, scroll_step, scroll_inc, - &style->scrollbar, in, font); - } - } - - /* draw text */ - {struct nk_color background_color; - struct nk_color text_color; - struct nk_color sel_background_color; - struct nk_color sel_text_color; - struct nk_color cursor_color; - struct nk_color cursor_text_color; - const struct nk_style_item *background; - nk_push_scissor(out, clip); - - /* select correct colors to draw */ - if (*state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - text_color = style->text_active; - sel_text_color = style->selected_text_hover; - sel_background_color = style->selected_hover; - cursor_color = style->cursor_hover; - cursor_text_color = style->cursor_text_hover; - } else if (*state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text_color = style->text_hover; - sel_text_color = style->selected_text_hover; - sel_background_color = style->selected_hover; - cursor_text_color = style->cursor_text_hover; - cursor_color = style->cursor_hover; - } else { - background = &style->normal; - text_color = style->text_normal; - sel_text_color = style->selected_text_normal; - sel_background_color = style->selected_normal; - cursor_color = style->cursor_normal; - cursor_text_color = style->cursor_text_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) - background_color = nk_rgba(0,0,0,0); - else background_color = background->data.color; - - - if (edit->select_start == edit->select_end) { - /* no selection so just draw the complete text */ - const char *begin = nk_str_get_const(&edit->string); - int l = nk_str_len_char(&edit->string); - nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, - area.y - edit->scrollbar.y, 0, begin, l, row_height, font, - background_color, text_color, nk_false); - } else { - /* edit has selection so draw 1-3 text chunks */ - if (edit->select_start != edit->select_end && selection_begin > 0){ - /* draw unselected text before selection */ - const char *begin = nk_str_get_const(&edit->string); - NK_ASSERT(select_begin_ptr); - nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, - area.y - edit->scrollbar.y, 0, begin, (int)(select_begin_ptr - begin), - row_height, font, background_color, text_color, nk_false); - } - if (edit->select_start != edit->select_end) { - /* draw selected text */ - NK_ASSERT(select_begin_ptr); - if (!select_end_ptr) { - const char *begin = nk_str_get_const(&edit->string); - select_end_ptr = begin + nk_str_len_char(&edit->string); - } - nk_edit_draw_text(out, style, - area.x - edit->scrollbar.x, - area.y + selection_offset_start.y - edit->scrollbar.y, - selection_offset_start.x, - select_begin_ptr, (int)(select_end_ptr - select_begin_ptr), - row_height, font, sel_background_color, sel_text_color, nk_true); - } - if ((edit->select_start != edit->select_end && - selection_end < edit->string.len)) - { - /* draw unselected text after selected text */ - const char *begin = select_end_ptr; - const char *end = nk_str_get_const(&edit->string) + - nk_str_len_char(&edit->string); - NK_ASSERT(select_end_ptr); - nk_edit_draw_text(out, style, - area.x - edit->scrollbar.x, - area.y + selection_offset_end.y - edit->scrollbar.y, - selection_offset_end.x, - begin, (int)(end - begin), row_height, font, - background_color, text_color, nk_true); - } - } - - /* cursor */ - if (edit->select_start == edit->select_end) - { - if (edit->cursor >= nk_str_len(&edit->string) || - (cursor_ptr && *cursor_ptr == '\n')) { - /* draw cursor at end of line */ - struct nk_rect cursor; - cursor.w = style->cursor_size; - cursor.h = font->height; - cursor.x = area.x + cursor_pos.x - edit->scrollbar.x; - cursor.y = area.y + cursor_pos.y + row_height/2.0f - cursor.h/2.0f; - cursor.y -= edit->scrollbar.y; - nk_fill_rect(out, cursor, 0, cursor_color); - } else { - /* draw cursor inside text */ - int glyph_len; - struct nk_rect label; - struct nk_text txt; - - nk_rune unicode; - NK_ASSERT(cursor_ptr); - glyph_len = nk_utf_decode(cursor_ptr, &unicode, 4); - - label.x = area.x + cursor_pos.x - edit->scrollbar.x; - label.y = area.y + cursor_pos.y - edit->scrollbar.y; - label.w = font->width(font->userdata, font->height, cursor_ptr, glyph_len); - label.h = row_height; - - txt.padding = nk_vec2(0,0); - txt.background = cursor_color;; - txt.text = cursor_text_color; - nk_fill_rect(out, label, 0, cursor_color); - nk_widget_text(out, label, cursor_ptr, glyph_len, &txt, NK_TEXT_LEFT, font); - } - }} - } else { - /* not active so just draw text */ - int l = nk_str_len_char(&edit->string); - const char *begin = nk_str_get_const(&edit->string); - - const struct nk_style_item *background; - struct nk_color background_color; - struct nk_color text_color; - nk_push_scissor(out, clip); - if (*state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - text_color = style->text_active; - } else if (*state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text_color = style->text_hover; - } else { - background = &style->normal; - text_color = style->text_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) - background_color = nk_rgba(0,0,0,0); - else background_color = background->data.color; - nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, - area.y - edit->scrollbar.y, 0, begin, l, row_height, font, - background_color, text_color, nk_false); - } - nk_push_scissor(out, old_clip);} - return ret; -} - -/* =============================================================== - * - * PROPERTY - * - * ===============================================================*/ -enum nk_property_status { - NK_PROPERTY_DEFAULT, - NK_PROPERTY_EDIT, - NK_PROPERTY_DRAG -}; -enum nk_property_filter { - NK_FILTER_INT, - NK_FILTER_FLOAT -}; -enum nk_property_kind { - NK_PROPERTY_INT, - NK_PROPERTY_FLOAT, - NK_PROPERTY_DOUBLE -}; -union nk_property { - int i; - float f; - double d; -}; -struct nk_property_variant { - enum nk_property_kind kind; - union nk_property value; - union nk_property min_value; - union nk_property max_value; - union nk_property step; -}; - -NK_INTERN void -nk_drag_behavior(nk_flags *state, const struct nk_input *in, - struct nk_rect drag, struct nk_property_variant *variant, - float inc_per_pixel) -{ - int left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down; - int left_mouse_click_in_cursor = in && - nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, drag, nk_true); - - nk_widget_state_reset(state); - if (nk_input_is_mouse_hovering_rect(in, drag)) - *state = NK_WIDGET_STATE_HOVERED; - - if (left_mouse_down && left_mouse_click_in_cursor) { - float delta, pixels; - pixels = in->mouse.delta.x; - delta = pixels * inc_per_pixel; - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = variant->value.i + (int)delta; - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i); - break; - case NK_PROPERTY_FLOAT: - variant->value.f = variant->value.f + (float)delta; - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f); - break; - case NK_PROPERTY_DOUBLE: - variant->value.d = variant->value.d + (double)delta; - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); - break; - } - *state = NK_WIDGET_STATE_ACTIVE; - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, drag)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, drag)) - *state |= NK_WIDGET_STATE_LEFT; -} - -NK_INTERN void -nk_property_behavior(nk_flags *ws, const struct nk_input *in, - struct nk_rect property, struct nk_rect label, struct nk_rect edit, - struct nk_rect empty, int *state, struct nk_property_variant *variant, - float inc_per_pixel) -{ - if (in && *state == NK_PROPERTY_DEFAULT) { - if (nk_button_behavior(ws, edit, in, NK_BUTTON_DEFAULT)) - *state = NK_PROPERTY_EDIT; - else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, label, nk_true)) - *state = NK_PROPERTY_DRAG; - else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, empty, nk_true)) - *state = NK_PROPERTY_DRAG; - } - if (*state == NK_PROPERTY_DRAG) { - nk_drag_behavior(ws, in, property, variant, inc_per_pixel); - if (!(*ws & NK_WIDGET_STATE_ACTIVED)) *state = NK_PROPERTY_DEFAULT; - } -} - -NK_INTERN void -nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style, - const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state, - const char *name, int len, const struct nk_user_font *font) -{ - struct nk_text text; - const struct nk_style_item *background; - - /* select correct background and text color */ - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - text.text = style->label_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text.text = style->label_hover; - } else { - background = &style->normal; - text.text = style->label_normal; - } - - /* draw background */ - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - text.background = nk_rgba(0,0,0,0); - } else { - text.background = background->data.color; - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, background->data.color); - } - - /* draw label */ - text.padding = nk_vec2(0,0); - nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font); -} - -NK_INTERN void -nk_do_property(nk_flags *ws, - struct nk_command_buffer *out, struct nk_rect property, - const char *name, struct nk_property_variant *variant, - float inc_per_pixel, char *buffer, int *len, - int *state, int *cursor, int *select_begin, int *select_end, - const struct nk_style_property *style, - enum nk_property_filter filter, struct nk_input *in, - const struct nk_user_font *font, struct nk_text_edit *text_edit, - enum nk_button_behavior behavior) -{ - const nk_plugin_filter filters[] = { - nk_filter_decimal, - nk_filter_float - }; - int active, old; - int num_len, name_len; - char string[NK_MAX_NUMBER_BUFFER]; - float size; - - char *dst = 0; - int *length; - - struct nk_rect left; - struct nk_rect right; - struct nk_rect label; - struct nk_rect edit; - struct nk_rect empty; - - /* left decrement button */ - left.h = font->height/2; - left.w = left.h; - left.x = property.x + style->border + style->padding.x; - left.y = property.y + style->border + property.h/2.0f - left.h/2; - - /* text label */ - name_len = nk_strlen(name); - size = font->width(font->userdata, font->height, name, name_len); - label.x = left.x + left.w + style->padding.x; - label.w = (float)size + 2 * style->padding.x; - label.y = property.y + style->border + style->padding.y; - label.h = property.h - (2 * style->border + 2 * style->padding.y); - - /* right increment button */ - right.y = left.y; - right.w = left.w; - right.h = left.h; - right.x = property.x + property.w - (right.w + style->padding.x); - - /* edit */ - if (*state == NK_PROPERTY_EDIT) { - size = font->width(font->userdata, font->height, buffer, *len); - size += style->edit.cursor_size; - length = len; - dst = buffer; - } else { - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - nk_itoa(string, variant->value.i); - num_len = nk_strlen(string); - break; - case NK_PROPERTY_FLOAT: - nk_dtoa(string, (double)variant->value.f); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); - break; - case NK_PROPERTY_DOUBLE: - nk_dtoa(string, variant->value.d); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); - break; - } - size = font->width(font->userdata, font->height, string, num_len); - dst = string; - length = &num_len; - } - - edit.w = (float)size + 2 * style->padding.x; - edit.w = NK_MIN(edit.w, right.x - (label.x + label.w)); - edit.x = right.x - (edit.w + style->padding.x); - edit.y = property.y + style->border; - edit.h = property.h - (2 * style->border); - - /* empty left space activator */ - empty.w = edit.x - (label.x + label.w); - empty.x = label.x + label.w; - empty.y = property.y; - empty.h = property.h; - - /* update property */ - old = (*state == NK_PROPERTY_EDIT); - nk_property_behavior(ws, in, property, label, edit, empty, state, variant, inc_per_pixel); - - /* draw property */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_property(out, style, &property, &label, *ws, name, name_len, font); - if (style->draw_end) style->draw_end(out, style->userdata); - - /* execute right button */ - if (nk_do_button_symbol(ws, out, left, style->sym_left, behavior, &style->dec_button, in, font)) { - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i - variant->step.i, variant->max_value.i); break; - case NK_PROPERTY_FLOAT: - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f - variant->step.f, variant->max_value.f); break; - case NK_PROPERTY_DOUBLE: - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break; - } - } - /* execute left button */ - if (nk_do_button_symbol(ws, out, right, style->sym_right, behavior, &style->inc_button, in, font)) { - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i + variant->step.i, variant->max_value.i); break; - case NK_PROPERTY_FLOAT: - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f + variant->step.f, variant->max_value.f); break; - case NK_PROPERTY_DOUBLE: - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break; - } - } - if (old != NK_PROPERTY_EDIT && (*state == NK_PROPERTY_EDIT)) { - /* property has been activated so setup buffer */ - NK_MEMCPY(buffer, dst, (nk_size)*length); - *cursor = nk_utf_len(buffer, *length); - *len = *length; - length = len; - dst = buffer; - active = 0; - } else active = (*state == NK_PROPERTY_EDIT); - - /* execute and run text edit field */ - nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]); - text_edit->active = (unsigned char)active; - text_edit->string.len = *length; - text_edit->cursor = NK_CLAMP(0, *cursor, *length); - text_edit->select_start = NK_CLAMP(0,*select_begin, *length); - text_edit->select_end = NK_CLAMP(0,*select_end, *length); - text_edit->string.buffer.allocated = (nk_size)*length; - text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER; - text_edit->string.buffer.memory.ptr = dst; - text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER; - text_edit->mode = NK_TEXT_EDIT_MODE_INSERT; - nk_do_edit(ws, out, edit, NK_EDIT_FIELD|NK_EDIT_AUTO_SELECT, - filters[filter], text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font); - - *length = text_edit->string.len; - *cursor = text_edit->cursor; - *select_begin = text_edit->select_start; - *select_end = text_edit->select_end; - if (text_edit->active && nk_input_is_key_pressed(in, NK_KEY_ENTER)) - text_edit->active = nk_false; - - if (active && !text_edit->active) { - /* property is now not active so convert edit text to value*/ - *state = NK_PROPERTY_DEFAULT; - buffer[*len] = '\0'; - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = nk_strtoi(buffer, 0); - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i); - break; - case NK_PROPERTY_FLOAT: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); - variant->value.f = nk_strtof(buffer, 0); - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f); - break; - case NK_PROPERTY_DOUBLE: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); - variant->value.d = nk_strtod(buffer, 0); - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); - break; - } - } -} -/* =============================================================== - * - * COLOR PICKER - * - * ===============================================================*/ -NK_INTERN int -nk_color_picker_behavior(nk_flags *state, - const struct nk_rect *bounds, const struct nk_rect *matrix, - const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, - struct nk_color *color, const struct nk_input *in) -{ - float hsva[4]; - int value_changed = 0; - int hsv_changed = 0; - - NK_ASSERT(state); - NK_ASSERT(matrix); - NK_ASSERT(hue_bar); - NK_ASSERT(color); - - /* color matrix */ - nk_color_hsva_fv(hsva, *color); - if (nk_button_behavior(state, *matrix, in, NK_BUTTON_REPEATER)) { - hsva[1] = NK_SATURATE((in->mouse.pos.x - matrix->x) / (matrix->w-1)); - hsva[2] = 1.0f - NK_SATURATE((in->mouse.pos.y - matrix->y) / (matrix->h-1)); - value_changed = hsv_changed = 1; - } - - /* hue bar */ - if (nk_button_behavior(state, *hue_bar, in, NK_BUTTON_REPEATER)) { - hsva[0] = NK_SATURATE((in->mouse.pos.y - hue_bar->y) / (hue_bar->h-1)); - value_changed = hsv_changed = 1; - } - - /* alpha bar */ - if (alpha_bar) { - if (nk_button_behavior(state, *alpha_bar, in, NK_BUTTON_REPEATER)) { - hsva[3] = 1.0f - NK_SATURATE((in->mouse.pos.y - alpha_bar->y) / (alpha_bar->h-1)); - value_changed = 1; - } - } - nk_widget_state_reset(state); - if (hsv_changed) { - *color = nk_hsva_fv(hsva); - *state = NK_WIDGET_STATE_ACTIVE; - } - if (value_changed) { - color->a = (nk_byte)(hsva[3] * 255.0f); - *state = NK_WIDGET_STATE_ACTIVE; - } - - /* set color picker widget state */ - if (nk_input_is_mouse_hovering_rect(in, *bounds)) - *state = NK_WIDGET_STATE_HOVERED; - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *bounds)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, *bounds)) - *state |= NK_WIDGET_STATE_LEFT; - return value_changed; -} - -NK_INTERN void -nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix, - const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, - struct nk_color color) -{ - NK_STORAGE const struct nk_color black = {0,0,0,255}; - NK_STORAGE const struct nk_color white = {255, 255, 255, 255}; - NK_STORAGE const struct nk_color black_trans = {0,0,0,0}; - - const float crosshair_size = 7.0f; - struct nk_color temp; - float hsva[4]; - float line_y; - int i; - - NK_ASSERT(o); - NK_ASSERT(matrix); - NK_ASSERT(hue_bar); - - /* draw hue bar */ - nk_color_hsv_fv(hsva, color); - for (i = 0; i < 6; ++i) { - NK_GLOBAL const struct nk_color hue_colors[] = { - {255, 0, 0, 255}, - {255,255,0,255}, - {0,255,0,255}, - {0, 255,255,255}, - {0,0,255,255}, - {255, 0, 255, 255}, - {255, 0, 0, 255} - }; - nk_fill_rect_multi_color(o, - nk_rect(hue_bar->x, hue_bar->y + (float)i * (hue_bar->h/6.0f) + 0.5f, - hue_bar->w, (hue_bar->h/6.0f) + 0.5f), hue_colors[i], hue_colors[i], - hue_colors[i+1], hue_colors[i+1]); - } - line_y = (float)(int)(hue_bar->y + hsva[0] * matrix->h + 0.5f); - nk_stroke_line(o, hue_bar->x-1, line_y, hue_bar->x + hue_bar->w + 2, - line_y, 1, nk_rgb(255,255,255)); - - /* draw alpha bar */ - if (alpha_bar) { - float alpha = NK_SATURATE((float)color.a/255.0f); - line_y = (float)(int)(alpha_bar->y + (1.0f - alpha) * matrix->h + 0.5f); - - nk_fill_rect_multi_color(o, *alpha_bar, white, white, black, black); - nk_stroke_line(o, alpha_bar->x-1, line_y, alpha_bar->x + alpha_bar->w + 2, - line_y, 1, nk_rgb(255,255,255)); - } - - /* draw color matrix */ - temp = nk_hsv_f(hsva[0], 1.0f, 1.0f); - nk_fill_rect_multi_color(o, *matrix, white, temp, temp, white); - nk_fill_rect_multi_color(o, *matrix, black_trans, black_trans, black, black); - - /* draw cross-hair */ - {struct nk_vec2 p; float S = hsva[1]; float V = hsva[2]; - p.x = (float)(int)(matrix->x + S * matrix->w); - p.y = (float)(int)(matrix->y + (1.0f - V) * matrix->h); - nk_stroke_line(o, p.x - crosshair_size, p.y, p.x-2, p.y, 1.0f, white); - nk_stroke_line(o, p.x + crosshair_size + 1, p.y, p.x+3, p.y, 1.0f, white); - nk_stroke_line(o, p.x, p.y + crosshair_size + 1, p.x, p.y+3, 1.0f, white); - nk_stroke_line(o, p.x, p.y - crosshair_size, p.x, p.y-2, 1.0f, white);} -} - -NK_INTERN int -nk_do_color_picker(nk_flags *state, - struct nk_command_buffer *out, struct nk_color *color, - enum nk_color_format fmt, struct nk_rect bounds, - struct nk_vec2 padding, const struct nk_input *in, - const struct nk_user_font *font) -{ - int ret = 0; - struct nk_rect matrix; - struct nk_rect hue_bar; - struct nk_rect alpha_bar; - float bar_w; - - NK_ASSERT(out); - NK_ASSERT(color); - NK_ASSERT(state); - NK_ASSERT(font); - if (!out || !color || !state || !font) - return ret; - - bar_w = font->height; - bounds.x += padding.x; - bounds.y += padding.x; - bounds.w -= 2 * padding.x; - bounds.h -= 2 * padding.y; - - matrix.x = bounds.x; - matrix.y = bounds.y; - matrix.h = bounds.h; - matrix.w = bounds.w - (3 * padding.x + 2 * bar_w); - - hue_bar.w = bar_w; - hue_bar.y = bounds.y; - hue_bar.h = matrix.h; - hue_bar.x = matrix.x + matrix.w + padding.x; - - alpha_bar.x = hue_bar.x + hue_bar.w + padding.x; - alpha_bar.y = bounds.y; - alpha_bar.w = bar_w; - alpha_bar.h = matrix.h; - - ret = nk_color_picker_behavior(state, &bounds, &matrix, &hue_bar, - (fmt == NK_RGBA) ? &alpha_bar:0, color, in); - nk_draw_color_picker(out, &matrix, &hue_bar, (fmt == NK_RGBA) ? &alpha_bar:0, *color); - return ret; -} - -/* ============================================================== - * - * STYLE - * - * ===============================================================*/ -NK_API void nk_style_default(struct nk_context *ctx){nk_style_from_table(ctx, 0);} -#define NK_COLOR_MAP(NK_COLOR)\ - NK_COLOR(NK_COLOR_TEXT, 175,175,175,255) \ - NK_COLOR(NK_COLOR_WINDOW, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_HEADER, 40, 40, 40, 255) \ - NK_COLOR(NK_COLOR_BORDER, 65, 65, 65, 255) \ - NK_COLOR(NK_COLOR_BUTTON, 50, 50, 50, 255) \ - NK_COLOR(NK_COLOR_BUTTON_HOVER, 40, 40, 40, 255) \ - NK_COLOR(NK_COLOR_BUTTON_ACTIVE, 35, 35, 35, 255) \ - NK_COLOR(NK_COLOR_TOGGLE, 100,100,100,255) \ - NK_COLOR(NK_COLOR_TOGGLE_HOVER, 120,120,120,255) \ - NK_COLOR(NK_COLOR_TOGGLE_CURSOR, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_SELECT, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_SELECT_ACTIVE, 35, 35, 35,255) \ - NK_COLOR(NK_COLOR_SLIDER, 38, 38, 38, 255) \ - NK_COLOR(NK_COLOR_SLIDER_CURSOR, 100,100,100,255) \ - NK_COLOR(NK_COLOR_SLIDER_CURSOR_HOVER, 120,120,120,255) \ - NK_COLOR(NK_COLOR_SLIDER_CURSOR_ACTIVE, 150,150,150,255) \ - NK_COLOR(NK_COLOR_PROPERTY, 38, 38, 38, 255) \ - NK_COLOR(NK_COLOR_EDIT, 38, 38, 38, 255) \ - NK_COLOR(NK_COLOR_EDIT_CURSOR, 175,175,175,255) \ - NK_COLOR(NK_COLOR_COMBO, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_CHART, 120,120,120,255) \ - NK_COLOR(NK_COLOR_CHART_COLOR, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_CHART_COLOR_HIGHLIGHT,255, 0, 0, 255) \ - NK_COLOR(NK_COLOR_SCROLLBAR, 40, 40, 40, 255) \ - NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR, 100,100,100,255) \ - NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_HOVER,120,120,120,255) \ - NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,150,150,150,255) \ - NK_COLOR(NK_COLOR_TAB_HEADER, 40, 40, 40,255) - -NK_GLOBAL const struct nk_color -nk_default_color_style[NK_COLOR_COUNT] = { -#define NK_COLOR(a,b,c,d,e) {b,c,d,e}, - NK_COLOR_MAP(NK_COLOR) -#undef NK_COLOR -}; - -NK_GLOBAL const char *nk_color_names[NK_COLOR_COUNT] = { -#define NK_COLOR(a,b,c,d,e) #a, - NK_COLOR_MAP(NK_COLOR) -#undef NK_COLOR -}; - -NK_API const char *nk_style_get_color_by_name(enum nk_style_colors c) -{return nk_color_names[c];} - -NK_API struct nk_style_item nk_style_item_image(struct nk_image img) -{struct nk_style_item i; i.type = NK_STYLE_ITEM_IMAGE; i.data.image = img; return i;} - -NK_API struct nk_style_item nk_style_item_color(struct nk_color col) -{struct nk_style_item i; i.type = NK_STYLE_ITEM_COLOR; i.data.color = col; return i;} - -NK_API struct nk_style_item nk_style_item_hide(void) -{struct nk_style_item i; i.type = NK_STYLE_ITEM_COLOR; i.data.color = nk_rgba(0,0,0,0); return i;} - -NK_API void -nk_style_from_table(struct nk_context *ctx, const struct nk_color *table) -{ - struct nk_style *style; - struct nk_style_text *text; - struct nk_style_button *button; - struct nk_style_toggle *toggle; - struct nk_style_selectable *select; - struct nk_style_slider *slider; - struct nk_style_progress *prog; - struct nk_style_scrollbar *scroll; - struct nk_style_edit *edit; - struct nk_style_property *property; - struct nk_style_combo *combo; - struct nk_style_chart *chart; - struct nk_style_tab *tab; - struct nk_style_window *win; - - NK_ASSERT(ctx); - if (!ctx) return; - style = &ctx->style; - table = (!table) ? nk_default_color_style: table; - - /* default text */ - text = &style->text; - text->color = table[NK_COLOR_TEXT]; - text->padding = nk_vec2(0,0); - - /* default button */ - button = &style->button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_BUTTON]); - button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]); - button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]); - button->border_color = table[NK_COLOR_BORDER]; - button->text_background = table[NK_COLOR_BUTTON]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->image_padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f, 0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 1.0f; - button->rounding = 4.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* contextual button */ - button = &style->contextual_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]); - button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]); - button->border_color = table[NK_COLOR_WINDOW]; - button->text_background = table[NK_COLOR_WINDOW]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* menu button */ - button = &style->menu_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->active = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->border_color = table[NK_COLOR_WINDOW]; - button->text_background = table[NK_COLOR_WINDOW]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 1.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* checkbox toggle */ - toggle = &style->checkbox; - nk_zero_struct(*toggle); - toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]); - toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->userdata = nk_handle_ptr(0); - toggle->text_background = table[NK_COLOR_WINDOW]; - toggle->text_normal = table[NK_COLOR_TEXT]; - toggle->text_hover = table[NK_COLOR_TEXT]; - toggle->text_active = table[NK_COLOR_TEXT]; - toggle->padding = nk_vec2(2.0f, 2.0f); - toggle->touch_padding = nk_vec2(0,0); - toggle->border_color = nk_rgba(0,0,0,0); - toggle->border = 0.0f; - toggle->spacing = 4; - - /* option toggle */ - toggle = &style->option; - nk_zero_struct(*toggle); - toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]); - toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->userdata = nk_handle_ptr(0); - toggle->text_background = table[NK_COLOR_WINDOW]; - toggle->text_normal = table[NK_COLOR_TEXT]; - toggle->text_hover = table[NK_COLOR_TEXT]; - toggle->text_active = table[NK_COLOR_TEXT]; - toggle->padding = nk_vec2(3.0f, 3.0f); - toggle->touch_padding = nk_vec2(0,0); - toggle->border_color = nk_rgba(0,0,0,0); - toggle->border = 0.0f; - toggle->spacing = 4; - - /* selectable */ - select = &style->selectable; - nk_zero_struct(*select); - select->normal = nk_style_item_color(table[NK_COLOR_SELECT]); - select->hover = nk_style_item_color(table[NK_COLOR_SELECT]); - select->pressed = nk_style_item_color(table[NK_COLOR_SELECT]); - select->normal_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); - select->hover_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); - select->pressed_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); - select->text_normal = table[NK_COLOR_TEXT]; - select->text_hover = table[NK_COLOR_TEXT]; - select->text_pressed = table[NK_COLOR_TEXT]; - select->text_normal_active = table[NK_COLOR_TEXT]; - select->text_hover_active = table[NK_COLOR_TEXT]; - select->text_pressed_active = table[NK_COLOR_TEXT]; - select->padding = nk_vec2(2.0f,2.0f); - select->touch_padding = nk_vec2(0,0); - select->userdata = nk_handle_ptr(0); - select->rounding = 0.0f; - select->draw_begin = 0; - select->draw_end = 0; - - /* slider */ - slider = &style->slider; - nk_zero_struct(*slider); - slider->normal = nk_style_item_hide(); - slider->hover = nk_style_item_hide(); - slider->active = nk_style_item_hide(); - slider->bar_normal = table[NK_COLOR_SLIDER]; - slider->bar_hover = table[NK_COLOR_SLIDER]; - slider->bar_active = table[NK_COLOR_SLIDER]; - slider->bar_filled = table[NK_COLOR_SLIDER_CURSOR]; - slider->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]); - slider->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]); - slider->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]); - slider->inc_symbol = NK_SYMBOL_TRIANGLE_RIGHT; - slider->dec_symbol = NK_SYMBOL_TRIANGLE_LEFT; - slider->cursor_size = nk_vec2(16,16); - slider->padding = nk_vec2(2,2); - slider->spacing = nk_vec2(2,2); - slider->userdata = nk_handle_ptr(0); - slider->show_buttons = nk_false; - slider->bar_height = 8; - slider->rounding = 0; - slider->draw_begin = 0; - slider->draw_end = 0; - - /* slider buttons */ - button = &style->slider.inc_button; - button->normal = nk_style_item_color(nk_rgb(40,40,40)); - button->hover = nk_style_item_color(nk_rgb(42,42,42)); - button->active = nk_style_item_color(nk_rgb(44,44,44)); - button->border_color = nk_rgb(65,65,65); - button->text_background = nk_rgb(40,40,40); - button->text_normal = nk_rgb(175,175,175); - button->text_hover = nk_rgb(175,175,175); - button->text_active = nk_rgb(175,175,175); - button->padding = nk_vec2(8.0f,8.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 1.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->slider.dec_button = style->slider.inc_button; - - /* progressbar */ - prog = &style->progress; - nk_zero_struct(*prog); - prog->normal = nk_style_item_color(table[NK_COLOR_SLIDER]); - prog->hover = nk_style_item_color(table[NK_COLOR_SLIDER]); - prog->active = nk_style_item_color(table[NK_COLOR_SLIDER]); - prog->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]); - prog->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]); - prog->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]); - prog->border_color = nk_rgba(0,0,0,0); - prog->cursor_border_color = nk_rgba(0,0,0,0); - prog->userdata = nk_handle_ptr(0); - prog->padding = nk_vec2(4,4); - prog->rounding = 0; - prog->border = 0; - prog->cursor_rounding = 0; - prog->cursor_border = 0; - prog->draw_begin = 0; - prog->draw_end = 0; - - /* scrollbars */ - scroll = &style->scrollh; - nk_zero_struct(*scroll); - scroll->normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); - scroll->hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); - scroll->active = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); - scroll->cursor_normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR]); - scroll->cursor_hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_HOVER]); - scroll->cursor_active = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE]); - scroll->dec_symbol = NK_SYMBOL_CIRCLE_SOLID; - scroll->inc_symbol = NK_SYMBOL_CIRCLE_SOLID; - scroll->userdata = nk_handle_ptr(0); - scroll->border_color = table[NK_COLOR_SCROLLBAR]; - scroll->cursor_border_color = table[NK_COLOR_SCROLLBAR]; - scroll->padding = nk_vec2(0,0); - scroll->show_buttons = nk_false; - scroll->border = 0; - scroll->rounding = 0; - scroll->border_cursor = 0; - scroll->rounding_cursor = 0; - scroll->draw_begin = 0; - scroll->draw_end = 0; - style->scrollv = style->scrollh; - - /* scrollbars buttons */ - button = &style->scrollh.inc_button; - button->normal = nk_style_item_color(nk_rgb(40,40,40)); - button->hover = nk_style_item_color(nk_rgb(42,42,42)); - button->active = nk_style_item_color(nk_rgb(44,44,44)); - button->border_color = nk_rgb(65,65,65); - button->text_background = nk_rgb(40,40,40); - button->text_normal = nk_rgb(175,175,175); - button->text_hover = nk_rgb(175,175,175); - button->text_active = nk_rgb(175,175,175); - button->padding = nk_vec2(4.0f,4.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 1.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->scrollh.dec_button = style->scrollh.inc_button; - style->scrollv.inc_button = style->scrollh.inc_button; - style->scrollv.dec_button = style->scrollh.inc_button; - - /* edit */ - edit = &style->edit; - nk_zero_struct(*edit); - edit->normal = nk_style_item_color(table[NK_COLOR_EDIT]); - edit->hover = nk_style_item_color(table[NK_COLOR_EDIT]); - edit->active = nk_style_item_color(table[NK_COLOR_EDIT]); - edit->cursor_normal = table[NK_COLOR_TEXT]; - edit->cursor_hover = table[NK_COLOR_TEXT]; - edit->cursor_text_normal= table[NK_COLOR_EDIT]; - edit->cursor_text_hover = table[NK_COLOR_EDIT]; - edit->border_color = table[NK_COLOR_BORDER]; - edit->text_normal = table[NK_COLOR_TEXT]; - edit->text_hover = table[NK_COLOR_TEXT]; - edit->text_active = table[NK_COLOR_TEXT]; - edit->selected_normal = table[NK_COLOR_TEXT]; - edit->selected_hover = table[NK_COLOR_TEXT]; - edit->selected_text_normal = table[NK_COLOR_EDIT]; - edit->selected_text_hover = table[NK_COLOR_EDIT]; - edit->scrollbar_size = nk_vec2(10,10); - edit->scrollbar = style->scrollv; - edit->padding = nk_vec2(4,4); - edit->row_padding = 2; - edit->cursor_size = 4; - edit->border = 1; - edit->rounding = 0; - - /* property */ - property = &style->property; - nk_zero_struct(*property); - property->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); - property->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); - property->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); - property->border_color = table[NK_COLOR_BORDER]; - property->label_normal = table[NK_COLOR_TEXT]; - property->label_hover = table[NK_COLOR_TEXT]; - property->label_active = table[NK_COLOR_TEXT]; - property->sym_left = NK_SYMBOL_TRIANGLE_LEFT; - property->sym_right = NK_SYMBOL_TRIANGLE_RIGHT; - property->userdata = nk_handle_ptr(0); - property->padding = nk_vec2(4,4); - property->border = 1; - property->rounding = 10; - property->draw_begin = 0; - property->draw_end = 0; - - /* property buttons */ - button = &style->property.dec_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); - button->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); - button->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_PROPERTY]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->property.inc_button = style->property.dec_button; - - /* property edit */ - edit = &style->property.edit; - nk_zero_struct(*edit); - edit->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); - edit->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); - edit->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); - edit->border_color = nk_rgba(0,0,0,0); - edit->cursor_normal = table[NK_COLOR_TEXT]; - edit->cursor_hover = table[NK_COLOR_TEXT]; - edit->cursor_text_normal= table[NK_COLOR_EDIT]; - edit->cursor_text_hover = table[NK_COLOR_EDIT]; - edit->text_normal = table[NK_COLOR_TEXT]; - edit->text_hover = table[NK_COLOR_TEXT]; - edit->text_active = table[NK_COLOR_TEXT]; - edit->selected_normal = table[NK_COLOR_TEXT]; - edit->selected_hover = table[NK_COLOR_TEXT]; - edit->selected_text_normal = table[NK_COLOR_EDIT]; - edit->selected_text_hover = table[NK_COLOR_EDIT]; - edit->padding = nk_vec2(0,0); - edit->cursor_size = 8; - edit->border = 0; - edit->rounding = 0; - - /* chart */ - chart = &style->chart; - nk_zero_struct(*chart); - chart->background = nk_style_item_color(table[NK_COLOR_CHART]); - chart->border_color = table[NK_COLOR_BORDER]; - chart->selected_color = table[NK_COLOR_CHART_COLOR_HIGHLIGHT]; - chart->color = table[NK_COLOR_CHART_COLOR]; - chart->padding = nk_vec2(4,4); - chart->border = 0; - chart->rounding = 0; - - /* combo */ - combo = &style->combo; - combo->normal = nk_style_item_color(table[NK_COLOR_COMBO]); - combo->hover = nk_style_item_color(table[NK_COLOR_COMBO]); - combo->active = nk_style_item_color(table[NK_COLOR_COMBO]); - combo->border_color = table[NK_COLOR_BORDER]; - combo->label_normal = table[NK_COLOR_TEXT]; - combo->label_hover = table[NK_COLOR_TEXT]; - combo->label_active = table[NK_COLOR_TEXT]; - combo->sym_normal = NK_SYMBOL_TRIANGLE_DOWN; - combo->sym_hover = NK_SYMBOL_TRIANGLE_DOWN; - combo->sym_active = NK_SYMBOL_TRIANGLE_DOWN; - combo->content_padding = nk_vec2(4,4); - combo->button_padding = nk_vec2(0,4); - combo->spacing = nk_vec2(4,0); - combo->border = 1; - combo->rounding = 0; - - /* combo button */ - button = &style->combo.button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_COMBO]); - button->hover = nk_style_item_color(table[NK_COLOR_COMBO]); - button->active = nk_style_item_color(table[NK_COLOR_COMBO]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_COMBO]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* tab */ - tab = &style->tab; - tab->background = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - tab->border_color = table[NK_COLOR_BORDER]; - tab->text = table[NK_COLOR_TEXT]; - tab->sym_minimize = NK_SYMBOL_TRIANGLE_RIGHT; - tab->sym_maximize = NK_SYMBOL_TRIANGLE_DOWN; - tab->padding = nk_vec2(4,4); - tab->spacing = nk_vec2(4,4); - tab->indent = 10.0f; - tab->border = 1; - tab->rounding = 0; - - /* tab button */ - button = &style->tab.tab_minimize_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - button->hover = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - button->active = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_TAB_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->tab.tab_maximize_button =*button; - - /* node button */ - button = &style->tab.node_minimize_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->active = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_TAB_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->tab.node_maximize_button =*button; - - /* window header */ - win = &style->window; - win->header.align = NK_HEADER_RIGHT; - win->header.close_symbol = NK_SYMBOL_X; - win->header.minimize_symbol = NK_SYMBOL_MINUS; - win->header.maximize_symbol = NK_SYMBOL_PLUS; - win->header.normal = nk_style_item_color(table[NK_COLOR_HEADER]); - win->header.hover = nk_style_item_color(table[NK_COLOR_HEADER]); - win->header.active = nk_style_item_color(table[NK_COLOR_HEADER]); - win->header.label_normal = table[NK_COLOR_TEXT]; - win->header.label_hover = table[NK_COLOR_TEXT]; - win->header.label_active = table[NK_COLOR_TEXT]; - win->header.label_padding = nk_vec2(4,4); - win->header.padding = nk_vec2(4,4); - win->header.spacing = nk_vec2(0,0); - - /* window header close button */ - button = &style->window.header.close_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_HEADER]); - button->hover = nk_style_item_color(table[NK_COLOR_HEADER]); - button->active = nk_style_item_color(table[NK_COLOR_HEADER]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* window header minimize button */ - button = &style->window.header.minimize_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_HEADER]); - button->hover = nk_style_item_color(table[NK_COLOR_HEADER]); - button->active = nk_style_item_color(table[NK_COLOR_HEADER]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* window */ - win->background = table[NK_COLOR_WINDOW]; - win->fixed_background = nk_style_item_color(table[NK_COLOR_WINDOW]); - win->border_color = table[NK_COLOR_BORDER]; - win->popup_border_color = table[NK_COLOR_BORDER]; - win->combo_border_color = table[NK_COLOR_BORDER]; - win->contextual_border_color = table[NK_COLOR_BORDER]; - win->menu_border_color = table[NK_COLOR_BORDER]; - win->group_border_color = table[NK_COLOR_BORDER]; - win->tooltip_border_color = table[NK_COLOR_BORDER]; - win->scaler = nk_style_item_color(table[NK_COLOR_TEXT]); - - win->rounding = 0.0f; - win->spacing = nk_vec2(4,4); - win->scrollbar_size = nk_vec2(10,10); - win->min_size = nk_vec2(64,64); - - win->combo_border = 1.0f; - win->contextual_border = 1.0f; - win->menu_border = 1.0f; - win->group_border = 1.0f; - win->tooltip_border = 1.0f; - win->popup_border = 1.0f; - win->border = 2.0f; - win->min_row_height_padding = 8; - - win->padding = nk_vec2(4,4); - win->group_padding = nk_vec2(4,4); - win->popup_padding = nk_vec2(4,4); - win->combo_padding = nk_vec2(4,4); - win->contextual_padding = nk_vec2(4,4); - win->menu_padding = nk_vec2(4,4); - win->tooltip_padding = nk_vec2(4,4); -} - -NK_API void -nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font) -{ - struct nk_style *style; - NK_ASSERT(ctx); - - if (!ctx) return; - style = &ctx->style; - style->font = font; - ctx->stacks.fonts.head = 0; - if (ctx->current) - nk_layout_reset_min_row_height(ctx); -} - -NK_API int -nk_style_push_font(struct nk_context *ctx, const struct nk_user_font *font) -{ - struct nk_config_stack_user_font *font_stack; - struct nk_config_stack_user_font_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - font_stack = &ctx->stacks.fonts; - NK_ASSERT(font_stack->head < (int)NK_LEN(font_stack->elements)); - if (font_stack->head >= (int)NK_LEN(font_stack->elements)) - return 0; - - element = &font_stack->elements[font_stack->head++]; - element->address = &ctx->style.font; - element->old_value = ctx->style.font; - ctx->style.font = font; - return 1; -} - -NK_API int -nk_style_pop_font(struct nk_context *ctx) -{ - struct nk_config_stack_user_font *font_stack; - struct nk_config_stack_user_font_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - font_stack = &ctx->stacks.fonts; - NK_ASSERT(font_stack->head > 0); - if (font_stack->head < 1) - return 0; - - element = &font_stack->elements[--font_stack->head]; - *element->address = element->old_value; - return 1; -} - -#define NK_STYLE_PUSH_IMPLEMENATION(prefix, type, stack) \ -nk_style_push_##type(struct nk_context *ctx, prefix##_##type *address, prefix##_##type value)\ -{\ - struct nk_config_stack_##type * type_stack;\ - struct nk_config_stack_##type##_element *element;\ - NK_ASSERT(ctx);\ - if (!ctx) return 0;\ - type_stack = &ctx->stacks.stack;\ - NK_ASSERT(type_stack->head < (int)NK_LEN(type_stack->elements));\ - if (type_stack->head >= (int)NK_LEN(type_stack->elements))\ - return 0;\ - element = &type_stack->elements[type_stack->head++];\ - element->address = address;\ - element->old_value = *address;\ - *address = value;\ - return 1;\ -} - -#define NK_STYLE_POP_IMPLEMENATION(type, stack) \ -nk_style_pop_##type(struct nk_context *ctx)\ -{\ - struct nk_config_stack_##type *type_stack;\ - struct nk_config_stack_##type##_element *element;\ - NK_ASSERT(ctx);\ - if (!ctx) return 0;\ - type_stack = &ctx->stacks.stack;\ - NK_ASSERT(type_stack->head > 0);\ - if (type_stack->head < 1)\ - return 0;\ - element = &type_stack->elements[--type_stack->head];\ - *element->address = element->old_value;\ - return 1;\ -} - -NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, style_item, style_items) -NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,float, floats) -NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, vec2, vectors) -NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,flags, flags) -NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk,color, colors) - -NK_API int NK_STYLE_POP_IMPLEMENATION(style_item, style_items) -NK_API int NK_STYLE_POP_IMPLEMENATION(float,floats) -NK_API int NK_STYLE_POP_IMPLEMENATION(vec2, vectors) -NK_API int NK_STYLE_POP_IMPLEMENATION(flags,flags) -NK_API int NK_STYLE_POP_IMPLEMENATION(color,colors) - -NK_API int -nk_style_set_cursor(struct nk_context *ctx, enum nk_style_cursor c) -{ - struct nk_style *style; - NK_ASSERT(ctx); - if (!ctx) return 0; - style = &ctx->style; - if (style->cursors[c]) { - style->cursor_active = style->cursors[c]; - return 1; - } - return 0; -} - -NK_API void -nk_style_show_cursor(struct nk_context *ctx) -{ - ctx->style.cursor_visible = nk_true; -} - -NK_API void -nk_style_hide_cursor(struct nk_context *ctx) -{ - ctx->style.cursor_visible = nk_false; -} - -NK_API void -nk_style_load_cursor(struct nk_context *ctx, enum nk_style_cursor cursor, - const struct nk_cursor *c) -{ - struct nk_style *style; - NK_ASSERT(ctx); - if (!ctx) return; - style = &ctx->style; - style->cursors[cursor] = c; -} - -NK_API void -nk_style_load_all_cursors(struct nk_context *ctx, struct nk_cursor *cursors) -{ - int i = 0; - struct nk_style *style; - NK_ASSERT(ctx); - if (!ctx) return; - style = &ctx->style; - for (i = 0; i < NK_CURSOR_COUNT; ++i) - style->cursors[i] = &cursors[i]; - style->cursor_visible = nk_true; -} - -/* =============================================================== - * - * POOL - * - * ===============================================================*/ -NK_INTERN void -nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc, - unsigned int capacity) -{ - nk_zero(pool, sizeof(*pool)); - pool->alloc = *alloc; - pool->capacity = capacity; - pool->type = NK_BUFFER_DYNAMIC; - pool->pages = 0; -} - -NK_INTERN void -nk_pool_free(struct nk_pool *pool) -{ - struct nk_page *iter = pool->pages; - if (!pool) return; - if (pool->type == NK_BUFFER_FIXED) return; - while (iter) { - struct nk_page *next = iter->next; - pool->alloc.free(pool->alloc.userdata, iter); - iter = next; - } -} - -NK_INTERN void -nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size) -{ - nk_zero(pool, sizeof(*pool)); - NK_ASSERT(size >= sizeof(struct nk_page)); - if (size < sizeof(struct nk_page)) return; - pool->capacity = (unsigned)(size - sizeof(struct nk_page)) / sizeof(struct nk_page_element); - pool->pages = (struct nk_page*)memory; - pool->type = NK_BUFFER_FIXED; - pool->size = size; -} - -NK_INTERN struct nk_page_element* -nk_pool_alloc(struct nk_pool *pool) -{ - if (!pool->pages || pool->pages->size >= pool->capacity) { - /* allocate new page */ - struct nk_page *page; - if (pool->type == NK_BUFFER_FIXED) { - if (!pool->pages) { - NK_ASSERT(pool->pages); - return 0; - } - NK_ASSERT(pool->pages->size < pool->capacity); - return 0; - } else { - nk_size size = sizeof(struct nk_page); - size += NK_POOL_DEFAULT_CAPACITY * sizeof(union nk_page_data); - page = (struct nk_page*)pool->alloc.alloc(pool->alloc.userdata,0, size); - page->next = pool->pages; - pool->pages = page; - page->size = 0; - } - } - return &pool->pages->win[pool->pages->size++]; -} - -/* =============================================================== - * - * CONTEXT - * - * ===============================================================*/ -NK_INTERN void* nk_create_window(struct nk_context *ctx); -NK_INTERN void nk_remove_window(struct nk_context*, struct nk_window*); -NK_INTERN void nk_free_window(struct nk_context *ctx, struct nk_window *win); -NK_INTERN void nk_free_table(struct nk_context *ctx, struct nk_table *tbl); -NK_INTERN void nk_remove_table(struct nk_window *win, struct nk_table *tbl); -NK_INTERN void* nk_create_panel(struct nk_context *ctx); -NK_INTERN void nk_free_panel(struct nk_context*, struct nk_panel *pan); - -NK_INTERN void -nk_setup(struct nk_context *ctx, const struct nk_user_font *font) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_zero_struct(*ctx); - nk_style_default(ctx); - ctx->seq = 1; - if (font) ctx->style.font = font; -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - nk_draw_list_init(&ctx->draw_list); -#endif -} - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API int -nk_init_default(struct nk_context *ctx, const struct nk_user_font *font) -{ - struct nk_allocator alloc; - alloc.userdata.ptr = 0; - alloc.alloc = nk_malloc; - alloc.free = nk_mfree; - return nk_init(ctx, &alloc, font); -} -#endif - -NK_API int -nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, - const struct nk_user_font *font) -{ - NK_ASSERT(memory); - if (!memory) return 0; - nk_setup(ctx, font); - nk_buffer_init_fixed(&ctx->memory, memory, size); - ctx->use_pool = nk_false; - return 1; -} - -NK_API int -nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, - struct nk_buffer *pool, const struct nk_user_font *font) -{ - NK_ASSERT(cmds); - NK_ASSERT(pool); - if (!cmds || !pool) return 0; - - nk_setup(ctx, font); - ctx->memory = *cmds; - if (pool->type == NK_BUFFER_FIXED) { - /* take memory from buffer and alloc fixed pool */ - nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size); - } else { - /* create dynamic pool from buffer allocator */ - struct nk_allocator *alloc = &pool->pool; - nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY); - } - ctx->use_pool = nk_true; - return 1; -} - -NK_API int -nk_init(struct nk_context *ctx, struct nk_allocator *alloc, - const struct nk_user_font *font) -{ - NK_ASSERT(alloc); - if (!alloc) return 0; - nk_setup(ctx, font); - nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE); - nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY); - ctx->use_pool = nk_true; - return 1; -} - -#ifdef NK_INCLUDE_COMMAND_USERDATA -NK_API void -nk_set_user_data(struct nk_context *ctx, nk_handle handle) -{ - if (!ctx) return; - ctx->userdata = handle; - if (ctx->current) - ctx->current->buffer.userdata = handle; -} -#endif - -NK_API void -nk_free(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_buffer_free(&ctx->memory); - if (ctx->use_pool) - nk_pool_free(&ctx->pool); - - nk_zero(&ctx->input, sizeof(ctx->input)); - nk_zero(&ctx->style, sizeof(ctx->style)); - nk_zero(&ctx->memory, sizeof(ctx->memory)); - - ctx->seq = 0; - ctx->build = 0; - ctx->begin = 0; - ctx->end = 0; - ctx->active = 0; - ctx->current = 0; - ctx->freelist = 0; - ctx->count = 0; -} - -NK_API void -nk_clear(struct nk_context *ctx) -{ - struct nk_window *iter; - struct nk_window *next; - NK_ASSERT(ctx); - - if (!ctx) return; - if (ctx->use_pool) - nk_buffer_clear(&ctx->memory); - else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT); - - ctx->build = 0; - ctx->memory.calls = 0; - ctx->last_widget_state = 0; - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW]; - NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay)); -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - nk_draw_list_clear(&ctx->draw_list); -#endif - - /* garbage collector */ - iter = ctx->begin; - while (iter) { - /* make sure minimized windows do not get removed */ - if ((iter->flags & NK_WINDOW_MINIMIZED) && - !(iter->flags & NK_WINDOW_CLOSED)) { - iter = iter->next; - continue; - } - /* remove hotness from hidden or closed windows*/ - if (((iter->flags & NK_WINDOW_HIDDEN) || - (iter->flags & NK_WINDOW_CLOSED)) && - iter == ctx->active) - ctx->active = iter->next; - - /* free unused popup windows */ - if (iter->popup.win && iter->popup.win->seq != ctx->seq) { - nk_free_window(ctx, iter->popup.win); - iter->popup.win = 0; - } - /* remove unused window state tables */ - {struct nk_table *n, *it = iter->tables; - while (it) { - n = it->next; - if (it->seq != ctx->seq) { - nk_remove_table(iter, it); - nk_zero(it, sizeof(union nk_page_data)); - nk_free_table(ctx, it); - if (it == iter->tables) - iter->tables = n; - } - it = n; - }} - /* window itself is not used anymore so free */ - if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) { - next = iter->next; - nk_remove_window(ctx, iter); - nk_free_window(ctx, iter); - iter = next; - } else iter = iter->next; - } - ctx->seq++; -} - -/* ---------------------------------------------------------------- - * - * BUFFERING - * - * ---------------------------------------------------------------*/ -NK_INTERN void -nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer) -{ - NK_ASSERT(ctx); - NK_ASSERT(buffer); - if (!ctx || !buffer) return; - buffer->begin = ctx->memory.allocated; - buffer->end = buffer->begin; - buffer->last = buffer->begin; - buffer->clip = nk_null_rect; -} - -NK_INTERN void -nk_start(struct nk_context *ctx, struct nk_window *win) -{ - NK_ASSERT(ctx); - NK_ASSERT(win); - nk_start_buffer(ctx, &win->buffer); -} - -NK_INTERN void -nk_start_popup(struct nk_context *ctx, struct nk_window *win) -{ - struct nk_popup_buffer *buf; - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!ctx || !win) return; - - /* save buffer fill state for popup */ - buf = &win->popup.buf; - buf->begin = win->buffer.end; - buf->end = win->buffer.end; - buf->parent = win->buffer.last; - buf->last = buf->begin; - buf->active = nk_true; -} - -NK_INTERN void -nk_finish_popup(struct nk_context *ctx, struct nk_window *win) -{ - struct nk_popup_buffer *buf; - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!ctx || !win) return; - - buf = &win->popup.buf; - buf->last = win->buffer.last; - buf->end = win->buffer.end; -} - -NK_INTERN void -nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer) -{ - NK_ASSERT(ctx); - NK_ASSERT(buffer); - if (!ctx || !buffer) return; - buffer->end = ctx->memory.allocated; -} - -NK_INTERN void -nk_finish(struct nk_context *ctx, struct nk_window *win) -{ - struct nk_popup_buffer *buf; - struct nk_command *parent_last; - void *memory; - - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!ctx || !win) return; - nk_finish_buffer(ctx, &win->buffer); - if (!win->popup.buf.active) return; - - buf = &win->popup.buf; - memory = ctx->memory.memory.ptr; - parent_last = nk_ptr_add(struct nk_command, memory, buf->parent); - parent_last->next = buf->end; -} - -NK_INTERN void -nk_build(struct nk_context *ctx) -{ - struct nk_window *iter = 0; - struct nk_command *cmd = 0; - nk_byte *buffer = 0; - - /* draw cursor overlay */ - if (!ctx->style.cursor_active) - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW]; - if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) { - struct nk_rect mouse_bounds; - const struct nk_cursor *cursor = ctx->style.cursor_active; - nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF); - nk_start_buffer(ctx, &ctx->overlay); - - mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x; - mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y; - mouse_bounds.w = cursor->size.x; - mouse_bounds.h = cursor->size.y; - - nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white); - nk_finish_buffer(ctx, &ctx->overlay); - } - /* build one big draw command list out of all window buffers */ - iter = ctx->begin; - buffer = (nk_byte*)ctx->memory.memory.ptr; - while (iter != 0) { - struct nk_window *next = iter->next; - if (iter->buffer.last == iter->buffer.begin || (iter->flags & NK_WINDOW_HIDDEN)|| - iter->seq != ctx->seq) - goto cont; - - cmd = nk_ptr_add(struct nk_command, buffer, iter->buffer.last); - while (next && ((next->buffer.last == next->buffer.begin) || - (next->flags & NK_WINDOW_HIDDEN))) - next = next->next; /* skip empty command buffers */ - - if (next) cmd->next = next->buffer.begin; - cont: iter = next; - } - /* append all popup draw commands into lists */ - iter = ctx->begin; - while (iter != 0) { - struct nk_window *next = iter->next; - struct nk_popup_buffer *buf; - if (!iter->popup.buf.active) - goto skip; - - buf = &iter->popup.buf; - cmd->next = buf->begin; - cmd = nk_ptr_add(struct nk_command, buffer, buf->last); - buf->active = nk_false; - skip: iter = next; - } - /* append overlay commands */ - if (cmd) { - if (ctx->overlay.end != ctx->overlay.begin) - cmd->next = ctx->overlay.begin; - else cmd->next = ctx->memory.allocated; - } -} - -NK_API const struct nk_command* -nk__begin(struct nk_context *ctx) -{ - struct nk_window *iter; - nk_byte *buffer; - NK_ASSERT(ctx); - if (!ctx) return 0; - if (!ctx->count) return 0; - - buffer = (nk_byte*)ctx->memory.memory.ptr; - if (!ctx->build) { - nk_build(ctx); - ctx->build = nk_true; - } - iter = ctx->begin; - while (iter && ((iter->buffer.begin == iter->buffer.end) || (iter->flags & NK_WINDOW_HIDDEN))) - iter = iter->next; - if (!iter) return 0; - return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin); -} - -NK_API const struct nk_command* -nk__next(struct nk_context *ctx, const struct nk_command *cmd) -{ - nk_byte *buffer; - const struct nk_command *next; - NK_ASSERT(ctx); - if (!ctx || !cmd || !ctx->count) return 0; - if (cmd->next >= ctx->memory.allocated) return 0; - buffer = (nk_byte*)ctx->memory.memory.ptr; - next = nk_ptr_add_const(struct nk_command, buffer, cmd->next); - return next; -} - -/* ---------------------------------------------------------------- - * - * PANEL - * - * ---------------------------------------------------------------*/ -static int -nk_panel_has_header(nk_flags flags, const char *title) -{ - int active = 0; - active = (flags & (NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE)); - active = active || (flags & NK_WINDOW_TITLE); - active = active && !(flags & NK_WINDOW_HIDDEN) && title; - return active; -} - -NK_INTERN struct nk_vec2 -nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type) -{ - switch (type) { - default: - case NK_PANEL_WINDOW: return style->window.padding; - case NK_PANEL_GROUP: return style->window.group_padding; - case NK_PANEL_POPUP: return style->window.popup_padding; - case NK_PANEL_CONTEXTUAL: return style->window.contextual_padding; - case NK_PANEL_COMBO: return style->window.combo_padding; - case NK_PANEL_MENU: return style->window.menu_padding; - case NK_PANEL_TOOLTIP: return style->window.menu_padding; - } -} - -NK_INTERN float -nk_panel_get_border(const struct nk_style *style, nk_flags flags, - enum nk_panel_type type) -{ - if (flags & NK_WINDOW_BORDER) { - switch (type) { - default: - case NK_PANEL_WINDOW: return style->window.border; - case NK_PANEL_GROUP: return style->window.group_border; - case NK_PANEL_POPUP: return style->window.popup_border; - case NK_PANEL_CONTEXTUAL: return style->window.contextual_border; - case NK_PANEL_COMBO: return style->window.combo_border; - case NK_PANEL_MENU: return style->window.menu_border; - case NK_PANEL_TOOLTIP: return style->window.menu_border; - }} else return 0; -} - -NK_INTERN struct nk_color -nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type) -{ - switch (type) { - default: - case NK_PANEL_WINDOW: return style->window.border_color; - case NK_PANEL_GROUP: return style->window.group_border_color; - case NK_PANEL_POPUP: return style->window.popup_border_color; - case NK_PANEL_CONTEXTUAL: return style->window.contextual_border_color; - case NK_PANEL_COMBO: return style->window.combo_border_color; - case NK_PANEL_MENU: return style->window.menu_border_color; - case NK_PANEL_TOOLTIP: return style->window.menu_border_color; - } -} - -NK_INTERN int -nk_panel_is_sub(enum nk_panel_type type) -{ - return (type & NK_PANEL_SET_SUB)?1:0; -} - -NK_INTERN int -nk_panel_is_nonblock(enum nk_panel_type type) -{ - return (type & NK_PANEL_SET_NONBLOCK)?1:0; -} - -NK_INTERN int -nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type) -{ - struct nk_input *in; - struct nk_window *win; - struct nk_panel *layout; - struct nk_command_buffer *out; - const struct nk_style *style; - const struct nk_user_font *font; - - struct nk_vec2 scrollbar_size; - struct nk_vec2 panel_padding; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return 0; - nk_zero(ctx->current->layout, sizeof(*ctx->current->layout)); - if ((ctx->current->flags & NK_WINDOW_HIDDEN) || (ctx->current->flags & NK_WINDOW_CLOSED)) { - nk_zero(ctx->current->layout, sizeof(struct nk_panel)); - ctx->current->layout->type = panel_type; - return 0; - } - /* pull state into local stack */ - style = &ctx->style; - font = style->font; - win = ctx->current; - layout = win->layout; - out = &win->buffer; - in = (win->flags & NK_WINDOW_NO_INPUT) ? 0: &ctx->input; -#ifdef NK_INCLUDE_COMMAND_USERDATA - win->buffer.userdata = ctx->userdata; -#endif - /* pull style configuration into local stack */ - scrollbar_size = style->window.scrollbar_size; - panel_padding = nk_panel_get_padding(style, panel_type); - - /* window movement */ - if ((win->flags & NK_WINDOW_MOVABLE) && !(win->flags & NK_WINDOW_ROM)) { - int left_mouse_down; - int left_mouse_click_in_cursor; - - /* calculate draggable window space */ - struct nk_rect header; - header.x = win->bounds.x; - header.y = win->bounds.y; - header.w = win->bounds.w; - if (nk_panel_has_header(win->flags, title)) { - header.h = font->height + 2.0f * style->window.header.padding.y; - header.h += 2.0f * style->window.header.label_padding.y; - } else header.h = panel_padding.y; - - /* window movement by dragging */ - left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; - left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, header, nk_true); - if (left_mouse_down && left_mouse_click_in_cursor) { - win->bounds.x = win->bounds.x + in->mouse.delta.x; - win->bounds.y = win->bounds.y + in->mouse.delta.y; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x += in->mouse.delta.x; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y += in->mouse.delta.y; - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_MOVE]; - } - } - - /* setup panel */ - layout->type = panel_type; - layout->flags = win->flags; - layout->bounds = win->bounds; - layout->bounds.x += panel_padding.x; - layout->bounds.w -= 2*panel_padding.x; - if (win->flags & NK_WINDOW_BORDER) { - layout->border = nk_panel_get_border(style, win->flags, panel_type); - layout->bounds = nk_shrink_rect(layout->bounds, layout->border); - } else layout->border = 0; - layout->at_y = layout->bounds.y; - layout->at_x = layout->bounds.x; - layout->max_x = 0; - layout->header_height = 0; - layout->footer_height = 0; - nk_layout_reset_min_row_height(ctx); - layout->row.index = 0; - layout->row.columns = 0; - layout->row.ratio = 0; - layout->row.item_width = 0; - layout->row.tree_depth = 0; - layout->row.height = panel_padding.y; - layout->has_scrolling = nk_true; - if (!(win->flags & NK_WINDOW_NO_SCROLLBAR)) - layout->bounds.w -= scrollbar_size.x; - if (!nk_panel_is_nonblock(panel_type)) { - layout->footer_height = 0; - if (!(win->flags & NK_WINDOW_NO_SCROLLBAR) || win->flags & NK_WINDOW_SCALABLE) - layout->footer_height = scrollbar_size.y; - layout->bounds.h -= layout->footer_height; - } - - /* panel header */ - if (nk_panel_has_header(win->flags, title)) - { - struct nk_text text; - struct nk_rect header; - const struct nk_style_item *background = 0; - - /* calculate header bounds */ - header.x = win->bounds.x; - header.y = win->bounds.y; - header.w = win->bounds.w; - header.h = font->height + 2.0f * style->window.header.padding.y; - header.h += (2.0f * style->window.header.label_padding.y); - - /* shrink panel by header */ - layout->header_height = header.h; - layout->bounds.y += header.h; - layout->bounds.h -= header.h; - layout->at_y += header.h; - - /* select correct header background and text color */ - if (ctx->active == win) { - background = &style->window.header.active; - text.text = style->window.header.label_active; - } else if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) { - background = &style->window.header.hover; - text.text = style->window.header.label_hover; - } else { - background = &style->window.header.normal; - text.text = style->window.header.label_normal; - } - - /* draw header background */ - header.h += 1.0f; - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(out, header, 0, background->data.color); - } - - /* window close button */ - {struct nk_rect button; - button.y = header.y + style->window.header.padding.y; - button.h = header.h - 2 * style->window.header.padding.y; - button.w = button.h; - if (win->flags & NK_WINDOW_CLOSABLE) { - nk_flags ws = 0; - if (style->window.header.align == NK_HEADER_RIGHT) { - button.x = (header.w + header.x) - (button.w + style->window.header.padding.x); - header.w -= button.w + style->window.header.spacing.x + style->window.header.padding.x; - } else { - button.x = header.x + style->window.header.padding.x; - header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x; - } - - if (nk_do_button_symbol(&ws, &win->buffer, button, - style->window.header.close_symbol, NK_BUTTON_DEFAULT, - &style->window.header.close_button, in, style->font) && !(win->flags & NK_WINDOW_ROM)) - { - layout->flags |= NK_WINDOW_HIDDEN; - layout->flags &= (nk_flags)~NK_WINDOW_MINIMIZED; - } - } - - /* window minimize button */ - if (win->flags & NK_WINDOW_MINIMIZABLE) { - nk_flags ws = 0; - if (style->window.header.align == NK_HEADER_RIGHT) { - button.x = (header.w + header.x) - button.w; - if (!(win->flags & NK_WINDOW_CLOSABLE)) { - button.x -= style->window.header.padding.x; - header.w -= style->window.header.padding.x; - } - header.w -= button.w + style->window.header.spacing.x; - } else { - button.x = header.x; - header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x; - } - if (nk_do_button_symbol(&ws, &win->buffer, button, (layout->flags & NK_WINDOW_MINIMIZED)? - style->window.header.maximize_symbol: style->window.header.minimize_symbol, - NK_BUTTON_DEFAULT, &style->window.header.minimize_button, in, style->font) && !(win->flags & NK_WINDOW_ROM)) - layout->flags = (layout->flags & NK_WINDOW_MINIMIZED) ? - layout->flags & (nk_flags)~NK_WINDOW_MINIMIZED: - layout->flags | NK_WINDOW_MINIMIZED; - }} - - {/* window header title */ - int text_len = nk_strlen(title); - struct nk_rect label = {0,0,0,0}; - float t = font->width(font->userdata, font->height, title, text_len); - text.padding = nk_vec2(0,0); - - label.x = header.x + style->window.header.padding.x; - label.x += style->window.header.label_padding.x; - label.y = header.y + style->window.header.label_padding.y; - label.h = font->height + 2 * style->window.header.label_padding.y; - label.w = t + 2 * style->window.header.spacing.x; - label.w = NK_CLAMP(0, label.w, header.x + header.w - label.x); - nk_widget_text(out, label,(const char*)title, text_len, &text, NK_TEXT_LEFT, font);} - } - - /* draw window background */ - if (!(layout->flags & NK_WINDOW_MINIMIZED) && !(layout->flags & NK_WINDOW_DYNAMIC)) { - struct nk_rect body; - body.x = win->bounds.x; - body.w = win->bounds.w; - body.y = (win->bounds.y + layout->header_height); - body.h = (win->bounds.h - layout->header_height); - if (style->window.fixed_background.type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, body, &style->window.fixed_background.data.image, nk_white); - else nk_fill_rect(out, body, 0, style->window.fixed_background.data.color); - } - - /* set clipping rectangle */ - {struct nk_rect clip; - layout->clip = layout->bounds; - nk_unify(&clip, &win->buffer.clip, layout->clip.x, layout->clip.y, - layout->clip.x + layout->clip.w, layout->clip.y + layout->clip.h); - nk_push_scissor(out, clip); - layout->clip = clip;} - return !(layout->flags & NK_WINDOW_HIDDEN) && !(layout->flags & NK_WINDOW_MINIMIZED); -} - -NK_INTERN void -nk_panel_end(struct nk_context *ctx) -{ - struct nk_input *in; - struct nk_window *window; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_command_buffer *out; - - struct nk_vec2 scrollbar_size; - struct nk_vec2 panel_padding; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - window = ctx->current; - layout = window->layout; - style = &ctx->style; - out = &window->buffer; - in = (layout->flags & NK_WINDOW_ROM || layout->flags & NK_WINDOW_NO_INPUT) ? 0 :&ctx->input; - if (!nk_panel_is_sub(layout->type)) - nk_push_scissor(out, nk_null_rect); - - /* cache configuration data */ - scrollbar_size = style->window.scrollbar_size; - panel_padding = nk_panel_get_padding(style, layout->type); - - /* update the current cursor Y-position to point over the last added widget */ - layout->at_y += layout->row.height; - - /* dynamic panels */ - if (layout->flags & NK_WINDOW_DYNAMIC && !(layout->flags & NK_WINDOW_MINIMIZED)) - { - /* update panel height to fit dynamic growth */ - struct nk_rect empty_space; - if (layout->at_y < (layout->bounds.y + layout->bounds.h)) - layout->bounds.h = layout->at_y - layout->bounds.y; - - /* fill top empty space */ - empty_space.x = window->bounds.x; - empty_space.y = layout->bounds.y; - empty_space.h = panel_padding.y; - empty_space.w = window->bounds.w; - nk_fill_rect(out, empty_space, 0, style->window.background); - - /* fill left empty space */ - empty_space.x = window->bounds.x; - empty_space.y = layout->bounds.y; - empty_space.w = panel_padding.x + layout->border; - empty_space.h = layout->bounds.h; - nk_fill_rect(out, empty_space, 0, style->window.background); - - /* fill right empty space */ - empty_space.x = layout->bounds.x + layout->bounds.w - layout->border; - empty_space.y = layout->bounds.y; - empty_space.w = panel_padding.x + layout->border; - empty_space.h = layout->bounds.h; - if (*layout->offset_y == 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR)) - empty_space.w += scrollbar_size.x; - nk_fill_rect(out, empty_space, 0, style->window.background); - - /* fill bottom empty space */ - if (*layout->offset_x != 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR)) { - empty_space.x = window->bounds.x; - empty_space.y = layout->bounds.y + layout->bounds.h; - empty_space.w = window->bounds.w; - empty_space.h = scrollbar_size.y; - nk_fill_rect(out, empty_space, 0, style->window.background); - } - } - - /* scrollbars */ - if (!(layout->flags & NK_WINDOW_NO_SCROLLBAR) && - !(layout->flags & NK_WINDOW_MINIMIZED) && - window->scrollbar_hiding_timer < NK_SCROLLBAR_HIDING_TIMEOUT) - { - struct nk_rect scroll; - int scroll_has_scrolling; - float scroll_target; - float scroll_offset; - float scroll_step; - float scroll_inc; - - /* mouse wheel scrolling */ - if (nk_panel_is_sub(layout->type)) - { - /* sub-window mouse wheel scrolling */ - struct nk_window *root_window = window; - struct nk_panel *root_panel = window->layout; - while (root_panel->parent) - root_panel = root_panel->parent; - while (root_window->parent) - root_window = root_window->parent; - - /* only allow scrolling if parent window is active */ - scroll_has_scrolling = 0; - if ((root_window == ctx->active) && layout->has_scrolling) { - /* and panel is being hovered and inside clip rect*/ - if (nk_input_is_mouse_hovering_rect(in, layout->bounds) && - NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h, - root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h)) - { - /* deactivate all parent scrolling */ - root_panel = window->layout; - while (root_panel->parent) { - root_panel->has_scrolling = nk_false; - root_panel = root_panel->parent; - } - root_panel->has_scrolling = nk_false; - scroll_has_scrolling = nk_true; - } - } - } else if (!nk_panel_is_sub(layout->type)) { - /* window mouse wheel scrolling */ - scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling; - if (in && (in->mouse.scroll_delta.y > 0 || in->mouse.scroll_delta.x > 0) && scroll_has_scrolling) - window->scrolled = nk_true; - else window->scrolled = nk_false; - } else scroll_has_scrolling = nk_false; - - { - /* vertical scrollbar */ - nk_flags state = 0; - scroll.x = layout->bounds.x + layout->bounds.w + panel_padding.x; - scroll.y = layout->bounds.y; - scroll.w = scrollbar_size.x; - scroll.h = layout->bounds.h; - - scroll_offset = (float)*layout->offset_y; - scroll_step = scroll.h * 0.10f; - scroll_inc = scroll.h * 0.01f; - scroll_target = (float)(int)(layout->at_y - scroll.y); - scroll_offset = nk_do_scrollbarv(&state, out, scroll, scroll_has_scrolling, - scroll_offset, scroll_target, scroll_step, scroll_inc, - &ctx->style.scrollv, in, style->font); - *layout->offset_y = (nk_uint)scroll_offset; - if (in && scroll_has_scrolling) - in->mouse.scroll_delta.y = 0; - } - { - /* horizontal scrollbar */ - nk_flags state = 0; - scroll.x = layout->bounds.x; - scroll.y = layout->bounds.y + layout->bounds.h; - scroll.w = layout->bounds.w; - scroll.h = scrollbar_size.y; - - scroll_offset = (float)*layout->offset_x; - scroll_target = (float)(int)(layout->max_x - scroll.x); - scroll_step = layout->max_x * 0.05f; - scroll_inc = layout->max_x * 0.005f; - scroll_offset = nk_do_scrollbarh(&state, out, scroll, scroll_has_scrolling, - scroll_offset, scroll_target, scroll_step, scroll_inc, - &ctx->style.scrollh, in, style->font); - *layout->offset_x = (nk_uint)scroll_offset; - } - } - - /* hide scroll if no user input */ - if (window->flags & NK_WINDOW_SCROLL_AUTO_HIDE) { - int has_input = ctx->input.mouse.delta.x != 0 || ctx->input.mouse.delta.y != 0 || ctx->input.mouse.scroll_delta.y != 0; - int is_window_hovered = nk_window_is_hovered(ctx); - int any_item_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED); - if ((!has_input && is_window_hovered) || (!is_window_hovered && !any_item_active)) - window->scrollbar_hiding_timer += ctx->delta_time_seconds; - else window->scrollbar_hiding_timer = 0; - } else window->scrollbar_hiding_timer = 0; - - /* window border */ - if (layout->flags & NK_WINDOW_BORDER) - { - struct nk_color border_color = nk_panel_get_border_color(style, layout->type); - const float padding_y = (layout->flags & NK_WINDOW_MINIMIZED) ? - style->window.border + window->bounds.y + layout->header_height: - (layout->flags & NK_WINDOW_DYNAMIC)? - layout->bounds.y + layout->bounds.h + layout->footer_height: - window->bounds.y + window->bounds.h; - - /* draw border top */ - nk_stroke_line(out,window->bounds.x,window->bounds.y, - window->bounds.x + window->bounds.w, window->bounds.y, - layout->border, border_color); - - /* draw bottom border */ - nk_stroke_line(out, window->bounds.x, padding_y, - window->bounds.x + window->bounds.w, padding_y, layout->border, border_color); - - /* draw left border */ - nk_stroke_line(out, window->bounds.x + layout->border*0.5f, - window->bounds.y, window->bounds.x + layout->border*0.5f, - padding_y, layout->border, border_color); - - /* draw right border */ - nk_stroke_line(out, window->bounds.x + window->bounds.w - layout->border*0.5f, - window->bounds.y, window->bounds.x + window->bounds.w - layout->border*0.5f, - padding_y, layout->border, border_color); - } - - /* scaler */ - if ((layout->flags & NK_WINDOW_SCALABLE) && in && !(layout->flags & NK_WINDOW_MINIMIZED)) - { - /* calculate scaler bounds */ - struct nk_rect scaler; - scaler.w = scrollbar_size.x; - scaler.h = scrollbar_size.y; - scaler.y = layout->bounds.y + layout->bounds.h; - if (layout->flags & NK_WINDOW_SCALE_LEFT) - scaler.x = layout->bounds.x - panel_padding.x * 0.5f; - else scaler.x = layout->bounds.x + layout->bounds.w + panel_padding.x; - if (layout->flags & NK_WINDOW_NO_SCROLLBAR) - scaler.x -= scaler.w; - - /* draw scaler */ - {const struct nk_style_item *item = &style->window.scaler; - if (item->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, scaler, &item->data.image, nk_white); - else { - if (layout->flags & NK_WINDOW_SCALE_LEFT) { - nk_fill_triangle(out, scaler.x, scaler.y, scaler.x, - scaler.y + scaler.h, scaler.x + scaler.w, - scaler.y + scaler.h, item->data.color); - } else { - nk_fill_triangle(out, scaler.x + scaler.w, scaler.y, scaler.x + scaler.w, - scaler.y + scaler.h, scaler.x, scaler.y + scaler.h, item->data.color); - } - }} - - /* do window scaling */ - if (!(window->flags & NK_WINDOW_ROM)) { - struct nk_vec2 window_size = style->window.min_size; - int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; - int left_mouse_click_in_scaler = nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, scaler, nk_true); - - if (left_mouse_down && left_mouse_click_in_scaler) { - float delta_x = in->mouse.delta.x; - if (layout->flags & NK_WINDOW_SCALE_LEFT) { - delta_x = -delta_x; - window->bounds.x += in->mouse.delta.x; - } - /* dragging in x-direction */ - if (window->bounds.w + delta_x >= window_size.x) { - if ((delta_x < 0) || (delta_x > 0 && in->mouse.pos.x >= scaler.x)) { - window->bounds.w = window->bounds.w + delta_x; - scaler.x += in->mouse.delta.x; - } - } - /* dragging in y-direction (only possible if static window) */ - if (!(layout->flags & NK_WINDOW_DYNAMIC)) { - if (window_size.y < window->bounds.h + in->mouse.delta.y) { - if ((in->mouse.delta.y < 0) || (in->mouse.delta.y > 0 && in->mouse.pos.y >= scaler.y)) { - window->bounds.h = window->bounds.h + in->mouse.delta.y; - scaler.y += in->mouse.delta.y; - } - } - } - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT]; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f; - } - } - } - if (!nk_panel_is_sub(layout->type)) { - /* window is hidden so clear command buffer */ - if (layout->flags & NK_WINDOW_HIDDEN) - nk_command_buffer_reset(&window->buffer); - /* window is visible and not tab */ - else nk_finish(ctx, window); - } - - /* NK_WINDOW_REMOVE_ROM flag was set so remove NK_WINDOW_ROM */ - if (layout->flags & NK_WINDOW_REMOVE_ROM) { - layout->flags &= ~(nk_flags)NK_WINDOW_ROM; - layout->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM; - } - window->flags = layout->flags; - - /* property garbage collector */ - if (window->property.active && window->property.old != window->property.seq && - window->property.active == window->property.prev) { - nk_zero(&window->property, sizeof(window->property)); - } else { - window->property.old = window->property.seq; - window->property.prev = window->property.active; - window->property.seq = 0; - } - /* edit garbage collector */ - if (window->edit.active && window->edit.old != window->edit.seq && - window->edit.active == window->edit.prev) { - nk_zero(&window->edit, sizeof(window->edit)); - } else { - window->edit.old = window->edit.seq; - window->edit.prev = window->edit.active; - window->edit.seq = 0; - } - /* contextual garbage collector */ - if (window->popup.active_con && window->popup.con_old != window->popup.con_count) { - window->popup.con_count = 0; - window->popup.con_old = 0; - window->popup.active_con = 0; - } else { - window->popup.con_old = window->popup.con_count; - window->popup.con_count = 0; - } - window->popup.combo_count = 0; - /* helper to make sure you have a 'nk_tree_push' for every 'nk_tree_pop' */ - NK_ASSERT(!layout->row.tree_depth); -} - -/* ---------------------------------------------------------------- - * - * PAGE ELEMENT - * - * ---------------------------------------------------------------*/ -NK_INTERN struct nk_page_element* -nk_create_page_element(struct nk_context *ctx) -{ - struct nk_page_element *elem; - if (ctx->freelist) { - /* unlink page element from free list */ - elem = ctx->freelist; - ctx->freelist = elem->next; - } else if (ctx->use_pool) { - /* allocate page element from memory pool */ - elem = nk_pool_alloc(&ctx->pool); - NK_ASSERT(elem); - if (!elem) return 0; - } else { - /* allocate new page element from back of fixed size memory buffer */ - NK_STORAGE const nk_size size = sizeof(struct nk_page_element); - NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_page_element); - elem = (struct nk_page_element*)nk_buffer_alloc(&ctx->memory, NK_BUFFER_BACK, size, align); - NK_ASSERT(elem); - if (!elem) return 0; - } - nk_zero_struct(*elem); - elem->next = 0; - elem->prev = 0; - return elem; -} - -NK_INTERN void -nk_link_page_element_into_freelist(struct nk_context *ctx, - struct nk_page_element *elem) -{ - /* link table into freelist */ - if (!ctx->freelist) { - ctx->freelist = elem; - } else { - elem->next = ctx->freelist; - ctx->freelist = elem; - } -} - -NK_INTERN void -nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem) -{ - /* we have a pool so just add to free list */ - if (ctx->use_pool) { - nk_link_page_element_into_freelist(ctx, elem); - return; - } - /* if possible remove last element from back of fixed memory buffer */ - {void *elem_end = (void*)(elem + 1); - void *buffer_end = (nk_byte*)ctx->memory.memory.ptr + ctx->memory.size; - if (elem_end == buffer_end) - ctx->memory.size -= sizeof(struct nk_page_element); - else nk_link_page_element_into_freelist(ctx, elem);} -} - -/* ---------------------------------------------------------------- - * - * PANEL - * - * ---------------------------------------------------------------*/ -NK_INTERN void* -nk_create_panel(struct nk_context *ctx) -{ - struct nk_page_element *elem; - elem = nk_create_page_element(ctx); - if (!elem) return 0; - nk_zero_struct(*elem); - return &elem->data.pan; -} - -NK_INTERN void -nk_free_panel(struct nk_context *ctx, struct nk_panel *pan) -{ - union nk_page_data *pd = NK_CONTAINER_OF(pan, union nk_page_data, pan); - struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); - nk_free_page_element(ctx, pe); -} - -/* ---------------------------------------------------------------- - * - * TABLES - * - * ---------------------------------------------------------------*/ -NK_INTERN struct nk_table* -nk_create_table(struct nk_context *ctx) -{ - struct nk_page_element *elem; - elem = nk_create_page_element(ctx); - if (!elem) return 0; - nk_zero_struct(*elem); - return &elem->data.tbl; -} - -NK_INTERN void -nk_free_table(struct nk_context *ctx, struct nk_table *tbl) -{ - union nk_page_data *pd = NK_CONTAINER_OF(tbl, union nk_page_data, tbl); - struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); - nk_free_page_element(ctx, pe); -} - -NK_INTERN void -nk_push_table(struct nk_window *win, struct nk_table *tbl) -{ - if (!win->tables) { - win->tables = tbl; - tbl->next = 0; - tbl->prev = 0; - tbl->size = 0; - win->table_count = 1; - return; - } - win->tables->prev = tbl; - tbl->next = win->tables; - tbl->prev = 0; - tbl->size = 0; - win->tables = tbl; - win->table_count++; -} - -NK_INTERN void -nk_remove_table(struct nk_window *win, struct nk_table *tbl) -{ - if (win->tables == tbl) - win->tables = tbl->next; - if (tbl->next) - tbl->next->prev = tbl->prev; - if (tbl->prev) - tbl->prev->next = tbl->next; - tbl->next = 0; - tbl->prev = 0; -} - -NK_INTERN nk_uint* -nk_add_value(struct nk_context *ctx, struct nk_window *win, - nk_hash name, nk_uint value) -{ - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!win || !ctx) return 0; - if (!win->tables || win->tables->size >= NK_VALUE_PAGE_CAPACITY) { - struct nk_table *tbl = nk_create_table(ctx); - NK_ASSERT(tbl); - if (!tbl) return 0; - nk_push_table(win, tbl); - } - win->tables->seq = win->seq; - win->tables->keys[win->tables->size] = name; - win->tables->values[win->tables->size] = value; - return &win->tables->values[win->tables->size++]; -} - -NK_INTERN nk_uint* -nk_find_value(struct nk_window *win, nk_hash name) -{ - struct nk_table *iter = win->tables; - while (iter) { - unsigned int i = 0; - unsigned int size = iter->size; - for (i = 0; i < size; ++i) { - if (iter->keys[i] == name) { - iter->seq = win->seq; - return &iter->values[i]; - } - } size = NK_VALUE_PAGE_CAPACITY; - iter = iter->next; - } - return 0; -} - -/* ---------------------------------------------------------------- - * - * WINDOW - * - * ---------------------------------------------------------------*/ -NK_INTERN void* -nk_create_window(struct nk_context *ctx) -{ - struct nk_page_element *elem; - elem = nk_create_page_element(ctx); - if (!elem) return 0; - elem->data.win.seq = ctx->seq; - return &elem->data.win; -} - -NK_INTERN void -nk_free_window(struct nk_context *ctx, struct nk_window *win) -{ - /* unlink windows from list */ - struct nk_table *it = win->tables; - if (win->popup.win) { - nk_free_window(ctx, win->popup.win); - win->popup.win = 0; - } - win->next = 0; - win->prev = 0; - - while (it) { - /*free window state tables */ - struct nk_table *n = it->next; - nk_remove_table(win, it); - nk_free_table(ctx, it); - if (it == win->tables) - win->tables = n; - it = n; - } - - /* link windows into freelist */ - {union nk_page_data *pd = NK_CONTAINER_OF(win, union nk_page_data, win); - struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); - nk_free_page_element(ctx, pe);} -} - -NK_INTERN struct nk_window* -nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name) -{ - struct nk_window *iter; - iter = ctx->begin; - while (iter) { - NK_ASSERT(iter != iter->next); - if (iter->name == hash) { - int max_len = nk_strlen(iter->name_string); - if (!nk_stricmpn(iter->name_string, name, max_len)) - return iter; - } - iter = iter->next; - } - return 0; -} - -enum nk_window_insert_location { - NK_INSERT_BACK, /* inserts window into the back of list (front of screen) */ - NK_INSERT_FRONT /* inserts window into the front of list (back of screen) */ -}; -NK_INTERN void -nk_insert_window(struct nk_context *ctx, struct nk_window *win, - enum nk_window_insert_location loc) -{ - const struct nk_window *iter; - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!win || !ctx) return; - - iter = ctx->begin; - while (iter) { - NK_ASSERT(iter != iter->next); - NK_ASSERT(iter != win); - if (iter == win) return; - iter = iter->next; - } - - if (!ctx->begin) { - win->next = 0; - win->prev = 0; - ctx->begin = win; - ctx->end = win; - ctx->count = 1; - return; - } - if (loc == NK_INSERT_BACK) { - struct nk_window *end; - end = ctx->end; - end->flags |= NK_WINDOW_ROM; - end->next = win; - win->prev = ctx->end; - win->next = 0; - ctx->end = win; - ctx->active = ctx->end; - ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM; - } else { - ctx->end->flags |= NK_WINDOW_ROM; - ctx->begin->prev = win; - win->next = ctx->begin; - win->prev = 0; - ctx->begin = win; - ctx->begin->flags &= ~(nk_flags)NK_WINDOW_ROM; - } - ctx->count++; -} - -NK_INTERN void -nk_remove_window(struct nk_context *ctx, struct nk_window *win) -{ - if (win == ctx->begin || win == ctx->end) { - if (win == ctx->begin) { - ctx->begin = win->next; - if (win->next) - win->next->prev = 0; - } - if (win == ctx->end) { - ctx->end = win->prev; - if (win->prev) - win->prev->next = 0; - } - } else { - if (win->next) - win->next->prev = win->prev; - if (win->prev) - win->prev->next = win->next; - } - if (win == ctx->active || !ctx->active) { - ctx->active = ctx->end; - if (ctx->end) - ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM; - } - win->next = 0; - win->prev = 0; - ctx->count--; -} - -NK_API int -nk_begin(struct nk_context *ctx, const char *title, - struct nk_rect bounds, nk_flags flags) -{ - return nk_begin_titled(ctx, title, title, bounds, flags); -} - -NK_API int -nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, - struct nk_rect bounds, nk_flags flags) -{ - struct nk_window *win; - struct nk_style *style; - nk_hash title_hash; - int title_len; - int ret = 0; - - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(title); - NK_ASSERT(ctx->style.font && ctx->style.font->width && "if this triggers you forgot to add a font"); - NK_ASSERT(!ctx->current && "if this triggers you missed a `nk_end` call"); - if (!ctx || ctx->current || !title || !name) - return 0; - - /* find or create window */ - style = &ctx->style; - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) { - /* create new window */ - nk_size name_length = (nk_size)nk_strlen(name); - win = (struct nk_window*)nk_create_window(ctx); - NK_ASSERT(win); - if (!win) return 0; - - if (flags & NK_WINDOW_BACKGROUND) - nk_insert_window(ctx, win, NK_INSERT_FRONT); - else nk_insert_window(ctx, win, NK_INSERT_BACK); - nk_command_buffer_init(&win->buffer, &ctx->memory, NK_CLIPPING_ON); - - win->flags = flags; - win->bounds = bounds; - win->name = title_hash; - name_length = NK_MIN(name_length, NK_WINDOW_MAX_NAME-1); - NK_MEMCPY(win->name_string, name, name_length); - win->name_string[name_length] = 0; - win->popup.win = 0; - if (!ctx->active) - ctx->active = win; - } else { - /* update window */ - win->flags &= ~(nk_flags)(NK_WINDOW_PRIVATE-1); - win->flags |= flags; - if (!(win->flags & (NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE))) - win->bounds = bounds; - /* If this assert triggers you either: - * - * I.) Have more than one window with the same name or - * II.) You forgot to actually draw the window. - * More specific you did not call `nk_clear` (nk_clear will be - * automatically called for you if you are using one of the - * provided demo backends). */ - NK_ASSERT(win->seq != ctx->seq); - win->seq = ctx->seq; - if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN)) - ctx->active = win; - } - if (win->flags & NK_WINDOW_HIDDEN) { - ctx->current = win; - win->layout = 0; - return 0; - } - - /* window overlapping */ - if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT)) - { - int inpanel, ishovered; - const struct nk_window *iter = win; - float h = ctx->style.font->height + 2.0f * style->window.header.padding.y + - (2.0f * style->window.header.label_padding.y); - struct nk_rect win_bounds = (!(win->flags & NK_WINDOW_MINIMIZED))? - win->bounds: nk_rect(win->bounds.x, win->bounds.y, win->bounds.w, h); - - /* activate window if hovered and no other window is overlapping this window */ - nk_start(ctx, win); - inpanel = nk_input_has_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_LEFT, win_bounds, nk_true); - inpanel = inpanel && ctx->input.mouse.buttons[NK_BUTTON_LEFT].clicked; - ishovered = nk_input_is_mouse_hovering_rect(&ctx->input, win_bounds); - if ((win != ctx->active) && ishovered && !ctx->input.mouse.buttons[NK_BUTTON_LEFT].down) { - iter = win->next; - while (iter) { - struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))? - iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h); - if (NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, - iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) && - (!(iter->flags & NK_WINDOW_HIDDEN) || !(iter->flags & NK_WINDOW_BACKGROUND))) - break; - - if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) && - NK_INTERSECT(win->bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, - iter->popup.win->bounds.x, iter->popup.win->bounds.y, - iter->popup.win->bounds.w, iter->popup.win->bounds.h)) - break; - iter = iter->next; - } - } - - /* activate window if clicked */ - if (iter && inpanel && (win != ctx->end) && !(iter->flags & NK_WINDOW_BACKGROUND)) { - iter = win->next; - while (iter) { - /* try to find a panel with higher priority in the same position */ - struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))? - iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h); - if (NK_INBOX(ctx->input.mouse.pos.x, ctx->input.mouse.pos.y, - iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) && - !(iter->flags & NK_WINDOW_HIDDEN)) - break; - if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) && - NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, - iter->popup.win->bounds.x, iter->popup.win->bounds.y, - iter->popup.win->bounds.w, iter->popup.win->bounds.h)) - break; - iter = iter->next; - } - } - - if (!iter && ctx->end != win) { - if (!(win->flags & NK_WINDOW_BACKGROUND)) { - /* current window is active in that position so transfer to top - * at the highest priority in stack */ - nk_remove_window(ctx, win); - nk_insert_window(ctx, win, NK_INSERT_BACK); - } - win->flags &= ~(nk_flags)NK_WINDOW_ROM; - ctx->active = win; - } - if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND)) - win->flags |= NK_WINDOW_ROM; - } - - win->layout = (struct nk_panel*)nk_create_panel(ctx); - ctx->current = win; - ret = nk_panel_begin(ctx, title, NK_PANEL_WINDOW); - win->layout->offset_x = &win->scrollbar.x; - win->layout->offset_y = &win->scrollbar.y; - return ret; -} - -NK_API void -nk_end(struct nk_context *ctx) -{ - struct nk_panel *layout; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current && "if this triggers you forgot to call `nk_begin`"); - if (!ctx || !ctx->current) - return; - - layout = ctx->current->layout; - if (!layout || (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN))) { - ctx->current = 0; - return; - } - nk_panel_end(ctx); - nk_free_panel(ctx, ctx->current->layout); - ctx->current = 0; -} - -NK_API struct nk_rect -nk_window_get_bounds(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_rect(0,0,0,0); - return ctx->current->bounds; -} - -NK_API struct nk_vec2 -nk_window_get_position(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->bounds.x, ctx->current->bounds.y); -} - -NK_API struct nk_vec2 -nk_window_get_size(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->bounds.w, ctx->current->bounds.h); -} - -NK_API float -nk_window_get_width(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - return ctx->current->bounds.w; -} - -NK_API float -nk_window_get_height(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - return ctx->current->bounds.h; -} - -NK_API struct nk_rect -nk_window_get_content_region(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_rect(0,0,0,0); - return ctx->current->layout->clip; -} - -NK_API struct nk_vec2 -nk_window_get_content_region_min(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y); -} - -NK_API struct nk_vec2 -nk_window_get_content_region_max(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->layout->clip.x + ctx->current->layout->clip.w, - ctx->current->layout->clip.y + ctx->current->layout->clip.h); -} - -NK_API struct nk_vec2 -nk_window_get_content_region_size(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h); -} - -NK_API struct nk_command_buffer* -nk_window_get_canvas(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return 0; - return &ctx->current->buffer; -} - -NK_API struct nk_panel* -nk_window_get_panel(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - return ctx->current->layout; -} - -NK_API int -nk_window_has_focus(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return 0; - return ctx->current == ctx->active; -} - -NK_API int -nk_window_is_hovered(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - return nk_input_is_mouse_hovering_rect(&ctx->input, ctx->current->bounds); -} - -NK_API int -nk_window_is_any_hovered(struct nk_context *ctx) -{ - struct nk_window *iter; - NK_ASSERT(ctx); - if (!ctx) return 0; - iter = ctx->begin; - while (iter) { - /* check if window is being hovered */ - if (iter->flags & NK_WINDOW_MINIMIZED) { - struct nk_rect header = iter->bounds; - header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y; - if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) - return 1; - } else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) { - return 1; - } - /* check if window popup is being hovered */ - if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds)) - return 1; - iter = iter->next; - } - return 0; -} - -NK_API int -nk_item_is_any_active(struct nk_context *ctx) -{ - int any_hovered = nk_window_is_any_hovered(ctx); - int any_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED); - return any_hovered || any_active; -} - -NK_API int -nk_window_is_collapsed(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 0; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 0; - return win->flags & NK_WINDOW_MINIMIZED; -} - -NK_API int -nk_window_is_closed(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 1; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 1; - return (win->flags & NK_WINDOW_CLOSED); -} - -NK_API int -nk_window_is_hidden(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 1; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 1; - return (win->flags & NK_WINDOW_HIDDEN); -} - -NK_API int -nk_window_is_active(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 0; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 0; - return win == ctx->active; -} - -NK_API struct nk_window* -nk_window_find(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - return nk_find_window(ctx, title_hash, name); -} - -NK_API void -nk_window_close(struct nk_context *ctx, const char *name) -{ - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - win = nk_window_find(ctx, name); - if (!win) return; - NK_ASSERT(ctx->current != win && "You cannot close a currently active window"); - if (ctx->current == win) return; - win->flags |= NK_WINDOW_HIDDEN; - win->flags |= NK_WINDOW_CLOSED; -} - -NK_API void -nk_window_set_bounds(struct nk_context *ctx, struct nk_rect bounds) -{ - NK_ASSERT(ctx); NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - ctx->current->bounds = bounds; -} - -NK_API void -nk_window_set_position(struct nk_context *ctx, struct nk_vec2 pos) -{ - NK_ASSERT(ctx); NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - ctx->current->bounds.x = pos.x; - ctx->current->bounds.y = pos.y; -} - -NK_API void -nk_window_set_size(struct nk_context *ctx, struct nk_vec2 size) -{ - NK_ASSERT(ctx); NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - ctx->current->bounds.w = size.x; - ctx->current->bounds.h = size.y; -} - -NK_API void -nk_window_collapse(struct nk_context *ctx, const char *name, - enum nk_collapse_states c) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return; - if (c == NK_MINIMIZED) - win->flags |= NK_WINDOW_MINIMIZED; - else win->flags &= ~(nk_flags)NK_WINDOW_MINIMIZED; -} - -NK_API void -nk_window_collapse_if(struct nk_context *ctx, const char *name, - enum nk_collapse_states c, int cond) -{ - NK_ASSERT(ctx); - if (!ctx || !cond) return; - nk_window_collapse(ctx, name, c); -} - -NK_API void -nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states s) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return; - if (s == NK_HIDDEN) { - win->flags |= NK_WINDOW_HIDDEN; - } else win->flags &= ~(nk_flags)NK_WINDOW_HIDDEN; -} - -NK_API void -nk_window_show_if(struct nk_context *ctx, const char *name, - enum nk_show_states s, int cond) -{ - NK_ASSERT(ctx); - if (!ctx || !cond) return; - nk_window_show(ctx, name, s); -} - -NK_API void -nk_window_set_focus(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (win && ctx->end != win) { - nk_remove_window(ctx, win); - nk_insert_window(ctx, win, NK_INSERT_BACK); - } - ctx->active = win; -} - -/*---------------------------------------------------------------- - * - * MENUBAR - * - * --------------------------------------------------------------*/ -NK_API void -nk_menubar_begin(struct nk_context *ctx) -{ - struct nk_panel *layout; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - layout = ctx->current->layout; - NK_ASSERT(layout->at_y == layout->bounds.y); - /* if this assert triggers you allocated space between nk_begin and nk_menubar_begin. - If you want a menubar the first nuklear function after `nk_begin` has to be a - `nk_menubar_begin` call. Inside the menubar you then have to allocate space for - widgets (also supports multiple rows). - Example: - if (nk_begin(...)) { - nk_menubar_begin(...); - nk_layout_xxxx(...); - nk_button(...); - nk_layout_xxxx(...); - nk_button(...); - nk_menubar_end(...); - } - nk_end(...); - */ - if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED) - return; - - layout->menu.x = layout->at_x; - layout->menu.y = layout->at_y + layout->row.height; - layout->menu.w = layout->bounds.w; - layout->menu.offset.x = *layout->offset_x; - layout->menu.offset.y = *layout->offset_y; - *layout->offset_y = 0; -} - -NK_API void -nk_menubar_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_command_buffer *out; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - out = &win->buffer; - layout = win->layout; - if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED) - return; - - layout->menu.h = layout->at_y - layout->menu.y; - layout->bounds.y += layout->menu.h + ctx->style.window.spacing.y + layout->row.height; - layout->bounds.h -= layout->menu.h + ctx->style.window.spacing.y + layout->row.height; - - *layout->offset_x = layout->menu.offset.x; - *layout->offset_y = layout->menu.offset.y; - layout->at_y = layout->bounds.y - layout->row.height; - - layout->clip.y = layout->bounds.y; - layout->clip.h = layout->bounds.h; - nk_push_scissor(out, layout->clip); -} -/* ------------------------------------------------------------- - * - * LAYOUT - * - * --------------------------------------------------------------*/ -NK_API void -nk_layout_set_min_row_height(struct nk_context *ctx, float height) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.min_height = height; -} - -NK_API void -nk_layout_reset_min_row_height(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.min_height = ctx->style.font->height; - layout->row.min_height += ctx->style.text.padding.y*2; - layout->row.min_height += ctx->style.window.min_row_height_padding*2; -} - -NK_INTERN float -nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type, - float total_space, int columns) -{ - float panel_padding; - float panel_spacing; - float panel_space; - - struct nk_vec2 spacing; - struct nk_vec2 padding; - - spacing = style->window.spacing; - padding = nk_panel_get_padding(style, type); - - /* calculate the usable panel space */ - panel_padding = 2 * padding.x; - panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x; - panel_space = total_space - panel_padding - panel_spacing; - return panel_space; -} - -NK_INTERN void -nk_panel_layout(const struct nk_context *ctx, struct nk_window *win, - float height, int cols) -{ - struct nk_panel *layout; - const struct nk_style *style; - struct nk_command_buffer *out; - - struct nk_vec2 item_spacing; - struct nk_color color; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - /* prefetch some configuration data */ - layout = win->layout; - style = &ctx->style; - out = &win->buffer; - color = style->window.background; - item_spacing = style->window.spacing; - - /* if one of these triggers you forgot to add an `if` condition around either - a window, group, popup, combobox or contextual menu `begin` and `end` block. - Example: - if (nk_begin(...) {...} nk_end(...); or - if (nk_group_begin(...) { nk_group_end(...);} */ - NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED)); - NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN)); - NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED)); - - /* update the current row and set the current row layout */ - layout->row.index = 0; - layout->at_y += layout->row.height; - layout->row.columns = cols; - if (height == 0.0f) - layout->row.height = NK_MAX(height, layout->row.min_height) + item_spacing.y; - else layout->row.height = height + item_spacing.y; - - layout->row.item_offset = 0; - if (layout->flags & NK_WINDOW_DYNAMIC) { - /* draw background for dynamic panels */ - struct nk_rect background; - background.x = win->bounds.x; - background.w = win->bounds.w; - background.y = layout->at_y - 1.0f; - background.h = layout->row.height + 1.0f; - nk_fill_rect(out, background, 0, color); - } -} - -NK_INTERN void -nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt, - float height, int cols, int width) -{ - /* update the current row and set the current row layout */ - struct nk_window *win; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - nk_panel_layout(ctx, win, height, cols); - if (fmt == NK_DYNAMIC) - win->layout->row.type = NK_LAYOUT_DYNAMIC_FIXED; - else win->layout->row.type = NK_LAYOUT_STATIC_FIXED; - - win->layout->row.ratio = 0; - win->layout->row.filled = 0; - win->layout->row.item_offset = 0; - win->layout->row.item_width = (float)width; -} - -NK_API float -nk_layout_ratio_from_pixel(struct nk_context *ctx, float pixel_width) -{ - struct nk_window *win; - NK_ASSERT(ctx); - NK_ASSERT(pixel_width); - if (!ctx || !ctx->current || !ctx->current->layout) return 0; - win = ctx->current; - return NK_CLAMP(0.0f, pixel_width/win->bounds.x, 1.0f); -} - -NK_API void -nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols) -{ - nk_row_layout(ctx, NK_DYNAMIC, height, cols, 0); -} - -NK_API void -nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols) -{ - nk_row_layout(ctx, NK_STATIC, height, cols, item_width); -} - -NK_API void -nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, - float row_height, int cols) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, row_height, cols); - if (fmt == NK_DYNAMIC) - layout->row.type = NK_LAYOUT_DYNAMIC_ROW; - else layout->row.type = NK_LAYOUT_STATIC_ROW; - - layout->row.ratio = 0; - layout->row.filled = 0; - layout->row.item_width = 0; - layout->row.item_offset = 0; - layout->row.columns = cols; -} - -NK_API void -nk_layout_row_push(struct nk_context *ctx, float ratio_or_width) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW); - if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW) - return; - - if (layout->row.type == NK_LAYOUT_DYNAMIC_ROW) { - float ratio = ratio_or_width; - if ((ratio + layout->row.filled) > 1.0f) return; - if (ratio > 0.0f) - layout->row.item_width = NK_SATURATE(ratio); - else layout->row.item_width = 1.0f - layout->row.filled; - } else layout->row.item_width = ratio_or_width; -} - -NK_API void -nk_layout_row_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW); - if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW) - return; - layout->row.item_width = 0; - layout->row.item_offset = 0; -} - -NK_API void -nk_layout_row(struct nk_context *ctx, enum nk_layout_format fmt, - float height, int cols, const float *ratio) -{ - int i; - int n_undef = 0; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, height, cols); - if (fmt == NK_DYNAMIC) { - /* calculate width of undefined widget ratios */ - float r = 0; - layout->row.ratio = ratio; - for (i = 0; i < cols; ++i) { - if (ratio[i] < 0.0f) - n_undef++; - else r += ratio[i]; - } - r = NK_SATURATE(1.0f - r); - layout->row.type = NK_LAYOUT_DYNAMIC; - layout->row.item_width = (r > 0 && n_undef > 0) ? (r / (float)n_undef):0; - } else { - layout->row.ratio = ratio; - layout->row.type = NK_LAYOUT_STATIC; - layout->row.item_width = 0; - layout->row.item_offset = 0; - } - layout->row.item_offset = 0; - layout->row.filled = 0; -} - -NK_API void -nk_layout_row_template_begin(struct nk_context *ctx, float height) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, height, 1); - layout->row.type = NK_LAYOUT_TEMPLATE; - layout->row.columns = 0; - layout->row.ratio = 0; - layout->row.item_width = 0; - layout->row.item_height = 0; - layout->row.item_offset = 0; - layout->row.filled = 0; - layout->row.item.x = 0; - layout->row.item.y = 0; - layout->row.item.w = 0; - layout->row.item.h = 0; -} - -NK_API void -nk_layout_row_template_push_dynamic(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; - layout->row.templates[layout->row.columns++] = -1.0f; -} - -NK_API void -nk_layout_row_template_push_variable(struct nk_context *ctx, float min_width) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; - layout->row.templates[layout->row.columns++] = -min_width; -} - -NK_API void -nk_layout_row_template_push_static(struct nk_context *ctx, float width) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; - layout->row.templates[layout->row.columns++] = width; -} - -NK_API void -nk_layout_row_template_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - int i = 0; - int variable_count = 0; - int min_variable_count = 0; - float min_fixed_width = 0.0f; - float total_fixed_width = 0.0f; - float max_variable_width = 0.0f; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - for (i = 0; i < layout->row.columns; ++i) { - float width = layout->row.templates[i]; - if (width >= 0.0f) { - total_fixed_width += width; - min_fixed_width += width; - } else if (width < -1.0f) { - width = -width; - total_fixed_width += width; - max_variable_width = NK_MAX(max_variable_width, width); - variable_count++; - } else { - min_variable_count++; - variable_count++; - } - } - if (variable_count) { - float space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type, - layout->bounds.w, layout->row.columns); - float var_width = (NK_MAX(space-min_fixed_width,0.0f)) / (float)variable_count; - int enough_space = var_width >= max_variable_width; - if (!enough_space) - var_width = (NK_MAX(space-total_fixed_width,0)) / (float)min_variable_count; - for (i = 0; i < layout->row.columns; ++i) { - float *width = &layout->row.templates[i]; - *width = (*width >= 0.0f)? *width: (*width < -1.0f && !enough_space)? -(*width): var_width; - } - } -} - -NK_API void -nk_layout_space_begin(struct nk_context *ctx, enum nk_layout_format fmt, - float height, int widget_count) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, height, widget_count); - if (fmt == NK_STATIC) - layout->row.type = NK_LAYOUT_STATIC_FREE; - else layout->row.type = NK_LAYOUT_DYNAMIC_FREE; - - layout->row.ratio = 0; - layout->row.filled = 0; - layout->row.item_width = 0; - layout->row.item_offset = 0; -} - -NK_API void -nk_layout_space_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.item_width = 0; - layout->row.item_height = 0; - layout->row.item_offset = 0; - nk_zero(&layout->row.item, sizeof(layout->row.item)); -} - -NK_API void -nk_layout_space_push(struct nk_context *ctx, struct nk_rect rect) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.item = rect; -} - -NK_API struct nk_rect -nk_layout_space_bounds(struct nk_context *ctx) -{ - struct nk_rect ret; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x = layout->clip.x; - ret.y = layout->clip.y; - ret.w = layout->clip.w; - ret.h = layout->row.height; - return ret; -} - -NK_API struct nk_rect -nk_layout_widget_bounds(struct nk_context *ctx) -{ - struct nk_rect ret; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x = layout->at_x; - ret.y = layout->at_y; - ret.w = layout->bounds.w - NK_MAX(layout->at_x - layout->bounds.x,0); - ret.h = layout->row.height; - return ret; -} - -NK_API struct nk_vec2 -nk_layout_space_to_screen(struct nk_context *ctx, struct nk_vec2 ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += layout->at_x - (float)*layout->offset_x; - ret.y += layout->at_y - (float)*layout->offset_y; - return ret; -} - -NK_API struct nk_vec2 -nk_layout_space_to_local(struct nk_context *ctx, struct nk_vec2 ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += -layout->at_x + (float)*layout->offset_x; - ret.y += -layout->at_y + (float)*layout->offset_y; - return ret; -} - -NK_API struct nk_rect -nk_layout_space_rect_to_screen(struct nk_context *ctx, struct nk_rect ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += layout->at_x - (float)*layout->offset_x; - ret.y += layout->at_y - (float)*layout->offset_y; - return ret; -} - -NK_API struct nk_rect -nk_layout_space_rect_to_local(struct nk_context *ctx, struct nk_rect ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += -layout->at_x + (float)*layout->offset_x; - ret.y += -layout->at_y + (float)*layout->offset_y; - return ret; -} - -NK_INTERN void -nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win) -{ - struct nk_panel *layout = win->layout; - struct nk_vec2 spacing = ctx->style.window.spacing; - const float row_height = layout->row.height - spacing.y; - nk_panel_layout(ctx, win, row_height, layout->row.columns); -} - -NK_INTERN void -nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, - struct nk_window *win, int modify) -{ - struct nk_panel *layout; - const struct nk_style *style; - - struct nk_vec2 spacing; - struct nk_vec2 padding; - - float item_offset = 0; - float item_width = 0; - float item_spacing = 0; - float panel_space = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - NK_ASSERT(bounds); - - spacing = style->window.spacing; - padding = nk_panel_get_padding(style, layout->type); - panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type, - layout->bounds.w, layout->row.columns); - - /* calculate the width of one item inside the current layout space */ - switch (layout->row.type) { - case NK_LAYOUT_DYNAMIC_FIXED: { - /* scaling fixed size widgets item width */ - item_width = NK_MAX(1.0f,panel_space-1.0f) / (float)layout->row.columns; - item_offset = (float)layout->row.index * item_width; - item_spacing = (float)layout->row.index * spacing.x; - } break; - case NK_LAYOUT_DYNAMIC_ROW: { - /* scaling single ratio widget width */ - item_width = layout->row.item_width * panel_space; - item_offset = layout->row.item_offset; - item_spacing = 0; - - if (modify) { - layout->row.item_offset += item_width + spacing.x; - layout->row.filled += layout->row.item_width; - layout->row.index = 0; - } - } break; - case NK_LAYOUT_DYNAMIC_FREE: { - /* panel width depended free widget placing */ - bounds->x = layout->at_x + (layout->bounds.w * layout->row.item.x); - bounds->x -= (float)*layout->offset_x; - bounds->y = layout->at_y + (layout->row.height * layout->row.item.y); - bounds->y -= (float)*layout->offset_y; - bounds->w = layout->bounds.w * layout->row.item.w; - bounds->h = layout->row.height * layout->row.item.h; - return; - } break; - case NK_LAYOUT_DYNAMIC: { - /* scaling arrays of panel width ratios for every widget */ - float ratio; - NK_ASSERT(layout->row.ratio); - ratio = (layout->row.ratio[layout->row.index] < 0) ? - layout->row.item_width : layout->row.ratio[layout->row.index]; - - item_spacing = (float)layout->row.index * spacing.x; - item_width = (ratio * panel_space); - item_offset = layout->row.item_offset; - - if (modify) { - layout->row.item_offset += item_width; - layout->row.filled += ratio; - } - } break; - case NK_LAYOUT_STATIC_FIXED: { - /* non-scaling fixed widgets item width */ - item_width = layout->row.item_width; - item_offset = (float)layout->row.index * item_width; - item_spacing = (float)layout->row.index * spacing.x; - } break; - case NK_LAYOUT_STATIC_ROW: { - /* scaling single ratio widget width */ - item_width = layout->row.item_width; - item_offset = layout->row.item_offset; - item_spacing = (float)layout->row.index * spacing.x; - if (modify) layout->row.item_offset += item_width; - } break; - case NK_LAYOUT_STATIC_FREE: { - /* free widget placing */ - bounds->x = layout->at_x + layout->row.item.x; - bounds->w = layout->row.item.w; - if (((bounds->x + bounds->w) > layout->max_x) && modify) - layout->max_x = (bounds->x + bounds->w); - bounds->x -= (float)*layout->offset_x; - bounds->y = layout->at_y + layout->row.item.y; - bounds->y -= (float)*layout->offset_y; - bounds->h = layout->row.item.h; - return; - } break; - case NK_LAYOUT_STATIC: { - /* non-scaling array of panel pixel width for every widget */ - item_spacing = (float)layout->row.index * spacing.x; - item_width = layout->row.ratio[layout->row.index]; - item_offset = layout->row.item_offset; - if (modify) layout->row.item_offset += item_width; - } break; - case NK_LAYOUT_TEMPLATE: { - /* stretchy row layout with combined dynamic/static widget width*/ - NK_ASSERT(layout->row.index < layout->row.columns); - NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - item_width = layout->row.templates[layout->row.index]; - item_offset = layout->row.item_offset; - item_spacing = (float)layout->row.index * spacing.x; - if (modify) layout->row.item_offset += item_width; - } break; - default: NK_ASSERT(0); break; - }; - - /* set the bounds of the newly allocated widget */ - bounds->w = item_width; - bounds->h = layout->row.height - spacing.y; - bounds->y = layout->at_y - (float)*layout->offset_y; - bounds->x = layout->at_x + item_offset + item_spacing + padding.x; - if (((bounds->x + bounds->w) > layout->max_x) && modify) - layout->max_x = bounds->x + bounds->w; - bounds->x -= (float)*layout->offset_x; -} - -NK_INTERN void -nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - /* check if the end of the row has been hit and begin new row if so */ - win = ctx->current; - layout = win->layout; - if (layout->row.index >= layout->row.columns) - nk_panel_alloc_row(ctx, win); - - /* calculate widget position and size */ - nk_layout_widget_space(bounds, ctx, win, nk_true); - layout->row.index++; -} - -NK_INTERN void -nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx) -{ - float y; - int index; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - y = layout->at_y; - index = layout->row.index; - if (layout->row.index >= layout->row.columns) { - layout->at_y += layout->row.height; - layout->row.index = 0; - } - nk_layout_widget_space(bounds, ctx, win, nk_false); - layout->at_y = y; - layout->row.index = index; -} - -NK_INTERN int -nk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image *img, const char *title, enum nk_collapse_states *state) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_command_buffer *out; - const struct nk_input *in; - const struct nk_style_button *button; - enum nk_symbol_type symbol; - float row_height; - - struct nk_vec2 item_spacing; - struct nk_rect header = {0,0,0,0}; - struct nk_rect sym = {0,0,0,0}; - struct nk_text text; - - nk_flags ws = 0; - enum nk_widget_layout_states widget_state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - /* cache some data */ - win = ctx->current; - layout = win->layout; - out = &win->buffer; - style = &ctx->style; - item_spacing = style->window.spacing; - - /* calculate header bounds and draw background */ - row_height = style->font->height + 2 * style->tab.padding.y; - nk_layout_set_min_row_height(ctx, row_height); - nk_layout_row_dynamic(ctx, row_height, 1); - nk_layout_reset_min_row_height(ctx); - - widget_state = nk_widget(&header, ctx); - if (type == NK_TREE_TAB) { - const struct nk_style_item *background = &style->tab.background; - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, header, &background->data.image, nk_white); - text.background = nk_rgba(0,0,0,0); - } else { - text.background = background->data.color; - nk_fill_rect(out, header, 0, style->tab.border_color); - nk_fill_rect(out, nk_shrink_rect(header, style->tab.border), - style->tab.rounding, background->data.color); - } - } else text.background = style->window.background; - - /* update node state */ - in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0; - in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0; - if (nk_button_behavior(&ws, header, in, NK_BUTTON_DEFAULT)) - *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED; - - /* select correct button style */ - if (*state == NK_MAXIMIZED) { - symbol = style->tab.sym_maximize; - if (type == NK_TREE_TAB) - button = &style->tab.tab_maximize_button; - else button = &style->tab.node_maximize_button; - } else { - symbol = style->tab.sym_minimize; - if (type == NK_TREE_TAB) - button = &style->tab.tab_minimize_button; - else button = &style->tab.node_minimize_button; - } - - {/* draw triangle button */ - sym.w = sym.h = style->font->height; - sym.y = header.y + style->tab.padding.y; - sym.x = header.x + style->tab.padding.x; - nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT, - button, 0, style->font); - - if (img) { - /* draw optional image icon */ - sym.x = sym.x + sym.w + 4 * item_spacing.x; - nk_draw_image(&win->buffer, sym, img, nk_white); - sym.w = style->font->height + style->tab.spacing.x;} - } - - {/* draw label */ - struct nk_rect label; - header.w = NK_MAX(header.w, sym.w + item_spacing.x); - label.x = sym.x + sym.w + item_spacing.x; - label.y = sym.y; - label.w = header.w - (sym.w + item_spacing.y + style->tab.indent); - label.h = style->font->height; - text.text = style->tab.text; - text.padding = nk_vec2(0,0); - nk_widget_text(out, label, title, nk_strlen(title), &text, - NK_TEXT_LEFT, style->font);} - - /* increase x-axis cursor widget position pointer */ - if (*state == NK_MAXIMIZED) { - layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent; - layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent); - layout->bounds.w -= (style->tab.indent + style->window.padding.x); - layout->row.tree_depth++; - return nk_true; - } else return nk_false; -} - -NK_INTERN int -nk_tree_base(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image *img, const char *title, enum nk_collapse_states initial_state, - const char *hash, int len, int line) -{ - struct nk_window *win = ctx->current; - int title_len = 0; - nk_hash tree_hash = 0; - nk_uint *state = 0; - - /* retrieve tree state from internal widget state tables */ - if (!hash) { - title_len = (int)nk_strlen(title); - tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line); - } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line); - state = nk_find_value(win, tree_hash); - if (!state) { - state = nk_add_value(ctx, win, tree_hash, 0); - *state = initial_state; - } - return nk_tree_state_base(ctx, type, img, title, (enum nk_collapse_states*)state); -} - -NK_API int -nk_tree_state_push(struct nk_context *ctx, enum nk_tree_type type, - const char *title, enum nk_collapse_states *state) -{return nk_tree_state_base(ctx, type, 0, title, state);} - -NK_API int -nk_tree_state_image_push(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image img, const char *title, enum nk_collapse_states *state) -{return nk_tree_state_base(ctx, type, &img, title, state);} - -NK_API void -nk_tree_state_pop(struct nk_context *ctx) -{ - struct nk_window *win = 0; - struct nk_panel *layout = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->at_x -= ctx->style.tab.indent + ctx->style.window.padding.x; - layout->bounds.w += ctx->style.tab.indent + ctx->style.window.padding.x; - NK_ASSERT(layout->row.tree_depth); - layout->row.tree_depth--; -} - -NK_API int -nk_tree_push_hashed(struct nk_context *ctx, enum nk_tree_type type, - const char *title, enum nk_collapse_states initial_state, - const char *hash, int len, int line) -{return nk_tree_base(ctx, type, 0, title, initial_state, hash, len, line);} - -NK_API int -nk_tree_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image img, const char *title, enum nk_collapse_states initial_state, - const char *hash, int len,int seed) -{return nk_tree_base(ctx, type, &img, title, initial_state, hash, len, seed);} - -NK_API void -nk_tree_pop(struct nk_context *ctx) -{nk_tree_state_pop(ctx);} - -/*---------------------------------------------------------------- - * - * WIDGETS - * - * --------------------------------------------------------------*/ -NK_API struct nk_rect -nk_widget_bounds(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return nk_rect(0,0,0,0); - nk_layout_peek(&bounds, ctx); - return bounds; -} - -NK_API struct nk_vec2 -nk_widget_position(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return nk_vec2(0,0); - - nk_layout_peek(&bounds, ctx); - return nk_vec2(bounds.x, bounds.y); -} - -NK_API struct nk_vec2 -nk_widget_size(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return nk_vec2(0,0); - - nk_layout_peek(&bounds, ctx); - return nk_vec2(bounds.w, bounds.h); -} - -NK_API float -nk_widget_width(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return 0; - - nk_layout_peek(&bounds, ctx); - return bounds.w; -} - -NK_API float -nk_widget_height(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return 0; - - nk_layout_peek(&bounds, ctx); - return bounds.h; -} - -NK_API int -nk_widget_is_hovered(struct nk_context *ctx) -{ - struct nk_rect c, v; - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current || ctx->active != ctx->current) - return 0; - - c = ctx->current->layout->clip; - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_layout_peek(&bounds, ctx); - nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) - return 0; - return nk_input_is_mouse_hovering_rect(&ctx->input, bounds); -} - -NK_API int -nk_widget_is_mouse_clicked(struct nk_context *ctx, enum nk_buttons btn) -{ - struct nk_rect c, v; - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current || ctx->active != ctx->current) - return 0; - - c = ctx->current->layout->clip; - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_layout_peek(&bounds, ctx); - nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) - return 0; - return nk_input_mouse_clicked(&ctx->input, btn, bounds); -} - -NK_API int -nk_widget_has_mouse_click_down(struct nk_context *ctx, enum nk_buttons btn, int down) -{ - struct nk_rect c, v; - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current || ctx->active != ctx->current) - return 0; - - c = ctx->current->layout->clip; - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_layout_peek(&bounds, ctx); - nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) - return 0; - return nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down); -} - -NK_API enum nk_widget_layout_states -nk_widget(struct nk_rect *bounds, const struct nk_context *ctx) -{ - struct nk_rect c, v; - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return NK_WIDGET_INVALID; - - /* allocate space and check if the widget needs to be updated and drawn */ - nk_panel_alloc_space(bounds, ctx); - win = ctx->current; - layout = win->layout; - in = &ctx->input; - c = layout->clip; - - /* if one of these triggers you forgot to add an `if` condition around either - a window, group, popup, combobox or contextual menu `begin` and `end` block. - Example: - if (nk_begin(...) {...} nk_end(...); or - if (nk_group_begin(...) { nk_group_end(...);} */ - NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED)); - NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN)); - NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED)); - - /* need to convert to int here to remove floating point errors */ - bounds->x = (float)((int)bounds->x); - bounds->y = (float)((int)bounds->y); - bounds->w = (float)((int)bounds->w); - bounds->h = (float)((int)bounds->h); - - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_unify(&v, &c, bounds->x, bounds->y, bounds->x + bounds->w, bounds->y + bounds->h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h)) - return NK_WIDGET_INVALID; - if (!NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, v.x, v.y, v.w, v.h)) - return NK_WIDGET_ROM; - return NK_WIDGET_VALID; -} - -NK_API enum nk_widget_layout_states -nk_widget_fitting(struct nk_rect *bounds, struct nk_context *ctx, - struct nk_vec2 item_padding) -{ - /* update the bounds to stand without padding */ - struct nk_window *win; - struct nk_style *style; - struct nk_panel *layout; - enum nk_widget_layout_states state; - struct nk_vec2 panel_padding; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return NK_WIDGET_INVALID; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - state = nk_widget(bounds, ctx); - - panel_padding = nk_panel_get_padding(style, layout->type); - if (layout->row.index == 1) { - bounds->w += panel_padding.x; - bounds->x -= panel_padding.x; - } else bounds->x -= item_padding.x; - - if (layout->row.index == layout->row.columns) - bounds->w += panel_padding.x; - else bounds->w += item_padding.x; - return state; -} - -/*---------------------------------------------------------------- - * - * MISC - * - * --------------------------------------------------------------*/ -NK_API void -nk_spacing(struct nk_context *ctx, int cols) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_rect none; - int i, index, rows; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - /* spacing over row boundaries */ - win = ctx->current; - layout = win->layout; - index = (layout->row.index + cols) % layout->row.columns; - rows = (layout->row.index + cols) / layout->row.columns; - if (rows) { - for (i = 0; i < rows; ++i) - nk_panel_alloc_row(ctx, win); - cols = index; - } - /* non table layout need to allocate space */ - if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED && - layout->row.type != NK_LAYOUT_STATIC_FIXED) { - for (i = 0; i < cols; ++i) - nk_panel_alloc_space(&none, ctx); - } - layout->row.index = index; -} - -/*---------------------------------------------------------------- - * - * TEXT - * - * --------------------------------------------------------------*/ -NK_API void -nk_text_colored(struct nk_context *ctx, const char *str, int len, - nk_flags alignment, struct nk_color color) -{ - struct nk_window *win; - const struct nk_style *style; - - struct nk_vec2 item_padding; - struct nk_rect bounds; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - style = &ctx->style; - nk_panel_alloc_space(&bounds, ctx); - item_padding = style->text.padding; - - text.padding.x = item_padding.x; - text.padding.y = item_padding.y; - text.background = style->window.background; - text.text = color; - nk_widget_text(&win->buffer, bounds, str, len, &text, alignment, style->font); -} - -NK_API void -nk_text_wrap_colored(struct nk_context *ctx, const char *str, - int len, struct nk_color color) -{ - struct nk_window *win; - const struct nk_style *style; - - struct nk_vec2 item_padding; - struct nk_rect bounds; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - style = &ctx->style; - nk_panel_alloc_space(&bounds, ctx); - item_padding = style->text.padding; - - text.padding.x = item_padding.x; - text.padding.y = item_padding.y; - text.background = style->window.background; - text.text = color; - nk_widget_text_wrap(&win->buffer, bounds, str, len, &text, style->font); -} - -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_API void -nk_labelf_colored(struct nk_context *ctx, nk_flags flags, - struct nk_color color, const char *fmt, ...) -{ - char buf[256]; - va_list args; - va_start(args, fmt); - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label_colored(ctx, buf, flags, color); - va_end(args); -} - -NK_API void -nk_labelf_colored_wrap(struct nk_context *ctx, struct nk_color color, - const char *fmt, ...) -{ - char buf[256]; - va_list args; - va_start(args, fmt); - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label_colored_wrap(ctx, buf, color); - va_end(args); -} - -NK_API void -nk_labelf(struct nk_context *ctx, nk_flags flags, const char *fmt, ...) -{ - char buf[256]; - va_list args; - va_start(args, fmt); - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label(ctx, buf, flags); - va_end(args); -} - -NK_API void -nk_labelf_wrap(struct nk_context *ctx, const char *fmt,...) -{ - char buf[256]; - va_list args; - va_start(args, fmt); - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label_wrap(ctx, buf); - va_end(args); -} - -NK_API void -nk_value_bool(struct nk_context *ctx, const char *prefix, int value) -{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, ((value) ? "true": "false"));} - -NK_API void -nk_value_int(struct nk_context *ctx, const char *prefix, int value) -{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %d", prefix, value);} - -NK_API void -nk_value_uint(struct nk_context *ctx, const char *prefix, unsigned int value) -{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %u", prefix, value);} - -NK_API void -nk_value_float(struct nk_context *ctx, const char *prefix, float value) -{ - double double_value = (double)value; - nk_labelf(ctx, NK_TEXT_LEFT, "%s: %.3f", prefix, double_value); -} - -NK_API void -nk_value_color_byte(struct nk_context *ctx, const char *p, struct nk_color c) -{nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%d, %d, %d, %d)", p, c.r, c.g, c.b, c.a);} - -NK_API void -nk_value_color_float(struct nk_context *ctx, const char *p, struct nk_color color) -{ - double c[4]; nk_color_dv(c, color); - nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%.2f, %.2f, %.2f, %.2f)", - p, c[0], c[1], c[2], c[3]); -} - -NK_API void -nk_value_color_hex(struct nk_context *ctx, const char *prefix, struct nk_color color) -{ - char hex[16]; - nk_color_hex_rgba(hex, color); - nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, hex); -} -#endif - -NK_API void -nk_text(struct nk_context *ctx, const char *str, int len, nk_flags alignment) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_text_colored(ctx, str, len, alignment, ctx->style.text.color); -} - -NK_API void -nk_text_wrap(struct nk_context *ctx, const char *str, int len) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_text_wrap_colored(ctx, str, len, ctx->style.text.color); -} - -NK_API void -nk_label(struct nk_context *ctx, const char *str, nk_flags alignment) -{nk_text(ctx, str, nk_strlen(str), alignment);} - -NK_API void -nk_label_colored(struct nk_context *ctx, const char *str, nk_flags align, - struct nk_color color) -{nk_text_colored(ctx, str, nk_strlen(str), align, color);} - -NK_API void -nk_label_wrap(struct nk_context *ctx, const char *str) -{nk_text_wrap(ctx, str, nk_strlen(str));} - -NK_API void -nk_label_colored_wrap(struct nk_context *ctx, const char *str, struct nk_color color) -{nk_text_wrap_colored(ctx, str, nk_strlen(str), color);} - -NK_API void -nk_image(struct nk_context *ctx, struct nk_image img) -{ - struct nk_window *win; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - if (!nk_widget(&bounds, ctx)) return; - nk_draw_image(&win->buffer, bounds, &img, nk_white); -} - -/*---------------------------------------------------------------- - * - * BUTTON - * - * --------------------------------------------------------------*/ -NK_API void -nk_button_set_behavior(struct nk_context *ctx, enum nk_button_behavior behavior) -{ - NK_ASSERT(ctx); - if (!ctx) return; - ctx->button_behavior = behavior; -} - -NK_API int -nk_button_push_behavior(struct nk_context *ctx, enum nk_button_behavior behavior) -{ - struct nk_config_stack_button_behavior *button_stack; - struct nk_config_stack_button_behavior_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - button_stack = &ctx->stacks.button_behaviors; - NK_ASSERT(button_stack->head < (int)NK_LEN(button_stack->elements)); - if (button_stack->head >= (int)NK_LEN(button_stack->elements)) - return 0; - - element = &button_stack->elements[button_stack->head++]; - element->address = &ctx->button_behavior; - element->old_value = ctx->button_behavior; - ctx->button_behavior = behavior; - return 1; -} - -NK_API int -nk_button_pop_behavior(struct nk_context *ctx) -{ - struct nk_config_stack_button_behavior *button_stack; - struct nk_config_stack_button_behavior_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - button_stack = &ctx->stacks.button_behaviors; - NK_ASSERT(button_stack->head > 0); - if (button_stack->head < 1) - return 0; - - element = &button_stack->elements[--button_stack->head]; - *element->address = element->old_value; - return 1; -} - -NK_API int -nk_button_text_styled(struct nk_context *ctx, - const struct nk_style_button *style, const char *title, int len) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(style); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!style || !ctx || !ctx->current || !ctx->current->layout) return 0; - - win = ctx->current; - layout = win->layout; - state = nk_widget(&bounds, ctx); - - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds, - title, len, style->text_alignment, ctx->button_behavior, - style, in, ctx->style.font); -} - -NK_API int -nk_button_text(struct nk_context *ctx, const char *title, int len) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_text_styled(ctx, &ctx->style.button, title, len); -} - -NK_API int nk_button_label_styled(struct nk_context *ctx, - const struct nk_style_button *style, const char *title) -{return nk_button_text_styled(ctx, style, title, nk_strlen(title));} - -NK_API int nk_button_label(struct nk_context *ctx, const char *title) -{return nk_button_text(ctx, title, nk_strlen(title));} - -NK_API int -nk_button_color(struct nk_context *ctx, struct nk_color color) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - struct nk_style_button button; - - int ret = 0; - struct nk_rect bounds; - struct nk_rect content; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - button = ctx->style.button; - button.normal = nk_style_item_color(color); - button.hover = nk_style_item_color(color); - button.active = nk_style_item_color(color); - ret = nk_do_button(&ctx->last_widget_state, &win->buffer, bounds, - &button, in, ctx->button_behavior, &content); - nk_draw_button(&win->buffer, &bounds, ctx->last_widget_state, &button); - return ret; -} - -NK_API int -nk_button_symbol_styled(struct nk_context *ctx, - const struct nk_style_button *style, enum nk_symbol_type symbol) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, bounds, - symbol, ctx->button_behavior, style, in, ctx->style.font); -} - -NK_API int -nk_button_symbol(struct nk_context *ctx, enum nk_symbol_type symbol) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_symbol_styled(ctx, &ctx->style.button, symbol); -} - -NK_API int -nk_button_image_styled(struct nk_context *ctx, const struct nk_style_button *style, - struct nk_image img) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_image(&ctx->last_widget_state, &win->buffer, bounds, - img, ctx->button_behavior, style, in); -} - -NK_API int -nk_button_image(struct nk_context *ctx, struct nk_image img) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_image_styled(ctx, &ctx->style.button, img); -} - -NK_API int -nk_button_symbol_text_styled(struct nk_context *ctx, - const struct nk_style_button *style, enum nk_symbol_type symbol, - const char *text, int len, nk_flags align) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds, - symbol, text, len, align, ctx->button_behavior, - style, ctx->style.font, in); -} - -NK_API int -nk_button_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol, - const char* text, int len, nk_flags align) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_symbol_text_styled(ctx, &ctx->style.button, symbol, text, len, align); -} - -NK_API int nk_button_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol, - const char *label, nk_flags align) -{return nk_button_symbol_text(ctx, symbol, label, nk_strlen(label), align);} - -NK_API int nk_button_symbol_label_styled(struct nk_context *ctx, - const struct nk_style_button *style, enum nk_symbol_type symbol, - const char *title, nk_flags align) -{return nk_button_symbol_text_styled(ctx, style, symbol, title, nk_strlen(title), align);} - -NK_API int -nk_button_image_text_styled(struct nk_context *ctx, - const struct nk_style_button *style, struct nk_image img, const char *text, - int len, nk_flags align) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, - bounds, img, text, len, align, ctx->button_behavior, - style, ctx->style.font, in); -} - -NK_API int -nk_button_image_text(struct nk_context *ctx, struct nk_image img, - const char *text, int len, nk_flags align) -{return nk_button_image_text_styled(ctx, &ctx->style.button,img, text, len, align);} - - -NK_API int nk_button_image_label(struct nk_context *ctx, struct nk_image img, - const char *label, nk_flags align) -{return nk_button_image_text(ctx, img, label, nk_strlen(label), align);} - -NK_API int nk_button_image_label_styled(struct nk_context *ctx, - const struct nk_style_button *style, struct nk_image img, - const char *label, nk_flags text_alignment) -{return nk_button_image_text_styled(ctx, style, img, label, nk_strlen(label), text_alignment);} - -/*---------------------------------------------------------------- - * - * SELECTABLE - * - * --------------------------------------------------------------*/ -NK_API int -nk_selectable_text(struct nk_context *ctx, const char *str, int len, - nk_flags align, int *value) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(value); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !value) - return 0; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds, - str, len, align, value, &style->selectable, in, style->font); -} - -NK_API int -nk_selectable_image_text(struct nk_context *ctx, struct nk_image img, - const char *str, int len, nk_flags align, int *value) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(value); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !value) - return 0; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_selectable_image(&ctx->last_widget_state, &win->buffer, bounds, - str, len, align, value, &img, &style->selectable, in, style->font); -} - -NK_API int nk_select_text(struct nk_context *ctx, const char *str, int len, - nk_flags align, int value) -{nk_selectable_text(ctx, str, len, align, &value);return value;} - -NK_API int nk_selectable_label(struct nk_context *ctx, const char *str, nk_flags align, int *value) -{return nk_selectable_text(ctx, str, nk_strlen(str), align, value);} - -NK_API int nk_selectable_image_label(struct nk_context *ctx,struct nk_image img, - const char *str, nk_flags align, int *value) -{return nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, value);} - -NK_API int nk_select_label(struct nk_context *ctx, const char *str, nk_flags align, int value) -{nk_selectable_text(ctx, str, nk_strlen(str), align, &value);return value;} - -NK_API int nk_select_image_label(struct nk_context *ctx, struct nk_image img, - const char *str, nk_flags align, int value) -{nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, &value);return value;} - -NK_API int nk_select_image_text(struct nk_context *ctx, struct nk_image img, - const char *str, int len, nk_flags align, int value) -{nk_selectable_image_text(ctx, img, str, len, align, &value);return value;} - -/*---------------------------------------------------------------- - * - * CHECKBOX - * - * --------------------------------------------------------------*/ -NK_API int -nk_check_text(struct nk_context *ctx, const char *text, int len, int active) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return active; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return active; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active, - text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font); - return active; -} - -NK_API unsigned int -nk_check_flags_text(struct nk_context *ctx, const char *text, int len, - unsigned int flags, unsigned int value) -{ - int old_active; - NK_ASSERT(ctx); - NK_ASSERT(text); - if (!ctx || !text) return flags; - old_active = (int)((flags & value) & value); - if (nk_check_text(ctx, text, len, old_active)) - flags |= value; - else flags &= ~value; - return flags; -} - -NK_API int -nk_checkbox_text(struct nk_context *ctx, const char *text, int len, int *active) -{ - int old_val; - NK_ASSERT(ctx); - NK_ASSERT(text); - NK_ASSERT(active); - if (!ctx || !text || !active) return 0; - old_val = *active; - *active = nk_check_text(ctx, text, len, *active); - return old_val != *active; -} - -NK_API int -nk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len, - unsigned int *flags, unsigned int value) -{ - int active; - NK_ASSERT(ctx); - NK_ASSERT(text); - NK_ASSERT(flags); - if (!ctx || !text || !flags) return 0; - - active = (int)((*flags & value) & value); - if (nk_checkbox_text(ctx, text, len, &active)) { - if (active) *flags |= value; - else *flags &= ~value; - return 1; - } - return 0; -} - -NK_API int nk_check_label(struct nk_context *ctx, const char *label, int active) -{return nk_check_text(ctx, label, nk_strlen(label), active);} - -NK_API unsigned int nk_check_flags_label(struct nk_context *ctx, const char *label, - unsigned int flags, unsigned int value) -{return nk_check_flags_text(ctx, label, nk_strlen(label), flags, value);} - -NK_API int nk_checkbox_label(struct nk_context *ctx, const char *label, int *active) -{return nk_checkbox_text(ctx, label, nk_strlen(label), active);} - -NK_API int nk_checkbox_flags_label(struct nk_context *ctx, const char *label, - unsigned int *flags, unsigned int value) -{return nk_checkbox_flags_text(ctx, label, nk_strlen(label), flags, value);} - -/*---------------------------------------------------------------- - * - * OPTION - * - * --------------------------------------------------------------*/ -NK_API int -nk_option_text(struct nk_context *ctx, const char *text, int len, int is_active) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return is_active; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return state; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active, - text, len, NK_TOGGLE_OPTION, &style->option, in, style->font); - return is_active; -} - -NK_API int -nk_radio_text(struct nk_context *ctx, const char *text, int len, int *active) -{ - int old_value; - NK_ASSERT(ctx); - NK_ASSERT(text); - NK_ASSERT(active); - if (!ctx || !text || !active) return 0; - old_value = *active; - *active = nk_option_text(ctx, text, len, old_value); - return old_value != *active; -} - -NK_API int -nk_option_label(struct nk_context *ctx, const char *label, int active) -{return nk_option_text(ctx, label, nk_strlen(label), active);} - -NK_API int -nk_radio_label(struct nk_context *ctx, const char *label, int *active) -{return nk_radio_text(ctx, label, nk_strlen(label), active);} - -/*---------------------------------------------------------------- - * - * SLIDER - * - * --------------------------------------------------------------*/ -NK_API int -nk_slider_float(struct nk_context *ctx, float min_value, float *value, float max_value, - float value_step) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_input *in; - const struct nk_style *style; - - int ret = 0; - float old_value; - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(value); - if (!ctx || !ctx->current || !ctx->current->layout || !value) - return ret; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return ret; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - old_value = *value; - *value = nk_do_slider(&ctx->last_widget_state, &win->buffer, bounds, min_value, - old_value, max_value, value_step, &style->slider, in, style->font); - return (old_value > *value || old_value < *value); -} - -NK_API float -nk_slide_float(struct nk_context *ctx, float min, float val, float max, float step) -{ - nk_slider_float(ctx, min, &val, max, step); return val; -} - -NK_API int -nk_slide_int(struct nk_context *ctx, int min, int val, int max, int step) -{ - float value = (float)val; - nk_slider_float(ctx, (float)min, &value, (float)max, (float)step); - return (int)value; -} - -NK_API int -nk_slider_int(struct nk_context *ctx, int min, int *val, int max, int step) -{ - int ret; - float value = (float)*val; - ret = nk_slider_float(ctx, (float)min, &value, (float)max, (float)step); - *val = (int)value; - return ret; -} - -/*---------------------------------------------------------------- - * - * PROGRESSBAR - * - * --------------------------------------------------------------*/ -NK_API int -nk_progress(struct nk_context *ctx, nk_size *cur, nk_size max, int is_modifyable) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *style; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - nk_size old_value; - - NK_ASSERT(ctx); - NK_ASSERT(cur); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !cur) - return 0; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - state = nk_widget(&bounds, ctx); - if (!state) return 0; - - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - old_value = *cur; - *cur = nk_do_progress(&ctx->last_widget_state, &win->buffer, bounds, - *cur, max, is_modifyable, &style->progress, in); - return (*cur != old_value); -} - -NK_API nk_size nk_prog(struct nk_context *ctx, nk_size cur, nk_size max, int modifyable) -{nk_progress(ctx, &cur, max, modifyable);return cur;} - -/*---------------------------------------------------------------- - * - * EDIT - * - * --------------------------------------------------------------*/ -NK_API void -nk_edit_focus(struct nk_context *ctx, nk_flags flags) -{ - nk_hash hash; - struct nk_window *win; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - - win = ctx->current; - hash = win->edit.seq; - win->edit.active = nk_true; - win->edit.name = hash; - if (flags & NK_EDIT_ALWAYS_INSERT_MODE) - win->edit.mode = NK_TEXT_EDIT_MODE_INSERT; -} - -NK_API void -nk_edit_unfocus(struct nk_context *ctx) -{ - struct nk_window *win; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - - win = ctx->current; - win->edit.active = nk_false; - win->edit.name = 0; -} - -NK_API nk_flags -nk_edit_string(struct nk_context *ctx, nk_flags flags, - char *memory, int *len, int max, nk_plugin_filter filter) -{ - nk_hash hash; - nk_flags state; - struct nk_text_edit *edit; - struct nk_window *win; - - NK_ASSERT(ctx); - NK_ASSERT(memory); - NK_ASSERT(len); - if (!ctx || !memory || !len) - return 0; - - filter = (!filter) ? nk_filter_default: filter; - win = ctx->current; - hash = win->edit.seq; - edit = &ctx->text_edit; - nk_textedit_clear_state(&ctx->text_edit, (flags & NK_EDIT_MULTILINE)? - NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE, filter); - - if (win->edit.active && hash == win->edit.name) { - if (flags & NK_EDIT_NO_CURSOR) - edit->cursor = nk_utf_len(memory, *len); - else edit->cursor = win->edit.cursor; - if (!(flags & NK_EDIT_SELECTABLE)) { - edit->select_start = win->edit.cursor; - edit->select_end = win->edit.cursor; - } else { - edit->select_start = win->edit.sel_start; - edit->select_end = win->edit.sel_end; - } - edit->mode = win->edit.mode; - edit->scrollbar.x = (float)win->edit.scrollbar.x; - edit->scrollbar.y = (float)win->edit.scrollbar.y; - edit->active = nk_true; - } else edit->active = nk_false; - - max = NK_MAX(1, max); - *len = NK_MIN(*len, max-1); - nk_str_init_fixed(&edit->string, memory, (nk_size)max); - edit->string.buffer.allocated = (nk_size)*len; - edit->string.len = nk_utf_len(memory, *len); - state = nk_edit_buffer(ctx, flags, edit, filter); - *len = (int)edit->string.buffer.allocated; - - if (edit->active) { - win->edit.cursor = edit->cursor; - win->edit.sel_start = edit->select_start; - win->edit.sel_end = edit->select_end; - win->edit.mode = edit->mode; - win->edit.scrollbar.x = (nk_ushort)edit->scrollbar.x; - win->edit.scrollbar.y = (nk_ushort)edit->scrollbar.y; - } - return state; -} - -NK_API nk_flags -nk_edit_buffer(struct nk_context *ctx, nk_flags flags, - struct nk_text_edit *edit, nk_plugin_filter filter) -{ - struct nk_window *win; - struct nk_style *style; - struct nk_input *in; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - nk_flags ret_flags = 0; - unsigned char prev_state; - nk_hash hash; - - /* make sure correct values */ - NK_ASSERT(ctx); - NK_ASSERT(edit); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget(&bounds, ctx); - if (!state) return state; - in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - /* check if edit is currently hot item */ - hash = win->edit.seq++; - if (win->edit.active && hash == win->edit.name) { - if (flags & NK_EDIT_NO_CURSOR) - edit->cursor = edit->string.len; - if (!(flags & NK_EDIT_SELECTABLE)) { - edit->select_start = edit->cursor; - edit->select_end = edit->cursor; - } - if (flags & NK_EDIT_CLIPBOARD) - edit->clip = ctx->clip; - } - - filter = (!filter) ? nk_filter_default: filter; - prev_state = (unsigned char)edit->active; - in = (flags & NK_EDIT_READ_ONLY) ? 0: in; - ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags, - filter, edit, &style->edit, in, style->font); - - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT]; - if (edit->active && prev_state != edit->active) { - /* current edit is now hot */ - win->edit.active = nk_true; - win->edit.name = hash; - } else if (prev_state && !edit->active) { - /* current edit is now cold */ - win->edit.active = nk_false; - } - return ret_flags; -} - -NK_API nk_flags -nk_edit_string_zero_terminated(struct nk_context *ctx, nk_flags flags, - char *buffer, int max, nk_plugin_filter filter) -{ - nk_flags result; - int len = nk_strlen(buffer); - result = nk_edit_string(ctx, flags, buffer, &len, max, filter); - buffer[NK_MIN(NK_MAX(max-1,0), len)] = '\0'; - return result; -} - -/*---------------------------------------------------------------- - * - * PROPERTY - * - * --------------------------------------------------------------*/ -NK_INTERN struct nk_property_variant -nk_property_variant_int(int value, int min_value, int max_value, int step) -{ - struct nk_property_variant result; - result.kind = NK_PROPERTY_INT; - result.value.i = value; - result.min_value.i = min_value; - result.max_value.i = max_value; - result.step.i = step; - return result; -} - -NK_INTERN struct nk_property_variant -nk_property_variant_float(float value, float min_value, float max_value, float step) -{ - struct nk_property_variant result; - result.kind = NK_PROPERTY_FLOAT; - result.value.f = value; - result.min_value.f = min_value; - result.max_value.f = max_value; - result.step.f = step; - return result; -} - -NK_INTERN struct nk_property_variant -nk_property_variant_double(double value, double min_value, double max_value, - double step) -{ - struct nk_property_variant result; - result.kind = NK_PROPERTY_DOUBLE; - result.value.d = value; - result.min_value.d = min_value; - result.max_value.d = max_value; - result.step.d = step; - return result; -} - -NK_INTERN void -nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant, - float inc_per_pixel, const enum nk_property_filter filter) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states s; - - int *state = 0; - nk_hash hash = 0; - char *buffer = 0; - int *len = 0; - int *cursor = 0; - int *select_begin = 0; - int *select_end = 0; - int old_state; - - char dummy_buffer[NK_MAX_NUMBER_BUFFER]; - int dummy_state = NK_PROPERTY_DEFAULT; - int dummy_length = 0; - int dummy_cursor = 0; - int dummy_select_begin = 0; - int dummy_select_end = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - s = nk_widget(&bounds, ctx); - if (!s) return; - - /* calculate hash from name */ - if (name[0] == '#') { - hash = nk_murmur_hash(name, (int)nk_strlen(name), win->property.seq++); - name++; /* special number hash */ - } else hash = nk_murmur_hash(name, (int)nk_strlen(name), 42); - - /* check if property is currently hot item */ - if (win->property.active && hash == win->property.name) { - buffer = win->property.buffer; - len = &win->property.length; - cursor = &win->property.cursor; - state = &win->property.state; - select_begin = &win->property.select_start; - select_end = &win->property.select_end; - } else { - buffer = dummy_buffer; - len = &dummy_length; - cursor = &dummy_cursor; - state = &dummy_state; - select_begin = &dummy_select_begin; - select_end = &dummy_select_end; - } - - /* execute property widget */ - old_state = *state; - ctx->text_edit.clip = ctx->clip; - in = ((s == NK_WIDGET_ROM && !win->property.active) || - layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name, - variant, inc_per_pixel, buffer, len, state, cursor, select_begin, - select_end, &style->property, filter, in, style->font, &ctx->text_edit, - ctx->button_behavior); - - if (in && *state != NK_PROPERTY_DEFAULT && !win->property.active) { - /* current property is now hot */ - win->property.active = 1; - NK_MEMCPY(win->property.buffer, buffer, (nk_size)*len); - win->property.length = *len; - win->property.cursor = *cursor; - win->property.state = *state; - win->property.name = hash; - win->property.select_start = *select_begin; - win->property.select_end = *select_end; - if (*state == NK_PROPERTY_DRAG) { - ctx->input.mouse.grab = nk_true; - ctx->input.mouse.grabbed = nk_true; - } - } - /* check if previously active property is now inactive */ - if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) { - if (old_state == NK_PROPERTY_DRAG) { - ctx->input.mouse.grab = nk_false; - ctx->input.mouse.grabbed = nk_false; - ctx->input.mouse.ungrab = nk_true; - } - win->property.select_start = 0; - win->property.select_end = 0; - win->property.active = 0; - } -} - -NK_API void -nk_property_int(struct nk_context *ctx, const char *name, - int min, int *val, int max, int step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(val); - - if (!ctx || !ctx->current || !name || !val) return; - variant = nk_property_variant_int(*val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT); - *val = variant.value.i; -} - -NK_API void -nk_property_float(struct nk_context *ctx, const char *name, - float min, float *val, float max, float step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(val); - - if (!ctx || !ctx->current || !name || !val) return; - variant = nk_property_variant_float(*val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - *val = variant.value.f; -} - -NK_API void -nk_property_double(struct nk_context *ctx, const char *name, - double min, double *val, double max, double step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(val); - - if (!ctx || !ctx->current || !name || !val) return; - variant = nk_property_variant_double(*val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - *val = variant.value.d; -} - -NK_API int -nk_propertyi(struct nk_context *ctx, const char *name, int min, int val, - int max, int step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - - if (!ctx || !ctx->current || !name) return val; - variant = nk_property_variant_int(val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT); - val = variant.value.i; - return val; -} - -NK_API float -nk_propertyf(struct nk_context *ctx, const char *name, float min, - float val, float max, float step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - - if (!ctx || !ctx->current || !name) return val; - variant = nk_property_variant_float(val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - val = variant.value.f; - return val; -} - -NK_API double -nk_propertyd(struct nk_context *ctx, const char *name, double min, - double val, double max, double step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - - if (!ctx || !ctx->current || !name) return val; - variant = nk_property_variant_double(val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - val = variant.value.d; - return val; -} - -/*---------------------------------------------------------------- - * - * COLOR PICKER - * - * --------------------------------------------------------------*/ -NK_API int -nk_color_pick(struct nk_context * ctx, struct nk_color *color, - enum nk_color_format fmt) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *config; - const struct nk_input *in; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(color); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !color) - return 0; - - win = ctx->current; - config = &ctx->style; - layout = win->layout; - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_color_picker(&ctx->last_widget_state, &win->buffer, color, fmt, bounds, - nk_vec2(0,0), in, config->font); -} - -NK_API struct nk_color -nk_color_picker(struct nk_context *ctx, struct nk_color color, - enum nk_color_format fmt) -{ - nk_color_pick(ctx, &color, fmt); - return color; -} - -/* ------------------------------------------------------------- - * - * CHART - * - * --------------------------------------------------------------*/ -NK_API int -nk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type, - struct nk_color color, struct nk_color highlight, - int count, float min_value, float max_value) -{ - struct nk_window *win; - struct nk_chart *chart; - const struct nk_style *config; - const struct nk_style_chart *style; - - const struct nk_style_item *background; - struct nk_rect bounds = {0, 0, 0, 0}; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - - if (!ctx || !ctx->current || !ctx->current->layout) return 0; - if (!nk_widget(&bounds, ctx)) { - chart = &ctx->current->layout->chart; - nk_zero(chart, sizeof(*chart)); - return 0; - } - - win = ctx->current; - config = &ctx->style; - chart = &win->layout->chart; - style = &config->chart; - - /* setup basic generic chart */ - nk_zero(chart, sizeof(*chart)); - chart->x = bounds.x + style->padding.x; - chart->y = bounds.y + style->padding.y; - chart->w = bounds.w - 2 * style->padding.x; - chart->h = bounds.h - 2 * style->padding.y; - chart->w = NK_MAX(chart->w, 2 * style->padding.x); - chart->h = NK_MAX(chart->h, 2 * style->padding.y); - - /* add first slot into chart */ - {struct nk_chart_slot *slot = &chart->slots[chart->slot++]; - slot->type = type; - slot->count = count; - slot->color = color; - slot->highlight = highlight; - slot->min = NK_MIN(min_value, max_value); - slot->max = NK_MAX(min_value, max_value); - slot->range = slot->max - slot->min;} - - /* draw chart background */ - background = &style->background; - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(&win->buffer, bounds, &background->data.image, nk_white); - } else { - nk_fill_rect(&win->buffer, bounds, style->rounding, style->border_color); - nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border), - style->rounding, style->background.data.color); - } - return 1; -} - -NK_API int -nk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type, - int count, float min_value, float max_value) -{return nk_chart_begin_colored(ctx, type, ctx->style.chart.color, ctx->style.chart.selected_color, count, min_value, max_value);} - -NK_API void -nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type, - struct nk_color color, struct nk_color highlight, - int count, float min_value, float max_value) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT); - if (!ctx || !ctx->current || !ctx->current->layout) return; - if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return; - - /* add another slot into the graph */ - {struct nk_chart *chart = &ctx->current->layout->chart; - struct nk_chart_slot *slot = &chart->slots[chart->slot++]; - slot->type = type; - slot->count = count; - slot->color = color; - slot->highlight = highlight; - slot->min = NK_MIN(min_value, max_value); - slot->max = NK_MAX(min_value, max_value); - slot->range = slot->max - slot->min;} -} - -NK_API void -nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type, - int count, float min_value, float max_value) -{nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color, ctx->style.chart.selected_color, count, min_value, max_value);} - -NK_INTERN nk_flags -nk_chart_push_line(struct nk_context *ctx, struct nk_window *win, - struct nk_chart *g, float value, int slot) -{ - struct nk_panel *layout = win->layout; - const struct nk_input *i = &ctx->input; - struct nk_command_buffer *out = &win->buffer; - - nk_flags ret = 0; - struct nk_vec2 cur; - struct nk_rect bounds; - struct nk_color color; - float step; - float range; - float ratio; - - NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); - step = g->w / (float)g->slots[slot].count; - range = g->slots[slot].max - g->slots[slot].min; - ratio = (value - g->slots[slot].min) / range; - - if (g->slots[slot].index == 0) { - /* first data point does not have a connection */ - g->slots[slot].last.x = g->x; - g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h; - - bounds.x = g->slots[slot].last.x - 2; - bounds.y = g->slots[slot].last.y - 2; - bounds.w = bounds.h = 4; - - color = g->slots[slot].color; - if (!(layout->flags & NK_WINDOW_ROM) && - NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){ - ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0; - ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down && - i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; - color = g->slots[slot].highlight; - } - nk_fill_rect(out, bounds, 0, color); - g->slots[slot].index += 1; - return ret; - } - - /* draw a line between the last data point and the new one */ - color = g->slots[slot].color; - cur.x = g->x + (float)(step * (float)g->slots[slot].index); - cur.y = (g->y + g->h) - (ratio * (float)g->h); - nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color); - - bounds.x = cur.x - 3; - bounds.y = cur.y - 3; - bounds.w = bounds.h = 6; - - /* user selection of current data point */ - if (!(layout->flags & NK_WINDOW_ROM)) { - if (nk_input_is_mouse_hovering_rect(i, bounds)) { - ret = NK_CHART_HOVERING; - ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down && - i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; - color = g->slots[slot].highlight; - } - } - nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color); - - /* save current data point position */ - g->slots[slot].last.x = cur.x; - g->slots[slot].last.y = cur.y; - g->slots[slot].index += 1; - return ret; -} - -NK_INTERN nk_flags -nk_chart_push_column(const struct nk_context *ctx, struct nk_window *win, - struct nk_chart *chart, float value, int slot) -{ - struct nk_command_buffer *out = &win->buffer; - const struct nk_input *in = &ctx->input; - struct nk_panel *layout = win->layout; - - float ratio; - nk_flags ret = 0; - struct nk_color color; - struct nk_rect item = {0,0,0,0}; - - NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); - if (chart->slots[slot].index >= chart->slots[slot].count) - return nk_false; - if (chart->slots[slot].count) { - float padding = (float)(chart->slots[slot].count-1); - item.w = (chart->w - padding) / (float)(chart->slots[slot].count); - } - - /* calculate bounds of current bar chart entry */ - color = chart->slots[slot].color;; - item.h = chart->h * NK_ABS((value/chart->slots[slot].range)); - if (value >= 0) { - ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range); - item.y = (chart->y + chart->h) - chart->h * ratio; - } else { - ratio = (value - chart->slots[slot].max) / chart->slots[slot].range; - item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h; - } - item.x = chart->x + ((float)chart->slots[slot].index * item.w); - item.x = item.x + ((float)chart->slots[slot].index); - - /* user chart bar selection */ - if (!(layout->flags & NK_WINDOW_ROM) && - NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) { - ret = NK_CHART_HOVERING; - ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down && - in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; - color = chart->slots[slot].highlight; - } - nk_fill_rect(out, item, 0, color); - chart->slots[slot].index += 1; - return ret; -} - -NK_API nk_flags -nk_chart_push_slot(struct nk_context *ctx, float value, int slot) -{ - nk_flags flags; - struct nk_window *win; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); - NK_ASSERT(slot < ctx->current->layout->chart.slot); - if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false; - if (slot >= ctx->current->layout->chart.slot) return nk_false; - - win = ctx->current; - if (win->layout->chart.slot < slot) return nk_false; - switch (win->layout->chart.slots[slot].type) { - case NK_CHART_LINES: - flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break; - case NK_CHART_COLUMN: - flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break; - default: - case NK_CHART_MAX: - flags = 0; - } - return flags; -} - -NK_API nk_flags -nk_chart_push(struct nk_context *ctx, float value) -{return nk_chart_push_slot(ctx, value, 0);} - -NK_API void -nk_chart_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_chart *chart; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return; - - win = ctx->current; - chart = &win->layout->chart; - NK_MEMSET(chart, 0, sizeof(*chart)); - return; -} - -NK_API void -nk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values, - int count, int offset) -{ - int i = 0; - float min_value; - float max_value; - - NK_ASSERT(ctx); - NK_ASSERT(values); - if (!ctx || !values || !count) return; - - min_value = values[offset]; - max_value = values[offset]; - for (i = 0; i < count; ++i) { - min_value = NK_MIN(values[i + offset], min_value); - max_value = NK_MAX(values[i + offset], max_value); - } - - if (nk_chart_begin(ctx, type, count, min_value, max_value)) { - for (i = 0; i < count; ++i) - nk_chart_push(ctx, values[i + offset]); - nk_chart_end(ctx); - } -} - -NK_API void -nk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata, - float(*value_getter)(void* user, int index), int count, int offset) -{ - int i = 0; - float min_value; - float max_value; - - NK_ASSERT(ctx); - NK_ASSERT(value_getter); - if (!ctx || !value_getter || !count) return; - - max_value = min_value = value_getter(userdata, offset); - for (i = 0; i < count; ++i) { - float value = value_getter(userdata, i + offset); - min_value = NK_MIN(value, min_value); - max_value = NK_MAX(value, max_value); - } - - if (nk_chart_begin(ctx, type, count, min_value, max_value)) { - for (i = 0; i < count; ++i) - nk_chart_push(ctx, value_getter(userdata, i + offset)); - nk_chart_end(ctx); - } -} - -/* ------------------------------------------------------------- - * - * GROUP - * - * --------------------------------------------------------------*/ -NK_API int -nk_group_scrolled_offset_begin(struct nk_context *ctx, - nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags) -{ - struct nk_rect bounds; - struct nk_window panel; - struct nk_window *win; - - win = ctx->current; - nk_panel_alloc_space(&bounds, ctx); - {const struct nk_rect *c = &win->layout->clip; - if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) && - !(flags & NK_WINDOW_MOVABLE)) { - return 0; - }} - if (win->flags & NK_WINDOW_ROM) - flags |= NK_WINDOW_ROM; - - /* initialize a fake window to create the panel from */ - nk_zero(&panel, sizeof(panel)); - panel.bounds = bounds; - panel.flags = flags; - panel.scrollbar.x = *x_offset; - panel.scrollbar.y = *y_offset; - panel.buffer = win->buffer; - panel.layout = (struct nk_panel*)nk_create_panel(ctx); - ctx->current = &panel; - nk_panel_begin(ctx, (flags & NK_WINDOW_TITLE) ? title: 0, NK_PANEL_GROUP); - - win->buffer = panel.buffer; - win->buffer.clip = panel.layout->clip; - panel.layout->offset_x = x_offset; - panel.layout->offset_y = y_offset; - panel.layout->parent = win->layout; - win->layout = panel.layout; - - ctx->current = win; - if ((panel.layout->flags & NK_WINDOW_CLOSED) || - (panel.layout->flags & NK_WINDOW_MINIMIZED)) - { - nk_flags f = panel.layout->flags; - nk_group_scrolled_end(ctx); - if (f & NK_WINDOW_CLOSED) - return NK_WINDOW_CLOSED; - if (f & NK_WINDOW_MINIMIZED) - return NK_WINDOW_MINIMIZED; - } - return 1; -} - -NK_API void -nk_group_scrolled_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *parent; - struct nk_panel *g; - - struct nk_rect clip; - struct nk_window pan; - struct nk_vec2 panel_padding; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return; - - /* make sure nk_group_begin was called correctly */ - NK_ASSERT(ctx->current); - win = ctx->current; - NK_ASSERT(win->layout); - g = win->layout; - NK_ASSERT(g->parent); - parent = g->parent; - - /* dummy window */ - nk_zero_struct(pan); - panel_padding = nk_panel_get_padding(&ctx->style, NK_PANEL_GROUP); - pan.bounds.y = g->bounds.y - (g->header_height + g->menu.h); - pan.bounds.x = g->bounds.x - panel_padding.x; - pan.bounds.w = g->bounds.w + 2 * panel_padding.x; - pan.bounds.h = g->bounds.h + g->header_height + g->menu.h; - if (g->flags & NK_WINDOW_BORDER) { - pan.bounds.x -= g->border; - pan.bounds.y -= g->border; - pan.bounds.w += 2*g->border; - pan.bounds.h += 2*g->border; - } - if (!(g->flags & NK_WINDOW_NO_SCROLLBAR)) { - pan.bounds.w += ctx->style.window.scrollbar_size.x; - pan.bounds.h += ctx->style.window.scrollbar_size.y; - } - pan.scrollbar.x = *g->offset_x; - pan.scrollbar.y = *g->offset_y; - pan.flags = g->flags; - pan.buffer = win->buffer; - pan.layout = g; - pan.parent = win; - ctx->current = &pan; - - /* make sure group has correct clipping rectangle */ - nk_unify(&clip, &parent->clip, pan.bounds.x, pan.bounds.y, - pan.bounds.x + pan.bounds.w, pan.bounds.y + pan.bounds.h + panel_padding.x); - nk_push_scissor(&pan.buffer, clip); - nk_end(ctx); - - win->buffer = pan.buffer; - nk_push_scissor(&win->buffer, parent->clip); - ctx->current = win; - win->layout = parent; - g->bounds = pan.bounds; - return; -} - -NK_API int -nk_group_scrolled_begin(struct nk_context *ctx, - struct nk_scroll *scroll, const char *title, nk_flags flags) -{return nk_group_scrolled_offset_begin(ctx, &scroll->x, &scroll->y, title, flags);} - -NK_API int -nk_group_begin(struct nk_context *ctx, const char *title, nk_flags flags) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - nk_uint *x_offset; - nk_uint *y_offset; - - NK_ASSERT(ctx); - NK_ASSERT(title); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !title) - return 0; - - /* find persistent group scrollbar value */ - win = ctx->current; - title_len = (int)nk_strlen(title); - title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP); - x_offset = nk_find_value(win, title_hash); - if (!x_offset) { - x_offset = nk_add_value(ctx, win, title_hash, 0); - y_offset = nk_add_value(ctx, win, title_hash+1, 0); - - NK_ASSERT(x_offset); - NK_ASSERT(y_offset); - if (!x_offset || !y_offset) return 0; - *x_offset = *y_offset = 0; - } else y_offset = nk_find_value(win, title_hash+1); - return nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags); -} - -NK_API void -nk_group_end(struct nk_context *ctx) -{nk_group_scrolled_end(ctx);} - -NK_API int -nk_list_view_begin(struct nk_context *ctx, struct nk_list_view *view, - const char *title, nk_flags flags, int row_height, int row_count) -{ - int title_len; - nk_hash title_hash; - nk_uint *x_offset; - nk_uint *y_offset; - - int result; - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_vec2 item_spacing; - - NK_ASSERT(ctx); - NK_ASSERT(view); - NK_ASSERT(title); - if (!ctx || !view || !title) return 0; - - win = ctx->current; - style = &ctx->style; - item_spacing = style->window.spacing; - row_height += NK_MAX(0, (int)item_spacing.y); - - /* find persistent list view scrollbar offset */ - title_len = (int)nk_strlen(title); - title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP); - x_offset = nk_find_value(win, title_hash); - if (!x_offset) { - x_offset = nk_add_value(ctx, win, title_hash, 0); - y_offset = nk_add_value(ctx, win, title_hash+1, 0); - - NK_ASSERT(x_offset); - NK_ASSERT(y_offset); - if (!x_offset || !y_offset) return 0; - *x_offset = *y_offset = 0; - } else y_offset = nk_find_value(win, title_hash+1); - view->scroll_value = *y_offset; - view->scroll_pointer = y_offset; - - *y_offset = 0; - result = nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags); - win = ctx->current; - layout = win->layout; - - view->total_height = row_height * NK_MAX(row_count,1); - view->begin = (int)NK_MAX(((float)view->scroll_value / (float)row_height), 0.0f); - view->count = (int)NK_MAX(nk_iceilf((layout->clip.h)/(float)row_height), 0); - view->end = view->begin + view->count; - view->ctx = ctx; - return result; -} - -NK_API void -nk_list_view_end(struct nk_list_view *view) -{ - struct nk_context *ctx; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(view); - NK_ASSERT(view->ctx); - NK_ASSERT(view->scroll_pointer); - if (!view || !view->ctx) return; - - ctx = view->ctx; - win = ctx->current; - layout = win->layout; - layout->at_y = layout->bounds.y + (float)view->total_height; - *view->scroll_pointer = *view->scroll_pointer + view->scroll_value; - nk_group_end(view->ctx); -} - -/* -------------------------------------------------------------- - * - * POPUP - * - * --------------------------------------------------------------*/ -NK_API int -nk_popup_begin(struct nk_context *ctx, enum nk_popup_type type, - const char *title, nk_flags flags, struct nk_rect rect) -{ - struct nk_window *popup; - struct nk_window *win; - struct nk_panel *panel; - - int title_len; - nk_hash title_hash; - nk_size allocated; - - NK_ASSERT(ctx); - NK_ASSERT(title); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - panel = win->layout; - NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP) && "popups are not allowed to have popups"); - (void)panel; - title_len = (int)nk_strlen(title); - title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_POPUP); - - popup = win->popup.win; - if (!popup) { - popup = (struct nk_window*)nk_create_window(ctx); - popup->parent = win; - win->popup.win = popup; - win->popup.active = 0; - win->popup.type = NK_PANEL_POPUP; - } - - /* make sure we have correct popup */ - if (win->popup.name != title_hash) { - if (!win->popup.active) { - nk_zero(popup, sizeof(*popup)); - win->popup.name = title_hash; - win->popup.active = 1; - win->popup.type = NK_PANEL_POPUP; - } else return 0; - } - - /* popup position is local to window */ - ctx->current = popup; - rect.x += win->layout->clip.x; - rect.y += win->layout->clip.y; - - /* setup popup data */ - popup->parent = win; - popup->bounds = rect; - popup->seq = ctx->seq; - popup->layout = (struct nk_panel*)nk_create_panel(ctx); - popup->flags = flags; - popup->flags |= NK_WINDOW_BORDER; - if (type == NK_POPUP_DYNAMIC) - popup->flags |= NK_WINDOW_DYNAMIC; - - popup->buffer = win->buffer; - nk_start_popup(ctx, win); - allocated = ctx->memory.allocated; - nk_push_scissor(&popup->buffer, nk_null_rect); - - if (nk_panel_begin(ctx, title, NK_PANEL_POPUP)) { - /* popup is running therefore invalidate parent panels */ - struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_ROM; - root->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - win->popup.active = 1; - popup->layout->offset_x = &popup->scrollbar.x; - popup->layout->offset_y = &popup->scrollbar.y; - popup->layout->parent = win->layout; - return 1; - } else { - /* popup was closed/is invalid so cleanup */ - struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - win->popup.buf.active = 0; - win->popup.active = 0; - ctx->memory.allocated = allocated; - ctx->current = win; - nk_free_panel(ctx, popup->layout); - popup->layout = 0; - return 0; - } -} - -NK_INTERN int -nk_nonblock_begin(struct nk_context *ctx, - nk_flags flags, struct nk_rect body, struct nk_rect header, - enum nk_panel_type panel_type) -{ - struct nk_window *popup; - struct nk_window *win; - struct nk_panel *panel; - int is_active = nk_true; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - /* popups cannot have popups */ - win = ctx->current; - panel = win->layout; - NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP)); - (void)panel; - popup = win->popup.win; - if (!popup) { - /* create window for nonblocking popup */ - popup = (struct nk_window*)nk_create_window(ctx); - popup->parent = win; - win->popup.win = popup; - win->popup.type = panel_type; - nk_command_buffer_init(&popup->buffer, &ctx->memory, NK_CLIPPING_ON); - } else { - /* close the popup if user pressed outside or in the header */ - int pressed, in_body, in_header; - pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT); - in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body); - in_header = nk_input_is_mouse_hovering_rect(&ctx->input, header); - if (pressed && (!in_body || in_header)) - is_active = nk_false; - } - win->popup.header = header; - - if (!is_active) { - /* remove read only mode from all parent panels */ - struct nk_panel *root = win->layout; - while (root) { - root->flags |= NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - return is_active; - } - - popup->bounds = body; - popup->parent = win; - popup->layout = (struct nk_panel*)nk_create_panel(ctx); - popup->flags = flags; - popup->flags |= NK_WINDOW_BORDER; - popup->flags |= NK_WINDOW_DYNAMIC; - popup->seq = ctx->seq; - win->popup.active = 1; - NK_ASSERT(popup->layout); - - nk_start_popup(ctx, win); - popup->buffer = win->buffer; - nk_push_scissor(&popup->buffer, nk_null_rect); - ctx->current = popup; - - nk_panel_begin(ctx, 0, panel_type); - win->buffer = popup->buffer; - popup->layout->parent = win->layout; - popup->layout->offset_x = &popup->scrollbar.x; - popup->layout->offset_y = &popup->scrollbar.y; - - /* set read only mode to all parent panels */ - {struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_ROM; - root = root->parent; - }} - return is_active; -} - -NK_API void -nk_popup_close(struct nk_context *ctx) -{ - struct nk_window *popup; - NK_ASSERT(ctx); - if (!ctx || !ctx->current) return; - - popup = ctx->current; - NK_ASSERT(popup->parent); - NK_ASSERT(popup->layout->type & NK_PANEL_SET_POPUP); - popup->flags |= NK_WINDOW_HIDDEN; -} - -NK_API void -nk_popup_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_window *popup; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - popup = ctx->current; - if (!popup->parent) return; - win = popup->parent; - if (popup->flags & NK_WINDOW_HIDDEN) { - struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - win->popup.active = 0; - } - nk_push_scissor(&popup->buffer, nk_null_rect); - nk_end(ctx); - - win->buffer = popup->buffer; - nk_finish_popup(ctx, win); - ctx->current = win; - nk_push_scissor(&win->buffer, win->layout->clip); -} -/* ------------------------------------------------------------- - * - * TOOLTIP - * - * -------------------------------------------------------------- */ -NK_API int -nk_tooltip_begin(struct nk_context *ctx, float width) -{ - struct nk_window *win; - const struct nk_input *in; - struct nk_rect bounds; - int ret; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - /* make sure that no nonblocking popup is currently active */ - win = ctx->current; - in = &ctx->input; - if (win->popup.win && (win->popup.type & NK_PANEL_SET_NONBLOCK)) - return 0; - - bounds.w = width; - bounds.h = nk_null_rect.h; - bounds.x = (in->mouse.pos.x + 1) - win->layout->clip.x; - bounds.y = (in->mouse.pos.y + 1) - win->layout->clip.y; - - ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC, - "__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds); - if (ret) win->layout->flags &= ~(nk_flags)NK_WINDOW_ROM; - win->popup.type = NK_PANEL_TOOLTIP; - ctx->current->layout->type = NK_PANEL_TOOLTIP; - return ret; -} - -NK_API void -nk_tooltip_end(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - ctx->current->seq--; - nk_popup_close(ctx); - nk_popup_end(ctx); -} - -NK_API void -nk_tooltip(struct nk_context *ctx, const char *text) -{ - const struct nk_style *style; - struct nk_vec2 padding; - - int text_len; - float text_width; - float text_height; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(text); - if (!ctx || !ctx->current || !ctx->current->layout || !text) - return; - - /* fetch configuration data */ - style = &ctx->style; - padding = style->window.padding; - - /* calculate size of the text and tooltip */ - text_len = nk_strlen(text); - text_width = style->font->width(style->font->userdata, - style->font->height, text, text_len); - text_width += (4 * padding.x); - text_height = (style->font->height + 2 * padding.y); - - /* execute tooltip and fill with text */ - if (nk_tooltip_begin(ctx, (float)text_width)) { - nk_layout_row_dynamic(ctx, (float)text_height, 1); - nk_text(ctx, text, text_len, NK_TEXT_LEFT); - nk_tooltip_end(ctx); - } -} -/* ------------------------------------------------------------- - * - * CONTEXTUAL - * - * -------------------------------------------------------------- */ -NK_API int -nk_contextual_begin(struct nk_context *ctx, nk_flags flags, struct nk_vec2 size, - struct nk_rect trigger_bounds) -{ - struct nk_window *win; - struct nk_window *popup; - struct nk_rect body; - - NK_STORAGE const struct nk_rect null_rect = {0,0,0,0}; - int is_clicked = 0; - int is_active = 0; - int is_open = 0; - int ret = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - ++win->popup.con_count; - - /* check if currently active contextual is active */ - popup = win->popup.win; - is_open = (popup && win->popup.type == NK_PANEL_CONTEXTUAL); - is_clicked = nk_input_mouse_clicked(&ctx->input, NK_BUTTON_RIGHT, trigger_bounds); - if (win->popup.active_con && win->popup.con_count != win->popup.active_con) - return 0; - if ((is_clicked && is_open && !is_active) || (!is_open && !is_active && !is_clicked)) - return 0; - - /* calculate contextual position on click */ - win->popup.active_con = win->popup.con_count; - if (is_clicked) { - body.x = ctx->input.mouse.pos.x; - body.y = ctx->input.mouse.pos.y; - } else { - body.x = popup->bounds.x; - body.y = popup->bounds.y; - } - body.w = size.x; - body.h = size.y; - - /* start nonblocking contextual popup */ - ret = nk_nonblock_begin(ctx, flags|NK_WINDOW_NO_SCROLLBAR, body, - null_rect, NK_PANEL_CONTEXTUAL); - if (ret) win->popup.type = NK_PANEL_CONTEXTUAL; - else { - win->popup.active_con = 0; - if (win->popup.win) - win->popup.win->flags = 0; - } - return ret; -} - -NK_API int -nk_contextual_item_text(struct nk_context *ctx, const char *text, int len, - nk_flags alignment) -{ - struct nk_window *win; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); - if (!state) return nk_false; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds, - text, len, alignment, NK_BUTTON_DEFAULT, &style->contextual_button, in, style->font)) { - nk_contextual_close(ctx); - return nk_true; - } - return nk_false; -} - -NK_API int nk_contextual_item_label(struct nk_context *ctx, const char *label, nk_flags align) -{return nk_contextual_item_text(ctx, label, nk_strlen(label), align);} - -NK_API int -nk_contextual_item_image_text(struct nk_context *ctx, struct nk_image img, - const char *text, int len, nk_flags align) -{ - struct nk_window *win; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); - if (!state) return nk_false; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, bounds, - img, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)){ - nk_contextual_close(ctx); - return nk_true; - } - return nk_false; -} - -NK_API int nk_contextual_item_image_label(struct nk_context *ctx, struct nk_image img, - const char *label, nk_flags align) -{return nk_contextual_item_image_text(ctx, img, label, nk_strlen(label), align);} - -NK_API int -nk_contextual_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol, - const char *text, int len, nk_flags align) -{ - struct nk_window *win; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); - if (!state) return nk_false; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds, - symbol, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)) { - nk_contextual_close(ctx); - return nk_true; - } - return nk_false; -} - -NK_API int nk_contextual_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol, - const char *text, nk_flags align) -{return nk_contextual_item_symbol_text(ctx, symbol, text, nk_strlen(text), align);} - -NK_API void -nk_contextual_close(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - nk_popup_close(ctx); -} - -NK_API void -nk_contextual_end(struct nk_context *ctx) -{ - struct nk_window *popup; - struct nk_panel *panel; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - - popup = ctx->current; - panel = popup->layout; - NK_ASSERT(popup->parent); - NK_ASSERT(panel->type & NK_PANEL_SET_POPUP); - if (panel->flags & NK_WINDOW_DYNAMIC) { - /* Close behavior - This is a bit of a hack solution since we do not know before we end our popup - how big it will be. We therefore do not directly know when a - click outside the non-blocking popup must close it at that direct frame. - Instead it will be closed in the next frame.*/ - struct nk_rect body = {0,0,0,0}; - if (panel->at_y < (panel->bounds.y + panel->bounds.h)) { - struct nk_vec2 padding = nk_panel_get_padding(&ctx->style, panel->type); - body = panel->bounds; - body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height); - body.h = (panel->bounds.y + panel->bounds.h) - body.y; - } - {int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT); - int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body); - if (pressed && in_body) - popup->flags |= NK_WINDOW_HIDDEN; - } - } - if (popup->flags & NK_WINDOW_HIDDEN) - popup->seq = 0; - nk_popup_end(ctx); - return; -} -/* ------------------------------------------------------------- - * - * COMBO - * - * --------------------------------------------------------------*/ -NK_INTERN int -nk_combo_begin(struct nk_context *ctx, struct nk_window *win, - struct nk_vec2 size, int is_clicked, struct nk_rect header) -{ - struct nk_window *popup; - int is_open = 0; - int is_active = 0; - struct nk_rect body; - nk_hash hash; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - popup = win->popup.win; - body.x = header.x; - body.w = size.x; - body.y = header.y + header.h-ctx->style.window.combo_border; - body.h = size.y; - - hash = win->popup.combo_count++; - is_open = (popup) ? nk_true:nk_false; - is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_COMBO); - if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || - (!is_open && !is_active && !is_clicked)) return 0; - if (!nk_nonblock_begin(ctx, 0, body, - (is_clicked && is_open)?nk_rect(0,0,0,0):header, NK_PANEL_COMBO)) return 0; - - win->popup.type = NK_PANEL_COMBO; - win->popup.name = hash; - return 1; -} - -NK_API int -nk_combo_begin_text(struct nk_context *ctx, const char *selected, int len, - struct nk_vec2 size) -{ - const struct nk_input *in; - struct nk_window *win; - struct nk_style *style; - - enum nk_widget_layout_states s; - int is_clicked = nk_false; - struct nk_rect header; - const struct nk_style_item *background; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(selected); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !selected) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - text.text = style->combo.label_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - text.text = style->combo.label_hover; - } else { - background = &style->combo.normal; - text.text = style->combo.label_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - /* print currently selected text item */ - struct nk_rect label; - struct nk_rect button; - struct nk_rect content; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw selected label */ - text.padding = nk_vec2(0,0); - label.x = header.x + style->combo.content_padding.x; - label.y = header.y + style->combo.content_padding.y; - label.w = button.x - (style->combo.content_padding.x + style->combo.spacing.x) - label.x;; - label.h = header.h - 2 * style->combo.content_padding.y; - nk_widget_text(&win->buffer, label, selected, len, &text, - NK_TEXT_LEFT, ctx->style.font); - - /* draw open/close button */ - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int nk_combo_begin_label(struct nk_context *ctx, const char *selected, struct nk_vec2 size) -{return nk_combo_begin_text(ctx, selected, nk_strlen(selected), size);} - -NK_API int -nk_combo_begin_color(struct nk_context *ctx, struct nk_color color, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - const struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) - background = &style->combo.active; - else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - background = &style->combo.hover; - else background = &style->combo.normal; - - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(&win->buffer, header, &background->data.image,nk_white); - } else { - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect content; - struct nk_rect button; - struct nk_rect bounds; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw color */ - bounds.h = header.h - 4 * style->combo.content_padding.y; - bounds.y = header.y + 2 * style->combo.content_padding.y; - bounds.x = header.x + 2 * style->combo.content_padding.x; - bounds.w = (button.x - (style->combo.content_padding.x + style->combo.spacing.x)) - bounds.x; - nk_fill_rect(&win->buffer, bounds, 0, color); - - /* draw open/close button */ - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int -nk_combo_begin_symbol(struct nk_context *ctx, enum nk_symbol_type symbol, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - const struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - struct nk_color sym_background; - struct nk_color symbol_color; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - symbol_color = style->combo.symbol_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - symbol_color = style->combo.symbol_hover; - } else { - background = &style->combo.normal; - symbol_color = style->combo.symbol_hover; - } - - if (background->type == NK_STYLE_ITEM_IMAGE) { - sym_background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - sym_background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect bounds = {0,0,0,0}; - struct nk_rect content; - struct nk_rect button; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.y; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw symbol */ - bounds.h = header.h - 2 * style->combo.content_padding.y; - bounds.y = header.y + style->combo.content_padding.y; - bounds.x = header.x + style->combo.content_padding.x; - bounds.w = (button.x - style->combo.content_padding.y) - bounds.x; - nk_draw_symbol(&win->buffer, symbol, bounds, sym_background, symbol_color, - 1.0f, style->font); - - /* draw open/close button */ - nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int -nk_combo_begin_symbol_text(struct nk_context *ctx, const char *selected, int len, - enum nk_symbol_type symbol, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - struct nk_color symbol_color; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (!s) return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - symbol_color = style->combo.symbol_active; - text.text = style->combo.label_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - symbol_color = style->combo.symbol_hover; - text.text = style->combo.label_hover; - } else { - background = &style->combo.normal; - symbol_color = style->combo.symbol_normal; - text.text = style->combo.label_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect content; - struct nk_rect button; - struct nk_rect label; - struct nk_rect image; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - - /* draw symbol */ - image.x = header.x + style->combo.content_padding.x; - image.y = header.y + style->combo.content_padding.y; - image.h = header.h - 2 * style->combo.content_padding.y; - image.w = image.h; - nk_draw_symbol(&win->buffer, symbol, image, text.background, symbol_color, - 1.0f, style->font); - - /* draw label */ - text.padding = nk_vec2(0,0); - label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x; - label.y = header.y + style->combo.content_padding.y; - label.w = (button.x - style->combo.content_padding.x) - label.x; - label.h = header.h - 2 * style->combo.content_padding.y; - nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int -nk_combo_begin_image(struct nk_context *ctx, struct nk_image img, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - const struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) - background = &style->combo.active; - else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - background = &style->combo.hover; - else background = &style->combo.normal; - - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect bounds = {0,0,0,0}; - struct nk_rect content; - struct nk_rect button; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.y; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw image */ - bounds.h = header.h - 2 * style->combo.content_padding.y; - bounds.y = header.y + style->combo.content_padding.y; - bounds.x = header.x + style->combo.content_padding.x; - bounds.w = (button.x - style->combo.content_padding.y) - bounds.x; - nk_draw_image(&win->buffer, bounds, &img, nk_white); - - /* draw open/close button */ - nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int -nk_combo_begin_image_text(struct nk_context *ctx, const char *selected, int len, - struct nk_image img, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (!s) return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - text.text = style->combo.label_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - text.text = style->combo.label_hover; - } else { - background = &style->combo.normal; - text.text = style->combo.label_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect content; - struct nk_rect button; - struct nk_rect label; - struct nk_rect image; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - - /* draw image */ - image.x = header.x + style->combo.content_padding.x; - image.y = header.y + style->combo.content_padding.y; - image.h = header.h - 2 * style->combo.content_padding.y; - image.w = image.h; - nk_draw_image(&win->buffer, image, &img, nk_white); - - /* draw label */ - text.padding = nk_vec2(0,0); - label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x; - label.y = header.y + style->combo.content_padding.y; - label.w = (button.x - style->combo.content_padding.x) - label.x; - label.h = header.h - 2 * style->combo.content_padding.y; - nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int nk_combo_begin_symbol_label(struct nk_context *ctx, - const char *selected, enum nk_symbol_type type, struct nk_vec2 size) -{return nk_combo_begin_symbol_text(ctx, selected, nk_strlen(selected), type, size);} - -NK_API int nk_combo_begin_image_label(struct nk_context *ctx, - const char *selected, struct nk_image img, struct nk_vec2 size) -{return nk_combo_begin_image_text(ctx, selected, nk_strlen(selected), img, size);} - -NK_API int nk_combo_item_text(struct nk_context *ctx, const char *text, int len,nk_flags align) -{return nk_contextual_item_text(ctx, text, len, align);} - -NK_API int nk_combo_item_label(struct nk_context *ctx, const char *label, nk_flags align) -{return nk_contextual_item_label(ctx, label, align);} - -NK_API int nk_combo_item_image_text(struct nk_context *ctx, struct nk_image img, const char *text, - int len, nk_flags alignment) -{return nk_contextual_item_image_text(ctx, img, text, len, alignment);} - -NK_API int nk_combo_item_image_label(struct nk_context *ctx, struct nk_image img, - const char *text, nk_flags alignment) -{return nk_contextual_item_image_label(ctx, img, text, alignment);} - -NK_API int nk_combo_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym, - const char *text, int len, nk_flags alignment) -{return nk_contextual_item_symbol_text(ctx, sym, text, len, alignment);} - -NK_API int nk_combo_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym, - const char *label, nk_flags alignment) -{return nk_contextual_item_symbol_label(ctx, sym, label, alignment);} - -NK_API void nk_combo_end(struct nk_context *ctx) -{nk_contextual_end(ctx);} - -NK_API void nk_combo_close(struct nk_context *ctx) -{nk_contextual_close(ctx);} - -NK_API int -nk_combo(struct nk_context *ctx, const char **items, int count, - int selected, int item_height, struct nk_vec2 size) -{ - int i = 0; - int max_height; - struct nk_vec2 item_spacing; - struct nk_vec2 window_padding; - - NK_ASSERT(ctx); - NK_ASSERT(items); - NK_ASSERT(ctx->current); - if (!ctx || !items ||!count) - return selected; - - item_spacing = ctx->style.window.spacing; - window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); - max_height = count * item_height + count * (int)item_spacing.y; - max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; - size.y = NK_MIN(size.y, (float)max_height); - if (nk_combo_begin_label(ctx, items[selected], size)) { - nk_layout_row_dynamic(ctx, (float)item_height, 1); - for (i = 0; i < count; ++i) { - if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT)) - selected = i; - } - nk_combo_end(ctx); - } - return selected; -} - -NK_API int -nk_combo_separator(struct nk_context *ctx, const char *items_separated_by_separator, - int separator, int selected, int count, int item_height, struct nk_vec2 size) -{ - int i; - int max_height; - struct nk_vec2 item_spacing; - struct nk_vec2 window_padding; - const char *current_item; - const char *iter; - int length = 0; - - NK_ASSERT(ctx); - NK_ASSERT(items_separated_by_separator); - if (!ctx || !items_separated_by_separator) - return selected; - - /* calculate popup window */ - item_spacing = ctx->style.window.spacing; - window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); - max_height = count * item_height + count * (int)item_spacing.y; - max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; - size.y = NK_MIN(size.y, (float)max_height); - - /* find selected item */ - current_item = items_separated_by_separator; - for (i = 0; i < count; ++i) { - iter = current_item; - while (*iter && *iter != separator) iter++; - length = (int)(iter - current_item); - if (i == selected) break; - current_item = iter + 1; - } - - if (nk_combo_begin_text(ctx, current_item, length, size)) { - current_item = items_separated_by_separator; - nk_layout_row_dynamic(ctx, (float)item_height, 1); - for (i = 0; i < count; ++i) { - iter = current_item; - while (*iter && *iter != separator) iter++; - length = (int)(iter - current_item); - if (nk_combo_item_text(ctx, current_item, length, NK_TEXT_LEFT)) - selected = i; - current_item = current_item + length + 1; - } - nk_combo_end(ctx); - } - return selected; -} - -NK_API int -nk_combo_string(struct nk_context *ctx, const char *items_separated_by_zeros, - int selected, int count, int item_height, struct nk_vec2 size) -{return nk_combo_separator(ctx, items_separated_by_zeros, '\0', selected, count, item_height, size);} - -NK_API int -nk_combo_callback(struct nk_context *ctx, void(*item_getter)(void*, int, const char**), - void *userdata, int selected, int count, int item_height, struct nk_vec2 size) -{ - int i; - int max_height; - struct nk_vec2 item_spacing; - struct nk_vec2 window_padding; - const char *item; - - NK_ASSERT(ctx); - NK_ASSERT(item_getter); - if (!ctx || !item_getter) - return selected; - - /* calculate popup window */ - item_spacing = ctx->style.window.spacing; - window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); - max_height = count * item_height + count * (int)item_spacing.y; - max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; - size.y = NK_MIN(size.y, (float)max_height); - - item_getter(userdata, selected, &item); - if (nk_combo_begin_label(ctx, item, size)) { - nk_layout_row_dynamic(ctx, (float)item_height, 1); - for (i = 0; i < count; ++i) { - item_getter(userdata, i, &item); - if (nk_combo_item_label(ctx, item, NK_TEXT_LEFT)) - selected = i; - } - nk_combo_end(ctx); - } - return selected; -} - -NK_API void nk_combobox(struct nk_context *ctx, const char **items, int count, - int *selected, int item_height, struct nk_vec2 size) -{*selected = nk_combo(ctx, items, count, *selected, item_height, size);} - -NK_API void nk_combobox_string(struct nk_context *ctx, const char *items_separated_by_zeros, - int *selected, int count, int item_height, struct nk_vec2 size) -{*selected = nk_combo_string(ctx, items_separated_by_zeros, *selected, count, item_height, size);} - -NK_API void nk_combobox_separator(struct nk_context *ctx, const char *items_separated_by_separator, - int separator,int *selected, int count, int item_height, struct nk_vec2 size) -{*selected = nk_combo_separator(ctx, items_separated_by_separator, separator, - *selected, count, item_height, size);} - -NK_API void nk_combobox_callback(struct nk_context *ctx, - void(*item_getter)(void* data, int id, const char **out_text), - void *userdata, int *selected, int count, int item_height, struct nk_vec2 size) -{*selected = nk_combo_callback(ctx, item_getter, userdata, *selected, count, item_height, size);} - -/* - * ------------------------------------------------------------- - * - * MENU - * - * -------------------------------------------------------------- - */ -NK_INTERN int -nk_menu_begin(struct nk_context *ctx, struct nk_window *win, - const char *id, int is_clicked, struct nk_rect header, struct nk_vec2 size) -{ - int is_open = 0; - int is_active = 0; - struct nk_rect body; - struct nk_window *popup; - nk_hash hash = nk_murmur_hash(id, (int)nk_strlen(id), NK_PANEL_MENU); - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - body.x = header.x; - body.w = size.x; - body.y = header.y + header.h; - body.h = size.y; - - popup = win->popup.win; - is_open = popup ? nk_true : nk_false; - is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU); - if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || - (!is_open && !is_active && !is_clicked)) return 0; - if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU)) - return 0; - - win->popup.type = NK_PANEL_MENU; - win->popup.name = hash; - return 1; -} - -NK_API int -nk_menu_begin_text(struct nk_context *ctx, const char *title, int len, - nk_flags align, struct nk_vec2 size) -{ - struct nk_window *win; - const struct nk_input *in; - struct nk_rect header; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, header, - title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, title, is_clicked, header, size); -} - -NK_API int nk_menu_begin_label(struct nk_context *ctx, - const char *text, nk_flags align, struct nk_vec2 size) -{return nk_menu_begin_text(ctx, text, nk_strlen(text), align, size);} - -NK_API int -nk_menu_begin_image(struct nk_context *ctx, const char *id, struct nk_image img, - struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_rect header; - const struct nk_input *in; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_image(&ctx->last_widget_state, &win->buffer, header, - img, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, id, is_clicked, header, size); -} - -NK_API int -nk_menu_begin_symbol(struct nk_context *ctx, const char *id, - enum nk_symbol_type sym, struct nk_vec2 size) -{ - struct nk_window *win; - const struct nk_input *in; - struct nk_rect header; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, header, - sym, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, id, is_clicked, header, size); -} - -NK_API int -nk_menu_begin_image_text(struct nk_context *ctx, const char *title, int len, - nk_flags align, struct nk_image img, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_rect header; - const struct nk_input *in; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, - header, img, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, - ctx->style.font, in)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, title, is_clicked, header, size); -} - -NK_API int nk_menu_begin_image_label(struct nk_context *ctx, - const char *title, nk_flags align, struct nk_image img, struct nk_vec2 size) -{return nk_menu_begin_image_text(ctx, title, nk_strlen(title), align, img, size);} - -NK_API int -nk_menu_begin_symbol_text(struct nk_context *ctx, const char *title, int len, - nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_rect header; - const struct nk_input *in; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, - header, sym, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, - ctx->style.font, in)) is_clicked = nk_true; - return nk_menu_begin(ctx, win, title, is_clicked, header, size); -} - -NK_API int nk_menu_begin_symbol_label(struct nk_context *ctx, - const char *title, nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size ) -{return nk_menu_begin_symbol_text(ctx, title, nk_strlen(title), align,sym,size);} - -NK_API int nk_menu_item_text(struct nk_context *ctx, const char *title, int len, nk_flags align) -{return nk_contextual_item_text(ctx, title, len, align);} - -NK_API int nk_menu_item_label(struct nk_context *ctx, const char *label, nk_flags align) -{return nk_contextual_item_label(ctx, label, align);} - -NK_API int nk_menu_item_image_label(struct nk_context *ctx, struct nk_image img, - const char *label, nk_flags align) -{return nk_contextual_item_image_label(ctx, img, label, align);} - -NK_API int nk_menu_item_image_text(struct nk_context *ctx, struct nk_image img, - const char *text, int len, nk_flags align) -{return nk_contextual_item_image_text(ctx, img, text, len, align);} - -NK_API int nk_menu_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym, - const char *text, int len, nk_flags align) -{return nk_contextual_item_symbol_text(ctx, sym, text, len, align);} - -NK_API int nk_menu_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym, - const char *label, nk_flags align) -{return nk_contextual_item_symbol_label(ctx, sym, label, align);} - -NK_API void nk_menu_close(struct nk_context *ctx) -{nk_contextual_close(ctx);} - -NK_API void -nk_menu_end(struct nk_context *ctx) -{nk_contextual_end(ctx);} - -#endif diff --git a/src/external/glfw/deps/nuklear_glfw_gl2.h b/src/external/glfw/deps/nuklear_glfw_gl2.h deleted file mode 100644 index 965af5fe..00000000 --- a/src/external/glfw/deps/nuklear_glfw_gl2.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Nuklear - v1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2017 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_GLFW_GL2_H_ -#define NK_GLFW_GL2_H_ - -#include - -enum nk_glfw_init_state{ - NK_GLFW3_DEFAULT = 0, - NK_GLFW3_INSTALL_CALLBACKS -}; -NK_API struct nk_context* nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state); -NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas); -NK_API void nk_glfw3_font_stash_end(void); - -NK_API void nk_glfw3_new_frame(void); -NK_API void nk_glfw3_render(enum nk_anti_aliasing); -NK_API void nk_glfw3_shutdown(void); - -NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint); -NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff); - -#endif - -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_GLFW_GL2_IMPLEMENTATION - -#ifndef NK_GLFW_TEXT_MAX -#define NK_GLFW_TEXT_MAX 256 -#endif -#ifndef NK_GLFW_DOUBLE_CLICK_LO -#define NK_GLFW_DOUBLE_CLICK_LO 0.02 -#endif -#ifndef NK_GLFW_DOUBLE_CLICK_HI -#define NK_GLFW_DOUBLE_CLICK_HI 0.2 -#endif - -struct nk_glfw_device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint font_tex; -}; - -struct nk_glfw_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -static struct nk_glfw { - GLFWwindow *win; - int width, height; - int display_width, display_height; - struct nk_glfw_device ogl; - struct nk_context ctx; - struct nk_font_atlas atlas; - struct nk_vec2 fb_scale; - unsigned int text[NK_GLFW_TEXT_MAX]; - int text_len; - struct nk_vec2 scroll; - double last_button_click; -} glfw; - -NK_INTERN void -nk_glfw3_device_upload_atlas(const void *image, int width, int height) -{ - struct nk_glfw_device *dev = &glfw.ogl; - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -NK_API void -nk_glfw3_render(enum nk_anti_aliasing AA) -{ - /* setup global state */ - struct nk_glfw_device *dev = &glfw.ogl; - glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glEnable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - /* setup viewport/project */ - glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, glfw.width, glfw.height, 0.0f, -1.0f, 1.0f); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - { - GLsizei vs = sizeof(struct nk_glfw_vertex); - size_t vp = offsetof(struct nk_glfw_vertex, position); - size_t vt = offsetof(struct nk_glfw_vertex, uv); - size_t vc = offsetof(struct nk_glfw_vertex, col); - - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - const nk_draw_index *offset = NULL; - struct nk_buffer vbuf, ebuf; - - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_glfw_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* convert shapes into vertexes */ - nk_buffer_init_default(&vbuf); - nk_buffer_init_default(&ebuf); - nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config); - - /* setup vertex buffer pointer */ - {const void *vertices = nk_buffer_memory_const(&vbuf); - glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp)); - glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt)); - glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));} - - /* iterate over and execute each draw command */ - offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf); - nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) - { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x * glfw.fb_scale.x), - (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y), - (GLint)(cmd->clip_rect.w * glfw.fb_scale.x), - (GLint)(cmd->clip_rect.h * glfw.fb_scale.y)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(&glfw.ctx); - nk_buffer_free(&vbuf); - nk_buffer_free(&ebuf); - } - - /* default OpenGL state */ - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, 0); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glPopAttrib(); -} - -NK_API void -nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint) -{ - (void)win; - if (glfw.text_len < NK_GLFW_TEXT_MAX) - glfw.text[glfw.text_len++] = codepoint; -} - -NK_API void -nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff) -{ - (void)win; (void)xoff; - glfw.scroll.x += (float)xoff; - glfw.scroll.y += (float)yoff; -} - -NK_API void -nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) -{ - double x, y; - if (button != GLFW_MOUSE_BUTTON_LEFT) return; - glfwGetCursorPos(window, &x, &y); - if (action == GLFW_PRESS) { - double dt = glfwGetTime() - glfw.last_button_click; - if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) - nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_true); - glfw.last_button_click = glfwGetTime(); - } else nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_false); -} - -NK_INTERN void -nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) -{ - const char *text = glfwGetClipboardString(glfw.win); - if (text) nk_textedit_paste(edit, text, nk_strlen(text)); - (void)usr; -} - -NK_INTERN void -nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len) -{ - char *str = 0; - (void)usr; - if (!len) return; - str = (char*)malloc((size_t)len+1); - if (!str) return; - NK_MEMCPY(str, text, (size_t)len); - str[len] = '\0'; - glfwSetClipboardString(glfw.win, str); - free(str); -} - -NK_API struct nk_context* -nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state) -{ - glfw.win = win; - if (init_state == NK_GLFW3_INSTALL_CALLBACKS) { - glfwSetScrollCallback(win, nk_gflw3_scroll_callback); - glfwSetCharCallback(win, nk_glfw3_char_callback); - glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback); - } - nk_init_default(&glfw.ctx, 0); - glfw.ctx.clip.copy = nk_glfw3_clipbard_copy; - glfw.ctx.clip.paste = nk_glfw3_clipbard_paste; - glfw.ctx.clip.userdata = nk_handle_ptr(0); - nk_buffer_init_default(&glfw.ogl.cmds); - return &glfw.ctx; -} - -NK_API void -nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas) -{ - nk_font_atlas_init_default(&glfw.atlas); - nk_font_atlas_begin(&glfw.atlas); - *atlas = &glfw.atlas; -} - -NK_API void -nk_glfw3_font_stash_end(void) -{ - const void *image; int w, h; - image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - nk_glfw3_device_upload_atlas(image, w, h); - nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null); - if (glfw.atlas.default_font) - nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle); -} - -NK_API void -nk_glfw3_new_frame(void) -{ - int i; - double x, y; - struct nk_context *ctx = &glfw.ctx; - struct GLFWwindow *win = glfw.win; - - glfwGetWindowSize(win, &glfw.width, &glfw.height); - glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height); - glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width; - glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height; - - nk_input_begin(ctx); - for (i = 0; i < glfw.text_len; ++i) - nk_input_unicode(ctx, glfw.text[i]); - - /* optional grabbing behavior */ - if (ctx->input.mouse.grab) - glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - else if (ctx->input.mouse.ungrab) - glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - - nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS|| - glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS); - - if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || - glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) { - nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_V) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); - } else { - nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_COPY, 0); - nk_input_key(ctx, NK_KEY_PASTE, 0); - nk_input_key(ctx, NK_KEY_CUT, 0); - nk_input_key(ctx, NK_KEY_SHIFT, 0); - } - - glfwGetCursorPos(win, &x, &y); - nk_input_motion(ctx, (int)x, (int)y); - if (ctx->input.mouse.grabbed) { - glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y); - ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; - ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; - } - - nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); - nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); - nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); - nk_input_scroll(ctx, glfw.scroll); - nk_input_end(&glfw.ctx); - glfw.text_len = 0; - glfw.scroll = nk_vec2(0,0); -} - -NK_API -void nk_glfw3_shutdown(void) -{ - struct nk_glfw_device *dev = &glfw.ogl; - nk_font_atlas_clear(&glfw.atlas); - nk_free(&glfw.ctx); - glDeleteTextures(1, &dev->font_tex); - nk_buffer_free(&dev->cmds); - NK_MEMSET(&glfw, 0, sizeof(glfw)); -} - -#endif diff --git a/src/external/glfw/deps/stb_image_write.h b/src/external/glfw/deps/stb_image_write.h deleted file mode 100644 index 4319c0de..00000000 --- a/src/external/glfw/deps/stb_image_write.h +++ /dev/null @@ -1,1048 +0,0 @@ -/* stb_image_write - v1.02 - public domain - http://nothings.org/stb/stb_image_write.h - writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015 - no warranty implied; use at your own risk - - Before #including, - - #define STB_IMAGE_WRITE_IMPLEMENTATION - - in the file that you want to have the implementation. - - Will probably not work correctly with strict-aliasing optimizations. - -ABOUT: - - This header file is a library for writing images to C stdio. It could be - adapted to write to memory or a general streaming interface; let me know. - - The PNG output is not optimal; it is 20-50% larger than the file - written by a decent optimizing implementation. This library is designed - for source code compactness and simplicity, not optimal image file size - or run-time performance. - -BUILDING: - - You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. - You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace - malloc,realloc,free. - You can define STBIW_MEMMOVE() to replace memmove() - -USAGE: - - There are four functions, one for each image file format: - - int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); - int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); - int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); - int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); - - There are also four equivalent functions that use an arbitrary write function. You are - expected to open/close your file-equivalent before and after calling these: - - int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); - int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); - int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); - int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); - - where the callback is: - void stbi_write_func(void *context, void *data, int size); - - You can define STBI_WRITE_NO_STDIO to disable the file variant of these - functions, so the library will not use stdio.h at all. However, this will - also disable HDR writing, because it requires stdio for formatted output. - - Each function returns 0 on failure and non-0 on success. - - The functions create an image file defined by the parameters. The image - is a rectangle of pixels stored from left-to-right, top-to-bottom. - Each pixel contains 'comp' channels of data stored interleaved with 8-bits - per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is - monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. - The *data pointer points to the first byte of the top-left-most pixel. - For PNG, "stride_in_bytes" is the distance in bytes from the first byte of - a row of pixels to the first byte of the next row of pixels. - - PNG creates output files with the same number of components as the input. - The BMP format expands Y to RGB in the file format and does not - output alpha. - - PNG supports writing rectangles of data even when the bytes storing rows of - data are not consecutive in memory (e.g. sub-rectangles of a larger image), - by supplying the stride between the beginning of adjacent rows. The other - formats do not. (Thus you cannot write a native-format BMP through the BMP - writer, both because it is in BGR order and because it may have padding - at the end of the line.) - - HDR expects linear float data. Since the format is always 32-bit rgb(e) - data, alpha (if provided) is discarded, and for monochrome data it is - replicated across all three channels. - - TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed - data, set the global variable 'stbi_write_tga_with_rle' to 0. - -CREDITS: - - PNG/BMP/TGA - Sean Barrett - HDR - Baldur Karlsson - TGA monochrome: - Jean-Sebastien Guay - misc enhancements: - Tim Kelsey - TGA RLE - Alan Hickman - initial file IO callback implementation - Emmanuel Julien - bugfixes: - github:Chribba - Guillaume Chereau - github:jry2 - github:romigrou - Sergio Gonzalez - Jonas Karlsson - Filip Wasil - Thatcher Ulrich - -LICENSE - -This software is dual-licensed to the public domain and under the following -license: you are granted a perpetual, irrevocable license to copy, modify, -publish, and distribute this file as you see fit. - -*/ - -#ifndef INCLUDE_STB_IMAGE_WRITE_H -#define INCLUDE_STB_IMAGE_WRITE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef STB_IMAGE_WRITE_STATIC -#define STBIWDEF static -#else -#define STBIWDEF extern -extern int stbi_write_tga_with_rle; -#endif - -#ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); -STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); -#endif - -typedef void stbi_write_func(void *context, void *data, int size); - -STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); -STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); - -#ifdef __cplusplus -} -#endif - -#endif//INCLUDE_STB_IMAGE_WRITE_H - -#ifdef STB_IMAGE_WRITE_IMPLEMENTATION - -#ifdef _WIN32 - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif - #ifndef _CRT_NONSTDC_NO_DEPRECATE - #define _CRT_NONSTDC_NO_DEPRECATE - #endif -#endif - -#ifndef STBI_WRITE_NO_STDIO -#include -#endif // STBI_WRITE_NO_STDIO - -#include -#include -#include -#include - -#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) -// ok -#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) -// ok -#else -#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." -#endif - -#ifndef STBIW_MALLOC -#define STBIW_MALLOC(sz) malloc(sz) -#define STBIW_REALLOC(p,newsz) realloc(p,newsz) -#define STBIW_FREE(p) free(p) -#endif - -#ifndef STBIW_REALLOC_SIZED -#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) -#endif - - -#ifndef STBIW_MEMMOVE -#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) -#endif - - -#ifndef STBIW_ASSERT -#include -#define STBIW_ASSERT(x) assert(x) -#endif - -#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) - -typedef struct -{ - stbi_write_func *func; - void *context; -} stbi__write_context; - -// initialize a callback-based context -static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) -{ - s->func = c; - s->context = context; -} - -#ifndef STBI_WRITE_NO_STDIO - -static void stbi__stdio_write(void *context, void *data, int size) -{ - fwrite(data,1,size,(FILE*) context); -} - -static int stbi__start_write_file(stbi__write_context *s, const char *filename) -{ - FILE *f = fopen(filename, "wb"); - stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); - return f != NULL; -} - -static void stbi__end_write_file(stbi__write_context *s) -{ - fclose((FILE *)s->context); -} - -#endif // !STBI_WRITE_NO_STDIO - -typedef unsigned int stbiw_uint32; -typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; - -#ifdef STB_IMAGE_WRITE_STATIC -static int stbi_write_tga_with_rle = 1; -#else -int stbi_write_tga_with_rle = 1; -#endif - -static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) -{ - while (*fmt) { - switch (*fmt++) { - case ' ': break; - case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); - s->func(s->context,&x,1); - break; } - case '2': { int x = va_arg(v,int); - unsigned char b[2]; - b[0] = STBIW_UCHAR(x); - b[1] = STBIW_UCHAR(x>>8); - s->func(s->context,b,2); - break; } - case '4': { stbiw_uint32 x = va_arg(v,int); - unsigned char b[4]; - b[0]=STBIW_UCHAR(x); - b[1]=STBIW_UCHAR(x>>8); - b[2]=STBIW_UCHAR(x>>16); - b[3]=STBIW_UCHAR(x>>24); - s->func(s->context,b,4); - break; } - default: - STBIW_ASSERT(0); - return; - } - } -} - -static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) -{ - va_list v; - va_start(v, fmt); - stbiw__writefv(s, fmt, v); - va_end(v); -} - -static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) -{ - unsigned char arr[3]; - arr[0] = a, arr[1] = b, arr[2] = c; - s->func(s->context, arr, 3); -} - -static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) -{ - unsigned char bg[3] = { 255, 0, 255}, px[3]; - int k; - - if (write_alpha < 0) - s->func(s->context, &d[comp - 1], 1); - - switch (comp) { - case 1: - s->func(s->context,d,1); - break; - case 2: - if (expand_mono) - stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp - else - s->func(s->context, d, 1); // monochrome TGA - break; - case 4: - if (!write_alpha) { - // composite against pink background - for (k = 0; k < 3; ++k) - px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; - stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); - break; - } - /* FALLTHROUGH */ - case 3: - stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); - break; - } - if (write_alpha > 0) - s->func(s->context, &d[comp - 1], 1); -} - -static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) -{ - stbiw_uint32 zero = 0; - int i,j, j_end; - - if (y <= 0) - return; - - if (vdir < 0) - j_end = -1, j = y-1; - else - j_end = y, j = 0; - - for (; j != j_end; j += vdir) { - for (i=0; i < x; ++i) { - unsigned char *d = (unsigned char *) data + (j*x+i)*comp; - stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); - } - s->func(s->context, &zero, scanline_pad); - } -} - -static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) -{ - if (y < 0 || x < 0) { - return 0; - } else { - va_list v; - va_start(v, fmt); - stbiw__writefv(s, fmt, v); - va_end(v); - stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); - return 1; - } -} - -static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) -{ - int pad = (-x*3) & 3; - return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, - "11 4 22 4" "4 44 22 444444", - 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header - 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header -} - -STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_bmp_core(&s, x, y, comp, data); -} - -#ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_bmp_core(&s, x, y, comp, data); - stbi__end_write_file(&s); - return r; - } else - return 0; -} -#endif //!STBI_WRITE_NO_STDIO - -static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) -{ - int has_alpha = (comp == 2 || comp == 4); - int colorbytes = has_alpha ? comp-1 : comp; - int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 - - if (y < 0 || x < 0) - return 0; - - if (!stbi_write_tga_with_rle) { - return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, - "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); - } else { - int i,j,k; - - stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); - - for (j = y - 1; j >= 0; --j) { - unsigned char *row = (unsigned char *) data + j * x * comp; - int len; - - for (i = 0; i < x; i += len) { - unsigned char *begin = row + i * comp; - int diff = 1; - len = 1; - - if (i < x - 1) { - ++len; - diff = memcmp(begin, row + (i + 1) * comp, comp); - if (diff) { - const unsigned char *prev = begin; - for (k = i + 2; k < x && len < 128; ++k) { - if (memcmp(prev, row + k * comp, comp)) { - prev += comp; - ++len; - } else { - --len; - break; - } - } - } else { - for (k = i + 2; k < x && len < 128; ++k) { - if (!memcmp(begin, row + k * comp, comp)) { - ++len; - } else { - break; - } - } - } - } - - if (diff) { - unsigned char header = STBIW_UCHAR(len - 1); - s->func(s->context, &header, 1); - for (k = 0; k < len; ++k) { - stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); - } - } else { - unsigned char header = STBIW_UCHAR(len - 129); - s->func(s->context, &header, 1); - stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); - } - } - } - } - return 1; -} - -int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_tga_core(&s, x, y, comp, (void *) data); -} - -#ifndef STBI_WRITE_NO_STDIO -int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); - stbi__end_write_file(&s); - return r; - } else - return 0; -} -#endif - -// ************************************************************************************************* -// Radiance RGBE HDR writer -// by Baldur Karlsson -#ifndef STBI_WRITE_NO_STDIO - -#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) - -void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) -{ - int exponent; - float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); - - if (maxcomp < 1e-32f) { - rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; - } else { - float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; - - rgbe[0] = (unsigned char)(linear[0] * normalize); - rgbe[1] = (unsigned char)(linear[1] * normalize); - rgbe[2] = (unsigned char)(linear[2] * normalize); - rgbe[3] = (unsigned char)(exponent + 128); - } -} - -void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) -{ - unsigned char lengthbyte = STBIW_UCHAR(length+128); - STBIW_ASSERT(length+128 <= 255); - s->func(s->context, &lengthbyte, 1); - s->func(s->context, &databyte, 1); -} - -void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) -{ - unsigned char lengthbyte = STBIW_UCHAR(length); - STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code - s->func(s->context, &lengthbyte, 1); - s->func(s->context, data, length); -} - -void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) -{ - unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; - unsigned char rgbe[4]; - float linear[3]; - int x; - - scanlineheader[2] = (width&0xff00)>>8; - scanlineheader[3] = (width&0x00ff); - - /* skip RLE for images too small or large */ - if (width < 8 || width >= 32768) { - for (x=0; x < width; x++) { - switch (ncomp) { - case 4: /* fallthrough */ - case 3: linear[2] = scanline[x*ncomp + 2]; - linear[1] = scanline[x*ncomp + 1]; - linear[0] = scanline[x*ncomp + 0]; - break; - default: - linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; - break; - } - stbiw__linear_to_rgbe(rgbe, linear); - s->func(s->context, rgbe, 4); - } - } else { - int c,r; - /* encode into scratch buffer */ - for (x=0; x < width; x++) { - switch(ncomp) { - case 4: /* fallthrough */ - case 3: linear[2] = scanline[x*ncomp + 2]; - linear[1] = scanline[x*ncomp + 1]; - linear[0] = scanline[x*ncomp + 0]; - break; - default: - linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; - break; - } - stbiw__linear_to_rgbe(rgbe, linear); - scratch[x + width*0] = rgbe[0]; - scratch[x + width*1] = rgbe[1]; - scratch[x + width*2] = rgbe[2]; - scratch[x + width*3] = rgbe[3]; - } - - s->func(s->context, scanlineheader, 4); - - /* RLE each component separately */ - for (c=0; c < 4; c++) { - unsigned char *comp = &scratch[width*c]; - - x = 0; - while (x < width) { - // find first run - r = x; - while (r+2 < width) { - if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) - break; - ++r; - } - if (r+2 >= width) - r = width; - // dump up to first run - while (x < r) { - int len = r-x; - if (len > 128) len = 128; - stbiw__write_dump_data(s, len, &comp[x]); - x += len; - } - // if there's a run, output it - if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd - // find next byte after run - while (r < width && comp[r] == comp[x]) - ++r; - // output run up to r - while (x < r) { - int len = r-x; - if (len > 127) len = 127; - stbiw__write_run_data(s, len, comp[x]); - x += len; - } - } - } - } - } -} - -static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) -{ - if (y <= 0 || x <= 0 || data == NULL) - return 0; - else { - // Each component is stored separately. Allocate scratch space for full output scanline. - unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); - int i, len; - char buffer[128]; - char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; - s->func(s->context, header, sizeof(header)-1); - - len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); - s->func(s->context, buffer, len); - - for(i=0; i < y; i++) - stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x); - STBIW_FREE(scratch); - return 1; - } -} - -int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) -{ - stbi__write_context s; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_hdr_core(&s, x, y, comp, (float *) data); -} - -int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) -{ - stbi__write_context s; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); - stbi__end_write_file(&s); - return r; - } else - return 0; -} -#endif // STBI_WRITE_NO_STDIO - - -////////////////////////////////////////////////////////////////////////////// -// -// PNG writer -// - -// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() -#define stbiw__sbraw(a) ((int *) (a) - 2) -#define stbiw__sbm(a) stbiw__sbraw(a)[0] -#define stbiw__sbn(a) stbiw__sbraw(a)[1] - -#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) -#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) -#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) - -#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) -#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) -#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) - -static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) -{ - int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; - void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); - STBIW_ASSERT(p); - if (p) { - if (!*arr) ((int *) p)[1] = 0; - *arr = (void *) ((int *) p + 2); - stbiw__sbm(*arr) = m; - } - return *arr; -} - -static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) -{ - while (*bitcount >= 8) { - stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); - *bitbuffer >>= 8; - *bitcount -= 8; - } - return data; -} - -static int stbiw__zlib_bitrev(int code, int codebits) -{ - int res=0; - while (codebits--) { - res = (res << 1) | (code & 1); - code >>= 1; - } - return res; -} - -static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) -{ - int i; - for (i=0; i < limit && i < 258; ++i) - if (a[i] != b[i]) break; - return i; -} - -static unsigned int stbiw__zhash(unsigned char *data) -{ - stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - return hash; -} - -#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) -#define stbiw__zlib_add(code,codebits) \ - (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) -#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) -// default huffman tables -#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) -#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) -#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) -#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) -#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) -#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) - -#define stbiw__ZHASH 16384 - -unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) -{ - static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; - static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; - static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; - static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; - unsigned int bitbuf=0; - int i,j, bitcount=0; - unsigned char *out = NULL; - unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); - if (quality < 5) quality = 5; - - stbiw__sbpush(out, 0x78); // DEFLATE 32K window - stbiw__sbpush(out, 0x5e); // FLEVEL = 1 - stbiw__zlib_add(1,1); // BFINAL = 1 - stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman - - for (i=0; i < stbiw__ZHASH; ++i) - hash_table[i] = NULL; - - i=0; - while (i < data_len-3) { - // hash next 3 bytes of data to be compressed - int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; - unsigned char *bestloc = 0; - unsigned char **hlist = hash_table[h]; - int n = stbiw__sbcount(hlist); - for (j=0; j < n; ++j) { - if (hlist[j]-data > i-32768) { // if entry lies within window - int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); - if (d >= best) best=d,bestloc=hlist[j]; - } - } - // when hash table entry is too long, delete half the entries - if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { - STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); - stbiw__sbn(hash_table[h]) = quality; - } - stbiw__sbpush(hash_table[h],data+i); - - if (bestloc) { - // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal - h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); - hlist = hash_table[h]; - n = stbiw__sbcount(hlist); - for (j=0; j < n; ++j) { - if (hlist[j]-data > i-32767) { - int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); - if (e > best) { // if next match is better, bail on current match - bestloc = NULL; - break; - } - } - } - } - - if (bestloc) { - int d = (int) (data+i - bestloc); // distance back - STBIW_ASSERT(d <= 32767 && best <= 258); - for (j=0; best > lengthc[j+1]-1; ++j); - stbiw__zlib_huff(j+257); - if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); - for (j=0; d > distc[j+1]-1; ++j); - stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); - if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); - i += best; - } else { - stbiw__zlib_huffb(data[i]); - ++i; - } - } - // write out final bytes - for (;i < data_len; ++i) - stbiw__zlib_huffb(data[i]); - stbiw__zlib_huff(256); // end of block - // pad with 0 bits to byte boundary - while (bitcount) - stbiw__zlib_add(0,1); - - for (i=0; i < stbiw__ZHASH; ++i) - (void) stbiw__sbfree(hash_table[i]); - STBIW_FREE(hash_table); - - { - // compute adler32 on input - unsigned int s1=1, s2=0; - int blocklen = (int) (data_len % 5552); - j=0; - while (j < data_len) { - for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; - s1 %= 65521, s2 %= 65521; - j += blocklen; - blocklen = 5552; - } - stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s2)); - stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s1)); - } - *out_len = stbiw__sbn(out); - // make returned pointer freeable - STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); - return (unsigned char *) stbiw__sbraw(out); -} - -static unsigned int stbiw__crc32(unsigned char *buffer, int len) -{ - static unsigned int crc_table[256] = - { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - }; - - unsigned int crc = ~0u; - int i; - for (i=0; i < len; ++i) - crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; - return ~crc; -} - -#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) -#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); -#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) - -static void stbiw__wpcrc(unsigned char **data, int len) -{ - unsigned int crc = stbiw__crc32(*data - len - 4, len+4); - stbiw__wp32(*data, crc); -} - -static unsigned char stbiw__paeth(int a, int b, int c) -{ - int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); - if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); - if (pb <= pc) return STBIW_UCHAR(b); - return STBIW_UCHAR(c); -} - -unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) -{ - int ctype[5] = { -1, 0, 4, 2, 6 }; - unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; - unsigned char *out,*o, *filt, *zlib; - signed char *line_buffer; - int i,j,k,p,zlen; - - if (stride_bytes == 0) - stride_bytes = x * n; - - filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; - line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } - for (j=0; j < y; ++j) { - static int mapping[] = { 0,1,2,3,4 }; - static int firstmap[] = { 0,1,0,5,6 }; - int *mymap = j ? mapping : firstmap; - int best = 0, bestval = 0x7fffffff; - for (p=0; p < 2; ++p) { - for (k= p?best:0; k < 5; ++k) { - int type = mymap[k],est=0; - unsigned char *z = pixels + stride_bytes*j; - for (i=0; i < n; ++i) - switch (type) { - case 0: line_buffer[i] = z[i]; break; - case 1: line_buffer[i] = z[i]; break; - case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; - case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break; - case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break; - case 5: line_buffer[i] = z[i]; break; - case 6: line_buffer[i] = z[i]; break; - } - for (i=n; i < x*n; ++i) { - switch (type) { - case 0: line_buffer[i] = z[i]; break; - case 1: line_buffer[i] = z[i] - z[i-n]; break; - case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; - case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break; - case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break; - case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; - case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; - } - } - if (p) break; - for (i=0; i < x*n; ++i) - est += abs((signed char) line_buffer[i]); - if (est < bestval) { bestval = est; best = k; } - } - } - // when we get here, best contains the filter type, and line_buffer contains the data - filt[j*(x*n+1)] = (unsigned char) best; - STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); - } - STBIW_FREE(line_buffer); - zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory - STBIW_FREE(filt); - if (!zlib) return 0; - - // each tag requires 12 bytes of overhead - out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); - if (!out) return 0; - *out_len = 8 + 12+13 + 12+zlen + 12; - - o=out; - STBIW_MEMMOVE(o,sig,8); o+= 8; - stbiw__wp32(o, 13); // header length - stbiw__wptag(o, "IHDR"); - stbiw__wp32(o, x); - stbiw__wp32(o, y); - *o++ = 8; - *o++ = STBIW_UCHAR(ctype[n]); - *o++ = 0; - *o++ = 0; - *o++ = 0; - stbiw__wpcrc(&o,13); - - stbiw__wp32(o, zlen); - stbiw__wptag(o, "IDAT"); - STBIW_MEMMOVE(o, zlib, zlen); - o += zlen; - STBIW_FREE(zlib); - stbiw__wpcrc(&o, zlen); - - stbiw__wp32(o,0); - stbiw__wptag(o, "IEND"); - stbiw__wpcrc(&o,0); - - STBIW_ASSERT(o == out + *out_len); - - return out; -} - -#ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) -{ - FILE *f; - int len; - unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); - if (png == NULL) return 0; - f = fopen(filename, "wb"); - if (!f) { STBIW_FREE(png); return 0; } - fwrite(png, 1, len, f); - fclose(f); - STBIW_FREE(png); - return 1; -} -#endif - -STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) -{ - int len; - unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); - if (png == NULL) return 0; - func(context, png, len); - STBIW_FREE(png); - return 1; -} - -#endif // STB_IMAGE_WRITE_IMPLEMENTATION - -/* Revision history - 1.02 (2016-04-02) - avoid allocating large structures on the stack - 1.01 (2016-01-16) - STBIW_REALLOC_SIZED: support allocators with no realloc support - avoid race-condition in crc initialization - minor compile issues - 1.00 (2015-09-14) - installable file IO function - 0.99 (2015-09-13) - warning fixes; TGA rle support - 0.98 (2015-04-08) - added STBIW_MALLOC, STBIW_ASSERT etc - 0.97 (2015-01-18) - fixed HDR asserts, rewrote HDR rle logic - 0.96 (2015-01-17) - add HDR output - fix monochrome BMP - 0.95 (2014-08-17) - add monochrome TGA output - 0.94 (2014-05-31) - rename private functions to avoid conflicts with stb_image.h - 0.93 (2014-05-27) - warning fixes - 0.92 (2010-08-01) - casts to unsigned char to fix warnings - 0.91 (2010-07-17) - first public release - 0.90 first internal release -*/ diff --git a/src/external/glfw/deps/tinycthread.c b/src/external/glfw/deps/tinycthread.c deleted file mode 100644 index f9cea2ed..00000000 --- a/src/external/glfw/deps/tinycthread.c +++ /dev/null @@ -1,594 +0,0 @@ -/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- -Copyright (c) 2012 Marcus Geelnard - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -/* 2013-01-06 Camilla Löwy - * - * Added casts from time_t to DWORD to avoid warnings on VC++. - * Fixed time retrieval on POSIX systems. - */ - -#include "tinycthread.h" -#include - -/* Platform specific includes */ -#if defined(_TTHREAD_POSIX_) - #include - #include - #include - #include - #include -#elif defined(_TTHREAD_WIN32_) - #include - #include -#endif - -/* Standard, good-to-have defines */ -#ifndef NULL - #define NULL (void*)0 -#endif -#ifndef TRUE - #define TRUE 1 -#endif -#ifndef FALSE - #define FALSE 0 -#endif - -int mtx_init(mtx_t *mtx, int type) -{ -#if defined(_TTHREAD_WIN32_) - mtx->mAlreadyLocked = FALSE; - mtx->mRecursive = type & mtx_recursive; - InitializeCriticalSection(&mtx->mHandle); - return thrd_success; -#else - int ret; - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - if (type & mtx_recursive) - { - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - } - ret = pthread_mutex_init(mtx, &attr); - pthread_mutexattr_destroy(&attr); - return ret == 0 ? thrd_success : thrd_error; -#endif -} - -void mtx_destroy(mtx_t *mtx) -{ -#if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mtx->mHandle); -#else - pthread_mutex_destroy(mtx); -#endif -} - -int mtx_lock(mtx_t *mtx) -{ -#if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mtx->mHandle); - if (!mtx->mRecursive) - { - while(mtx->mAlreadyLocked) Sleep(1000); /* Simulate deadlock... */ - mtx->mAlreadyLocked = TRUE; - } - return thrd_success; -#else - return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; -#endif -} - -int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) -{ - /* FIXME! */ - (void)mtx; - (void)ts; - return thrd_error; -} - -int mtx_trylock(mtx_t *mtx) -{ -#if defined(_TTHREAD_WIN32_) - int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; - if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) - { - LeaveCriticalSection(&mtx->mHandle); - ret = thrd_busy; - } - return ret; -#else - return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; -#endif -} - -int mtx_unlock(mtx_t *mtx) -{ -#if defined(_TTHREAD_WIN32_) - mtx->mAlreadyLocked = FALSE; - LeaveCriticalSection(&mtx->mHandle); - return thrd_success; -#else - return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;; -#endif -} - -#if defined(_TTHREAD_WIN32_) -#define _CONDITION_EVENT_ONE 0 -#define _CONDITION_EVENT_ALL 1 -#endif - -int cnd_init(cnd_t *cond) -{ -#if defined(_TTHREAD_WIN32_) - cond->mWaitersCount = 0; - - /* Init critical section */ - InitializeCriticalSection(&cond->mWaitersCountLock); - - /* Init events */ - cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); - if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) - { - cond->mEvents[_CONDITION_EVENT_ALL] = NULL; - return thrd_error; - } - cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); - if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); - cond->mEvents[_CONDITION_EVENT_ONE] = NULL; - return thrd_error; - } - - return thrd_success; -#else - return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; -#endif -} - -void cnd_destroy(cnd_t *cond) -{ -#if defined(_TTHREAD_WIN32_) - if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); - } - if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); - } - DeleteCriticalSection(&cond->mWaitersCountLock); -#else - pthread_cond_destroy(cond); -#endif -} - -int cnd_signal(cnd_t *cond) -{ -#if defined(_TTHREAD_WIN32_) - int haveWaiters; - - /* Are there any waiters? */ - EnterCriticalSection(&cond->mWaitersCountLock); - haveWaiters = (cond->mWaitersCount > 0); - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* If we have any waiting threads, send them a signal */ - if(haveWaiters) - { - if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) - { - return thrd_error; - } - } - - return thrd_success; -#else - return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; -#endif -} - -int cnd_broadcast(cnd_t *cond) -{ -#if defined(_TTHREAD_WIN32_) - int haveWaiters; - - /* Are there any waiters? */ - EnterCriticalSection(&cond->mWaitersCountLock); - haveWaiters = (cond->mWaitersCount > 0); - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* If we have any waiting threads, send them a signal */ - if(haveWaiters) - { - if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) - { - return thrd_error; - } - } - - return thrd_success; -#else - return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; -#endif -} - -#if defined(_TTHREAD_WIN32_) -static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) -{ - int result, lastWaiter; - - /* Increment number of waiters */ - EnterCriticalSection(&cond->mWaitersCountLock); - ++ cond->mWaitersCount; - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* Release the mutex while waiting for the condition (will decrease - the number of waiters when done)... */ - mtx_unlock(mtx); - - /* Wait for either event to become signaled due to cnd_signal() or - cnd_broadcast() being called */ - result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); - if (result == WAIT_TIMEOUT) - { - return thrd_timeout; - } - else if (result == (int)WAIT_FAILED) - { - return thrd_error; - } - - /* Check if we are the last waiter */ - EnterCriticalSection(&cond->mWaitersCountLock); - -- cond->mWaitersCount; - lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && - (cond->mWaitersCount == 0); - LeaveCriticalSection(&cond->mWaitersCountLock); - - /* If we are the last waiter to be notified to stop waiting, reset the event */ - if (lastWaiter) - { - if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) - { - return thrd_error; - } - } - - /* Re-acquire the mutex */ - mtx_lock(mtx); - - return thrd_success; -} -#endif - -int cnd_wait(cnd_t *cond, mtx_t *mtx) -{ -#if defined(_TTHREAD_WIN32_) - return _cnd_timedwait_win32(cond, mtx, INFINITE); -#else - return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; -#endif -} - -int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) -{ -#if defined(_TTHREAD_WIN32_) - struct timespec now; - if (clock_gettime(CLOCK_REALTIME, &now) == 0) - { - DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 + - (ts->tv_nsec - now.tv_nsec + 500000) / 1000000); - return _cnd_timedwait_win32(cond, mtx, delta); - } - else - return thrd_error; -#else - int ret; - ret = pthread_cond_timedwait(cond, mtx, ts); - if (ret == ETIMEDOUT) - { - return thrd_timeout; - } - return ret == 0 ? thrd_success : thrd_error; -#endif -} - - -/** Information to pass to the new thread (what to run). */ -typedef struct { - thrd_start_t mFunction; /**< Pointer to the function to be executed. */ - void * mArg; /**< Function argument for the thread function. */ -} _thread_start_info; - -/* Thread wrapper function. */ -#if defined(_TTHREAD_WIN32_) -static unsigned WINAPI _thrd_wrapper_function(void * aArg) -#elif defined(_TTHREAD_POSIX_) -static void * _thrd_wrapper_function(void * aArg) -#endif -{ - thrd_start_t fun; - void *arg; - int res; -#if defined(_TTHREAD_POSIX_) - void *pres; -#endif - - /* Get thread startup information */ - _thread_start_info *ti = (_thread_start_info *) aArg; - fun = ti->mFunction; - arg = ti->mArg; - - /* The thread is responsible for freeing the startup information */ - free((void *)ti); - - /* Call the actual client thread function */ - res = fun(arg); - -#if defined(_TTHREAD_WIN32_) - return res; -#else - pres = malloc(sizeof(int)); - if (pres != NULL) - { - *(int*)pres = res; - } - return pres; -#endif -} - -int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) -{ - /* Fill out the thread startup information (passed to the thread wrapper, - which will eventually free it) */ - _thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info)); - if (ti == NULL) - { - return thrd_nomem; - } - ti->mFunction = func; - ti->mArg = arg; - - /* Create the thread */ -#if defined(_TTHREAD_WIN32_) - *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); -#elif defined(_TTHREAD_POSIX_) - if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) - { - *thr = 0; - } -#endif - - /* Did we fail to create the thread? */ - if(!*thr) - { - free(ti); - return thrd_error; - } - - return thrd_success; -} - -thrd_t thrd_current(void) -{ -#if defined(_TTHREAD_WIN32_) - return GetCurrentThread(); -#else - return pthread_self(); -#endif -} - -int thrd_detach(thrd_t thr) -{ - /* FIXME! */ - (void)thr; - return thrd_error; -} - -int thrd_equal(thrd_t thr0, thrd_t thr1) -{ -#if defined(_TTHREAD_WIN32_) - return thr0 == thr1; -#else - return pthread_equal(thr0, thr1); -#endif -} - -void thrd_exit(int res) -{ -#if defined(_TTHREAD_WIN32_) - ExitThread(res); -#else - void *pres = malloc(sizeof(int)); - if (pres != NULL) - { - *(int*)pres = res; - } - pthread_exit(pres); -#endif -} - -int thrd_join(thrd_t thr, int *res) -{ -#if defined(_TTHREAD_WIN32_) - if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) - { - return thrd_error; - } - if (res != NULL) - { - DWORD dwRes; - GetExitCodeThread(thr, &dwRes); - *res = dwRes; - } -#elif defined(_TTHREAD_POSIX_) - void *pres; - int ires = 0; - if (pthread_join(thr, &pres) != 0) - { - return thrd_error; - } - if (pres != NULL) - { - ires = *(int*)pres; - free(pres); - } - if (res != NULL) - { - *res = ires; - } -#endif - return thrd_success; -} - -int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) -{ - struct timespec now; -#if defined(_TTHREAD_WIN32_) - DWORD delta; -#else - long delta; -#endif - - /* Get the current time */ - if (clock_gettime(CLOCK_REALTIME, &now) != 0) - return -2; // FIXME: Some specific error code? - -#if defined(_TTHREAD_WIN32_) - /* Delta in milliseconds */ - delta = (DWORD) ((time_point->tv_sec - now.tv_sec) * 1000 + - (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); - if (delta > 0) - { - Sleep(delta); - } -#else - /* Delta in microseconds */ - delta = (time_point->tv_sec - now.tv_sec) * 1000000L + - (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; - - /* On some systems, the usleep argument must be < 1000000 */ - while (delta > 999999L) - { - usleep(999999); - delta -= 999999L; - } - if (delta > 0L) - { - usleep((useconds_t)delta); - } -#endif - - /* We don't support waking up prematurely (yet) */ - if (remaining) - { - remaining->tv_sec = 0; - remaining->tv_nsec = 0; - } - return 0; -} - -void thrd_yield(void) -{ -#if defined(_TTHREAD_WIN32_) - Sleep(0); -#else - sched_yield(); -#endif -} - -int tss_create(tss_t *key, tss_dtor_t dtor) -{ -#if defined(_TTHREAD_WIN32_) - /* FIXME: The destructor function is not supported yet... */ - if (dtor != NULL) - { - return thrd_error; - } - *key = TlsAlloc(); - if (*key == TLS_OUT_OF_INDEXES) - { - return thrd_error; - } -#else - if (pthread_key_create(key, dtor) != 0) - { - return thrd_error; - } -#endif - return thrd_success; -} - -void tss_delete(tss_t key) -{ -#if defined(_TTHREAD_WIN32_) - TlsFree(key); -#else - pthread_key_delete(key); -#endif -} - -void *tss_get(tss_t key) -{ -#if defined(_TTHREAD_WIN32_) - return TlsGetValue(key); -#else - return pthread_getspecific(key); -#endif -} - -int tss_set(tss_t key, void *val) -{ -#if defined(_TTHREAD_WIN32_) - if (TlsSetValue(key, val) == 0) - { - return thrd_error; - } -#else - if (pthread_setspecific(key, val) != 0) - { - return thrd_error; - } -#endif - return thrd_success; -} - -#if defined(_TTHREAD_EMULATE_CLOCK_GETTIME_) -int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) -{ -#if defined(_TTHREAD_WIN32_) - struct _timeb tb; - _ftime(&tb); - ts->tv_sec = (time_t)tb.time; - ts->tv_nsec = 1000000L * (long)tb.millitm; -#else - struct timeval tv; - gettimeofday(&tv, NULL); - ts->tv_sec = (time_t)tv.tv_sec; - ts->tv_nsec = 1000L * (long)tv.tv_usec; -#endif - return 0; -} -#endif // _TTHREAD_EMULATE_CLOCK_GETTIME_ - diff --git a/src/external/glfw/deps/tinycthread.h b/src/external/glfw/deps/tinycthread.h deleted file mode 100644 index 42958c39..00000000 --- a/src/external/glfw/deps/tinycthread.h +++ /dev/null @@ -1,443 +0,0 @@ -/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- -Copyright (c) 2012 Marcus Geelnard - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef _TINYCTHREAD_H_ -#define _TINYCTHREAD_H_ - -/** -* @file -* @mainpage TinyCThread API Reference -* -* @section intro_sec Introduction -* TinyCThread is a minimal, portable implementation of basic threading -* classes for C. -* -* They closely mimic the functionality and naming of the C11 standard, and -* should be easily replaceable with the corresponding standard variants. -* -* @section port_sec Portability -* The Win32 variant uses the native Win32 API for implementing the thread -* classes, while for other systems, the POSIX threads API (pthread) is used. -* -* @section misc_sec Miscellaneous -* The following special keywords are available: #_Thread_local. -* -* For more detailed information, browse the different sections of this -* documentation. A good place to start is: -* tinycthread.h. -*/ - -/* Which platform are we on? */ -#if !defined(_TTHREAD_PLATFORM_DEFINED_) - #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) - #define _TTHREAD_WIN32_ - #else - #define _TTHREAD_POSIX_ - #endif - #define _TTHREAD_PLATFORM_DEFINED_ -#endif - -/* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ -#if defined(_TTHREAD_POSIX_) - #undef _FEATURES_H - #if !defined(_GNU_SOURCE) - #define _GNU_SOURCE - #endif - #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) - #undef _POSIX_C_SOURCE - #define _POSIX_C_SOURCE 199309L - #endif - #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) - #undef _XOPEN_SOURCE - #define _XOPEN_SOURCE 500 - #endif -#endif - -/* Generic includes */ -#include - -/* Platform specific includes */ -#if defined(_TTHREAD_POSIX_) - #include - #include -#elif defined(_TTHREAD_WIN32_) - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #define __UNDEF_LEAN_AND_MEAN - #endif - #include - #ifdef __UNDEF_LEAN_AND_MEAN - #undef WIN32_LEAN_AND_MEAN - #undef __UNDEF_LEAN_AND_MEAN - #endif -#endif - -/* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC, - it's quite likely that libc does not support it either. Hence, fall back to - the only other supported time specifier: CLOCK_REALTIME (and if that fails, - we're probably emulating clock_gettime anyway, so anything goes). */ -#ifndef TIME_UTC - #ifdef CLOCK_REALTIME - #define TIME_UTC CLOCK_REALTIME - #else - #define TIME_UTC 0 - #endif -#endif - -/* Workaround for missing clock_gettime (most Windows compilers, afaik) */ -#if defined(_TTHREAD_WIN32_) || defined(__APPLE_CC__) -#define _TTHREAD_EMULATE_CLOCK_GETTIME_ -/* Emulate struct timespec */ -#if defined(_TTHREAD_WIN32_) -struct _ttherad_timespec { - time_t tv_sec; - long tv_nsec; -}; -#define timespec _ttherad_timespec -#endif - -/* Emulate clockid_t */ -typedef int _tthread_clockid_t; -#define clockid_t _tthread_clockid_t - -/* Emulate clock_gettime */ -int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); -#define clock_gettime _tthread_clock_gettime -#ifndef CLOCK_REALTIME - #define CLOCK_REALTIME 0 -#endif -#endif - - -/** TinyCThread version (major number). */ -#define TINYCTHREAD_VERSION_MAJOR 1 -/** TinyCThread version (minor number). */ -#define TINYCTHREAD_VERSION_MINOR 1 -/** TinyCThread version (full version). */ -#define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) - -/** -* @def _Thread_local -* Thread local storage keyword. -* A variable that is declared with the @c _Thread_local keyword makes the -* value of the variable local to each thread (known as thread-local storage, -* or TLS). Example usage: -* @code -* // This variable is local to each thread. -* _Thread_local int variable; -* @endcode -* @note The @c _Thread_local keyword is a macro that maps to the corresponding -* compiler directive (e.g. @c __declspec(thread)). -* @note This directive is currently not supported on Mac OS X (it will give -* a compiler error), since compile-time TLS is not supported in the Mac OS X -* executable format. Also, some older versions of MinGW (before GCC 4.x) do -* not support this directive. -* @hideinitializer -*/ - -/* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */ -#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) - #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) - #define _Thread_local __thread - #else - #define _Thread_local __declspec(thread) - #endif -#endif - -/* Macros */ -#define TSS_DTOR_ITERATIONS 0 - -/* Function return values */ -#define thrd_error 0 /**< The requested operation failed */ -#define thrd_success 1 /**< The requested operation succeeded */ -#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ -#define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ -#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ - -/* Mutex types */ -#define mtx_plain 1 -#define mtx_timed 2 -#define mtx_try 4 -#define mtx_recursive 8 - -/* Mutex */ -#if defined(_TTHREAD_WIN32_) -typedef struct { - CRITICAL_SECTION mHandle; /* Critical section handle */ - int mAlreadyLocked; /* TRUE if the mutex is already locked */ - int mRecursive; /* TRUE if the mutex is recursive */ -} mtx_t; -#else -typedef pthread_mutex_t mtx_t; -#endif - -/** Create a mutex object. -* @param mtx A mutex object. -* @param type Bit-mask that must have one of the following six values: -* @li @c mtx_plain for a simple non-recursive mutex -* @li @c mtx_timed for a non-recursive mutex that supports timeout -* @li @c mtx_try for a non-recursive mutex that supports test and return -* @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) -* @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) -* @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ -int mtx_init(mtx_t *mtx, int type); - -/** Release any resources used by the given mutex. -* @param mtx A mutex object. -*/ -void mtx_destroy(mtx_t *mtx); - -/** Lock the given mutex. -* Blocks until the given mutex can be locked. If the mutex is non-recursive, and -* the calling thread already has a lock on the mutex, this call will block -* forever. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ -int mtx_lock(mtx_t *mtx); - -/** NOT YET IMPLEMENTED. -*/ -int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); - -/** Try to lock the given mutex. -* The specified mutex shall support either test and return or timeout. If the -* mutex is already locked, the function returns without blocking. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_busy if the resource -* requested is already in use, or @ref thrd_error if the request could not be -* honored. -*/ -int mtx_trylock(mtx_t *mtx); - -/** Unlock the given mutex. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ -int mtx_unlock(mtx_t *mtx); - -/* Condition variable */ -#if defined(_TTHREAD_WIN32_) -typedef struct { - HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ - unsigned int mWaitersCount; /* Count of the number of waiters. */ - CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ -} cnd_t; -#else -typedef pthread_cond_t cnd_t; -#endif - -/** Create a condition variable object. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ -int cnd_init(cnd_t *cond); - -/** Release any resources used by the given condition variable. -* @param cond A condition variable object. -*/ -void cnd_destroy(cnd_t *cond); - -/** Signal a condition variable. -* Unblocks one of the threads that are blocked on the given condition variable -* at the time of the call. If no threads are blocked on the condition variable -* at the time of the call, the function does nothing and return success. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ -int cnd_signal(cnd_t *cond); - -/** Broadcast a condition variable. -* Unblocks all of the threads that are blocked on the given condition variable -* at the time of the call. If no threads are blocked on the condition variable -* at the time of the call, the function does nothing and return success. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ -int cnd_broadcast(cnd_t *cond); - -/** Wait for a condition variable to become signaled. -* The function atomically unlocks the given mutex and endeavors to block until -* the given condition variable is signaled by a call to cnd_signal or to -* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex -* before it returns. -* @param cond A condition variable object. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ -int cnd_wait(cnd_t *cond, mtx_t *mtx); - -/** Wait for a condition variable to become signaled. -* The function atomically unlocks the given mutex and endeavors to block until -* the given condition variable is signaled by a call to cnd_signal or to -* cnd_broadcast, or until after the specified time. When the calling thread -* becomes unblocked it locks the mutex before it returns. -* @param cond A condition variable object. -* @param mtx A mutex object. -* @param xt A point in time at which the request will time out (absolute time). -* @return @ref thrd_success upon success, or @ref thrd_timeout if the time -* specified in the call was reached without acquiring the requested resource, or -* @ref thrd_error if the request could not be honored. -*/ -int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); - -/* Thread */ -#if defined(_TTHREAD_WIN32_) -typedef HANDLE thrd_t; -#else -typedef pthread_t thrd_t; -#endif - -/** Thread start function. -* Any thread that is started with the @ref thrd_create() function must be -* started through a function of this type. -* @param arg The thread argument (the @c arg argument of the corresponding -* @ref thrd_create() call). -* @return The thread return value, which can be obtained by another thread -* by using the @ref thrd_join() function. -*/ -typedef int (*thrd_start_t)(void *arg); - -/** Create a new thread. -* @param thr Identifier of the newly created thread. -* @param func A function pointer to the function that will be executed in -* the new thread. -* @param arg An argument to the thread function. -* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could -* be allocated for the thread requested, or @ref thrd_error if the request -* could not be honored. -* @note A thread’s identifier may be reused for a different thread once the -* original thread has exited and either been detached or joined to another -* thread. -*/ -int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); - -/** Identify the calling thread. -* @return The identifier of the calling thread. -*/ -thrd_t thrd_current(void); - -/** NOT YET IMPLEMENTED. -*/ -int thrd_detach(thrd_t thr); - -/** Compare two thread identifiers. -* The function determines if two thread identifiers refer to the same thread. -* @return Zero if the two thread identifiers refer to different threads. -* Otherwise a nonzero value is returned. -*/ -int thrd_equal(thrd_t thr0, thrd_t thr1); - -/** Terminate execution of the calling thread. -* @param res Result code of the calling thread. -*/ -void thrd_exit(int res); - -/** Wait for a thread to terminate. -* The function joins the given thread with the current thread by blocking -* until the other thread has terminated. -* @param thr The thread to join with. -* @param res If this pointer is not NULL, the function will store the result -* code of the given thread in the integer pointed to by @c res. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ -int thrd_join(thrd_t thr, int *res); - -/** Put the calling thread to sleep. -* Suspend execution of the calling thread. -* @param time_point A point in time at which the thread will resume (absolute time). -* @param remaining If non-NULL, this parameter will hold the remaining time until -* time_point upon return. This will typically be zero, but if -* the thread was woken up by a signal that is not ignored before -* time_point was reached @c remaining will hold a positive -* time. -* @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. -*/ -int thrd_sleep(const struct timespec *time_point, struct timespec *remaining); - -/** Yield execution to another thread. -* Permit other threads to run, even if the current thread would ordinarily -* continue to run. -*/ -void thrd_yield(void); - -/* Thread local storage */ -#if defined(_TTHREAD_WIN32_) -typedef DWORD tss_t; -#else -typedef pthread_key_t tss_t; -#endif - -/** Destructor function for a thread-specific storage. -* @param val The value of the destructed thread-specific storage. -*/ -typedef void (*tss_dtor_t)(void *val); - -/** Create a thread-specific storage. -* @param key The unique key identifier that will be set if the function is -* successful. -* @param dtor Destructor function. This can be NULL. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -* @note The destructor function is not supported under Windows. If @c dtor is -* not NULL when calling this function under Windows, the function will fail -* and return @ref thrd_error. -*/ -int tss_create(tss_t *key, tss_dtor_t dtor); - -/** Delete a thread-specific storage. -* The function releases any resources used by the given thread-specific -* storage. -* @param key The key that shall be deleted. -*/ -void tss_delete(tss_t key); - -/** Get the value for a thread-specific storage. -* @param key The thread-specific storage identifier. -* @return The value for the current thread held in the given thread-specific -* storage. -*/ -void *tss_get(tss_t key); - -/** Set the value for a thread-specific storage. -* @param key The thread-specific storage identifier. -* @param val The value of the thread-specific storage to set for the current -* thread. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ -int tss_set(tss_t key, void *val); - - -#endif /* _TINYTHREAD_H_ */ - diff --git a/src/external/glfw/deps/vulkan/vk_platform.h b/src/external/glfw/deps/vulkan/vk_platform.h deleted file mode 100644 index 0fa62ee2..00000000 --- a/src/external/glfw/deps/vulkan/vk_platform.h +++ /dev/null @@ -1,120 +0,0 @@ -// -// File: vk_platform.h -// -/* -** Copyright (c) 2014-2015 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - - -#ifndef VK_PLATFORM_H_ -#define VK_PLATFORM_H_ - -#ifdef __cplusplus -extern "C" -{ -#endif // __cplusplus - -/* -*************************************************************************************************** -* Platform-specific directives and type declarations -*************************************************************************************************** -*/ - -/* Platform-specific calling convention macros. - * - * Platforms should define these so that Vulkan clients call Vulkan commands - * with the same calling conventions that the Vulkan implementation expects. - * - * VKAPI_ATTR - Placed before the return type in function declarations. - * Useful for C++11 and GCC/Clang-style function attribute syntax. - * VKAPI_CALL - Placed after the return type in function declarations. - * Useful for MSVC-style calling convention syntax. - * VKAPI_PTR - Placed between the '(' and '*' in function pointer types. - * - * Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); - * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); - */ -#if defined(_WIN32) - // On Windows, Vulkan commands use the stdcall convention - #define VKAPI_ATTR - #define VKAPI_CALL __stdcall - #define VKAPI_PTR VKAPI_CALL -#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 - #error "Vulkan isn't supported for the 'armeabi' NDK ABI" -#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) - // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" - // calling convention, i.e. float parameters are passed in registers. This - // is true even if the rest of the application passes floats on the stack, - // as it does by default when compiling for the armeabi-v7a NDK ABI. - #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) - #define VKAPI_CALL - #define VKAPI_PTR VKAPI_ATTR -#else - // On other platforms, use the default calling convention - #define VKAPI_ATTR - #define VKAPI_CALL - #define VKAPI_PTR -#endif - -#include - -#if !defined(VK_NO_STDINT_H) - #if defined(_MSC_VER) && (_MSC_VER < 1600) - typedef signed __int8 int8_t; - typedef unsigned __int8 uint8_t; - typedef signed __int16 int16_t; - typedef unsigned __int16 uint16_t; - typedef signed __int32 int32_t; - typedef unsigned __int32 uint32_t; - typedef signed __int64 int64_t; - typedef unsigned __int64 uint64_t; - #else - #include - #endif -#endif // !defined(VK_NO_STDINT_H) - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -// Platform-specific headers required by platform window system extensions. -// These are enabled prior to #including "vulkan.h". The same enable then -// controls inclusion of the extension interfaces in vulkan.h. - -#ifdef VK_USE_PLATFORM_ANDROID_KHR -#include -#endif - -#ifdef VK_USE_PLATFORM_MIR_KHR -#include -#endif - -#ifdef VK_USE_PLATFORM_WAYLAND_KHR -#include -#endif - -#ifdef VK_USE_PLATFORM_WIN32_KHR -#include -#endif - -#ifdef VK_USE_PLATFORM_XLIB_KHR -#include -#endif - -#ifdef VK_USE_PLATFORM_XCB_KHR -#include -#endif - -#endif diff --git a/src/external/glfw/deps/vulkan/vulkan.h b/src/external/glfw/deps/vulkan/vulkan.h deleted file mode 100644 index 81dedf77..00000000 --- a/src/external/glfw/deps/vulkan/vulkan.h +++ /dev/null @@ -1,4763 +0,0 @@ -#ifndef VULKAN_H_ -#define VULKAN_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2017 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - -#define VK_VERSION_1_0 1 -#include "vk_platform.h" - -#define VK_MAKE_VERSION(major, minor, patch) \ - (((major) << 22) | ((minor) << 12) | (patch)) - -// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. -//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) - -// Vulkan 1.0 version number -#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0) - -#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) -#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) -#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) -// Version of this file -#define VK_HEADER_VERSION 39 - - -#define VK_NULL_HANDLE 0 - - - -#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; - - -#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE) -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) - #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; -#else - #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; -#endif -#endif - - - -typedef uint32_t VkFlags; -typedef uint32_t VkBool32; -typedef uint64_t VkDeviceSize; -typedef uint32_t VkSampleMask; - -VK_DEFINE_HANDLE(VkInstance) -VK_DEFINE_HANDLE(VkPhysicalDevice) -VK_DEFINE_HANDLE(VkDevice) -VK_DEFINE_HANDLE(VkQueue) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) -VK_DEFINE_HANDLE(VkCommandBuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) - -#define VK_LOD_CLAMP_NONE 1000.0f -#define VK_REMAINING_MIP_LEVELS (~0U) -#define VK_REMAINING_ARRAY_LAYERS (~0U) -#define VK_WHOLE_SIZE (~0ULL) -#define VK_ATTACHMENT_UNUSED (~0U) -#define VK_TRUE 1 -#define VK_FALSE 0 -#define VK_QUEUE_FAMILY_IGNORED (~0U) -#define VK_SUBPASS_EXTERNAL (~0U) -#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 -#define VK_UUID_SIZE 16 -#define VK_MAX_MEMORY_TYPES 32 -#define VK_MAX_MEMORY_HEAPS 16 -#define VK_MAX_EXTENSION_NAME_SIZE 256 -#define VK_MAX_DESCRIPTION_SIZE 256 - - -typedef enum VkPipelineCacheHeaderVersion { - VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, - VK_PIPELINE_CACHE_HEADER_VERSION_BEGIN_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, - VK_PIPELINE_CACHE_HEADER_VERSION_END_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, - VK_PIPELINE_CACHE_HEADER_VERSION_RANGE_SIZE = (VK_PIPELINE_CACHE_HEADER_VERSION_ONE - VK_PIPELINE_CACHE_HEADER_VERSION_ONE + 1), - VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF -} VkPipelineCacheHeaderVersion; - -typedef enum VkResult { - VK_SUCCESS = 0, - VK_NOT_READY = 1, - VK_TIMEOUT = 2, - VK_EVENT_SET = 3, - VK_EVENT_RESET = 4, - VK_INCOMPLETE = 5, - VK_ERROR_OUT_OF_HOST_MEMORY = -1, - VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, - VK_ERROR_INITIALIZATION_FAILED = -3, - VK_ERROR_DEVICE_LOST = -4, - VK_ERROR_MEMORY_MAP_FAILED = -5, - VK_ERROR_LAYER_NOT_PRESENT = -6, - VK_ERROR_EXTENSION_NOT_PRESENT = -7, - VK_ERROR_FEATURE_NOT_PRESENT = -8, - VK_ERROR_INCOMPATIBLE_DRIVER = -9, - VK_ERROR_TOO_MANY_OBJECTS = -10, - VK_ERROR_FORMAT_NOT_SUPPORTED = -11, - VK_ERROR_FRAGMENTED_POOL = -12, - VK_ERROR_SURFACE_LOST_KHR = -1000000000, - VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, - VK_SUBOPTIMAL_KHR = 1000001003, - VK_ERROR_OUT_OF_DATE_KHR = -1000001004, - VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, - VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, - VK_ERROR_INVALID_SHADER_NV = -1000012000, - VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000, - VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL, - VK_RESULT_END_RANGE = VK_INCOMPLETE, - VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1), - VK_RESULT_MAX_ENUM = 0x7FFFFFFF -} VkResult; - -typedef enum VkStructureType { - VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, - VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, - VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, - VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, - VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, - VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, - VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, - VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, - VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, - VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, - VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, - VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, - VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, - VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, - VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, - VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, - VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, - VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, - VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, - VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, - VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, - VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, - VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, - VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000, - VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, - VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, - VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, - VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, - VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, - VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, - VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, - VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, - VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, - VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, - VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001, - VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001, - VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008, - VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, - VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, - VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000, - VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001, - VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002, - VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003, - VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004, - VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005, - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = 1000090000, - VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000, - VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001, - VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002, - VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, - VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO, - VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO, - VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1), - VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkStructureType; - -typedef enum VkSystemAllocationScope { - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, - VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, - VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, - VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, - VK_SYSTEM_ALLOCATION_SCOPE_BEGIN_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND, - VK_SYSTEM_ALLOCATION_SCOPE_END_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE, - VK_SYSTEM_ALLOCATION_SCOPE_RANGE_SIZE = (VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND + 1), - VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF -} VkSystemAllocationScope; - -typedef enum VkInternalAllocationType { - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, - VK_INTERNAL_ALLOCATION_TYPE_BEGIN_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, - VK_INTERNAL_ALLOCATION_TYPE_END_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, - VK_INTERNAL_ALLOCATION_TYPE_RANGE_SIZE = (VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE + 1), - VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkInternalAllocationType; - -typedef enum VkFormat { - VK_FORMAT_UNDEFINED = 0, - VK_FORMAT_R4G4_UNORM_PACK8 = 1, - VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, - VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, - VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, - VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, - VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, - VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, - VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, - VK_FORMAT_R8_UNORM = 9, - VK_FORMAT_R8_SNORM = 10, - VK_FORMAT_R8_USCALED = 11, - VK_FORMAT_R8_SSCALED = 12, - VK_FORMAT_R8_UINT = 13, - VK_FORMAT_R8_SINT = 14, - VK_FORMAT_R8_SRGB = 15, - VK_FORMAT_R8G8_UNORM = 16, - VK_FORMAT_R8G8_SNORM = 17, - VK_FORMAT_R8G8_USCALED = 18, - VK_FORMAT_R8G8_SSCALED = 19, - VK_FORMAT_R8G8_UINT = 20, - VK_FORMAT_R8G8_SINT = 21, - VK_FORMAT_R8G8_SRGB = 22, - VK_FORMAT_R8G8B8_UNORM = 23, - VK_FORMAT_R8G8B8_SNORM = 24, - VK_FORMAT_R8G8B8_USCALED = 25, - VK_FORMAT_R8G8B8_SSCALED = 26, - VK_FORMAT_R8G8B8_UINT = 27, - VK_FORMAT_R8G8B8_SINT = 28, - VK_FORMAT_R8G8B8_SRGB = 29, - VK_FORMAT_B8G8R8_UNORM = 30, - VK_FORMAT_B8G8R8_SNORM = 31, - VK_FORMAT_B8G8R8_USCALED = 32, - VK_FORMAT_B8G8R8_SSCALED = 33, - VK_FORMAT_B8G8R8_UINT = 34, - VK_FORMAT_B8G8R8_SINT = 35, - VK_FORMAT_B8G8R8_SRGB = 36, - VK_FORMAT_R8G8B8A8_UNORM = 37, - VK_FORMAT_R8G8B8A8_SNORM = 38, - VK_FORMAT_R8G8B8A8_USCALED = 39, - VK_FORMAT_R8G8B8A8_SSCALED = 40, - VK_FORMAT_R8G8B8A8_UINT = 41, - VK_FORMAT_R8G8B8A8_SINT = 42, - VK_FORMAT_R8G8B8A8_SRGB = 43, - VK_FORMAT_B8G8R8A8_UNORM = 44, - VK_FORMAT_B8G8R8A8_SNORM = 45, - VK_FORMAT_B8G8R8A8_USCALED = 46, - VK_FORMAT_B8G8R8A8_SSCALED = 47, - VK_FORMAT_B8G8R8A8_UINT = 48, - VK_FORMAT_B8G8R8A8_SINT = 49, - VK_FORMAT_B8G8R8A8_SRGB = 50, - VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, - VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, - VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, - VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, - VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, - VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, - VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, - VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, - VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, - VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, - VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, - VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, - VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, - VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, - VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, - VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, - VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, - VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, - VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, - VK_FORMAT_R16_UNORM = 70, - VK_FORMAT_R16_SNORM = 71, - VK_FORMAT_R16_USCALED = 72, - VK_FORMAT_R16_SSCALED = 73, - VK_FORMAT_R16_UINT = 74, - VK_FORMAT_R16_SINT = 75, - VK_FORMAT_R16_SFLOAT = 76, - VK_FORMAT_R16G16_UNORM = 77, - VK_FORMAT_R16G16_SNORM = 78, - VK_FORMAT_R16G16_USCALED = 79, - VK_FORMAT_R16G16_SSCALED = 80, - VK_FORMAT_R16G16_UINT = 81, - VK_FORMAT_R16G16_SINT = 82, - VK_FORMAT_R16G16_SFLOAT = 83, - VK_FORMAT_R16G16B16_UNORM = 84, - VK_FORMAT_R16G16B16_SNORM = 85, - VK_FORMAT_R16G16B16_USCALED = 86, - VK_FORMAT_R16G16B16_SSCALED = 87, - VK_FORMAT_R16G16B16_UINT = 88, - VK_FORMAT_R16G16B16_SINT = 89, - VK_FORMAT_R16G16B16_SFLOAT = 90, - VK_FORMAT_R16G16B16A16_UNORM = 91, - VK_FORMAT_R16G16B16A16_SNORM = 92, - VK_FORMAT_R16G16B16A16_USCALED = 93, - VK_FORMAT_R16G16B16A16_SSCALED = 94, - VK_FORMAT_R16G16B16A16_UINT = 95, - VK_FORMAT_R16G16B16A16_SINT = 96, - VK_FORMAT_R16G16B16A16_SFLOAT = 97, - VK_FORMAT_R32_UINT = 98, - VK_FORMAT_R32_SINT = 99, - VK_FORMAT_R32_SFLOAT = 100, - VK_FORMAT_R32G32_UINT = 101, - VK_FORMAT_R32G32_SINT = 102, - VK_FORMAT_R32G32_SFLOAT = 103, - VK_FORMAT_R32G32B32_UINT = 104, - VK_FORMAT_R32G32B32_SINT = 105, - VK_FORMAT_R32G32B32_SFLOAT = 106, - VK_FORMAT_R32G32B32A32_UINT = 107, - VK_FORMAT_R32G32B32A32_SINT = 108, - VK_FORMAT_R32G32B32A32_SFLOAT = 109, - VK_FORMAT_R64_UINT = 110, - VK_FORMAT_R64_SINT = 111, - VK_FORMAT_R64_SFLOAT = 112, - VK_FORMAT_R64G64_UINT = 113, - VK_FORMAT_R64G64_SINT = 114, - VK_FORMAT_R64G64_SFLOAT = 115, - VK_FORMAT_R64G64B64_UINT = 116, - VK_FORMAT_R64G64B64_SINT = 117, - VK_FORMAT_R64G64B64_SFLOAT = 118, - VK_FORMAT_R64G64B64A64_UINT = 119, - VK_FORMAT_R64G64B64A64_SINT = 120, - VK_FORMAT_R64G64B64A64_SFLOAT = 121, - VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, - VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, - VK_FORMAT_D16_UNORM = 124, - VK_FORMAT_X8_D24_UNORM_PACK32 = 125, - VK_FORMAT_D32_SFLOAT = 126, - VK_FORMAT_S8_UINT = 127, - VK_FORMAT_D16_UNORM_S8_UINT = 128, - VK_FORMAT_D24_UNORM_S8_UINT = 129, - VK_FORMAT_D32_SFLOAT_S8_UINT = 130, - VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, - VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, - VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, - VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, - VK_FORMAT_BC2_UNORM_BLOCK = 135, - VK_FORMAT_BC2_SRGB_BLOCK = 136, - VK_FORMAT_BC3_UNORM_BLOCK = 137, - VK_FORMAT_BC3_SRGB_BLOCK = 138, - VK_FORMAT_BC4_UNORM_BLOCK = 139, - VK_FORMAT_BC4_SNORM_BLOCK = 140, - VK_FORMAT_BC5_UNORM_BLOCK = 141, - VK_FORMAT_BC5_SNORM_BLOCK = 142, - VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, - VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, - VK_FORMAT_BC7_UNORM_BLOCK = 145, - VK_FORMAT_BC7_SRGB_BLOCK = 146, - VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, - VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, - VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, - VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, - VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, - VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, - VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, - VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, - VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, - VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, - VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, - VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, - VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, - VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, - VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, - VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, - VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, - VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, - VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, - VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, - VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, - VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, - VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, - VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, - VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, - VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, - VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, - VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, - VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, - VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, - VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, - VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, - VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, - VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, - VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, - VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, - VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, - VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, - VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, - VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, - VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, - VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003, - VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004, - VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, - VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, - VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, - VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED, - VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK, - VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1), - VK_FORMAT_MAX_ENUM = 0x7FFFFFFF -} VkFormat; - -typedef enum VkImageType { - VK_IMAGE_TYPE_1D = 0, - VK_IMAGE_TYPE_2D = 1, - VK_IMAGE_TYPE_3D = 2, - VK_IMAGE_TYPE_BEGIN_RANGE = VK_IMAGE_TYPE_1D, - VK_IMAGE_TYPE_END_RANGE = VK_IMAGE_TYPE_3D, - VK_IMAGE_TYPE_RANGE_SIZE = (VK_IMAGE_TYPE_3D - VK_IMAGE_TYPE_1D + 1), - VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkImageType; - -typedef enum VkImageTiling { - VK_IMAGE_TILING_OPTIMAL = 0, - VK_IMAGE_TILING_LINEAR = 1, - VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR, - VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1), - VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF -} VkImageTiling; - -typedef enum VkPhysicalDeviceType { - VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, - VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, - VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, - VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, - VK_PHYSICAL_DEVICE_TYPE_CPU = 4, - VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE = VK_PHYSICAL_DEVICE_TYPE_OTHER, - VK_PHYSICAL_DEVICE_TYPE_END_RANGE = VK_PHYSICAL_DEVICE_TYPE_CPU, - VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE = (VK_PHYSICAL_DEVICE_TYPE_CPU - VK_PHYSICAL_DEVICE_TYPE_OTHER + 1), - VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkPhysicalDeviceType; - -typedef enum VkQueryType { - VK_QUERY_TYPE_OCCLUSION = 0, - VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, - VK_QUERY_TYPE_TIMESTAMP = 2, - VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION, - VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP, - VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1), - VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkQueryType; - -typedef enum VkSharingMode { - VK_SHARING_MODE_EXCLUSIVE = 0, - VK_SHARING_MODE_CONCURRENT = 1, - VK_SHARING_MODE_BEGIN_RANGE = VK_SHARING_MODE_EXCLUSIVE, - VK_SHARING_MODE_END_RANGE = VK_SHARING_MODE_CONCURRENT, - VK_SHARING_MODE_RANGE_SIZE = (VK_SHARING_MODE_CONCURRENT - VK_SHARING_MODE_EXCLUSIVE + 1), - VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF -} VkSharingMode; - -typedef enum VkImageLayout { - VK_IMAGE_LAYOUT_UNDEFINED = 0, - VK_IMAGE_LAYOUT_GENERAL = 1, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7, - VK_IMAGE_LAYOUT_PREINITIALIZED = 8, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, - VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_END_RANGE = VK_IMAGE_LAYOUT_PREINITIALIZED, - VK_IMAGE_LAYOUT_RANGE_SIZE = (VK_IMAGE_LAYOUT_PREINITIALIZED - VK_IMAGE_LAYOUT_UNDEFINED + 1), - VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF -} VkImageLayout; - -typedef enum VkImageViewType { - VK_IMAGE_VIEW_TYPE_1D = 0, - VK_IMAGE_VIEW_TYPE_2D = 1, - VK_IMAGE_VIEW_TYPE_3D = 2, - VK_IMAGE_VIEW_TYPE_CUBE = 3, - VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, - VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, - VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, - VK_IMAGE_VIEW_TYPE_BEGIN_RANGE = VK_IMAGE_VIEW_TYPE_1D, - VK_IMAGE_VIEW_TYPE_END_RANGE = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, - VK_IMAGE_VIEW_TYPE_RANGE_SIZE = (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY - VK_IMAGE_VIEW_TYPE_1D + 1), - VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkImageViewType; - -typedef enum VkComponentSwizzle { - VK_COMPONENT_SWIZZLE_IDENTITY = 0, - VK_COMPONENT_SWIZZLE_ZERO = 1, - VK_COMPONENT_SWIZZLE_ONE = 2, - VK_COMPONENT_SWIZZLE_R = 3, - VK_COMPONENT_SWIZZLE_G = 4, - VK_COMPONENT_SWIZZLE_B = 5, - VK_COMPONENT_SWIZZLE_A = 6, - VK_COMPONENT_SWIZZLE_BEGIN_RANGE = VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_END_RANGE = VK_COMPONENT_SWIZZLE_A, - VK_COMPONENT_SWIZZLE_RANGE_SIZE = (VK_COMPONENT_SWIZZLE_A - VK_COMPONENT_SWIZZLE_IDENTITY + 1), - VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF -} VkComponentSwizzle; - -typedef enum VkVertexInputRate { - VK_VERTEX_INPUT_RATE_VERTEX = 0, - VK_VERTEX_INPUT_RATE_INSTANCE = 1, - VK_VERTEX_INPUT_RATE_BEGIN_RANGE = VK_VERTEX_INPUT_RATE_VERTEX, - VK_VERTEX_INPUT_RATE_END_RANGE = VK_VERTEX_INPUT_RATE_INSTANCE, - VK_VERTEX_INPUT_RATE_RANGE_SIZE = (VK_VERTEX_INPUT_RATE_INSTANCE - VK_VERTEX_INPUT_RATE_VERTEX + 1), - VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF -} VkVertexInputRate; - -typedef enum VkPrimitiveTopology { - VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, - VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, - VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5, - VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6, - VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, - VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, - VK_PRIMITIVE_TOPOLOGY_BEGIN_RANGE = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, - VK_PRIMITIVE_TOPOLOGY_END_RANGE = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, - VK_PRIMITIVE_TOPOLOGY_RANGE_SIZE = (VK_PRIMITIVE_TOPOLOGY_PATCH_LIST - VK_PRIMITIVE_TOPOLOGY_POINT_LIST + 1), - VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF -} VkPrimitiveTopology; - -typedef enum VkPolygonMode { - VK_POLYGON_MODE_FILL = 0, - VK_POLYGON_MODE_LINE = 1, - VK_POLYGON_MODE_POINT = 2, - VK_POLYGON_MODE_BEGIN_RANGE = VK_POLYGON_MODE_FILL, - VK_POLYGON_MODE_END_RANGE = VK_POLYGON_MODE_POINT, - VK_POLYGON_MODE_RANGE_SIZE = (VK_POLYGON_MODE_POINT - VK_POLYGON_MODE_FILL + 1), - VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF -} VkPolygonMode; - -typedef enum VkFrontFace { - VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, - VK_FRONT_FACE_CLOCKWISE = 1, - VK_FRONT_FACE_BEGIN_RANGE = VK_FRONT_FACE_COUNTER_CLOCKWISE, - VK_FRONT_FACE_END_RANGE = VK_FRONT_FACE_CLOCKWISE, - VK_FRONT_FACE_RANGE_SIZE = (VK_FRONT_FACE_CLOCKWISE - VK_FRONT_FACE_COUNTER_CLOCKWISE + 1), - VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF -} VkFrontFace; - -typedef enum VkCompareOp { - VK_COMPARE_OP_NEVER = 0, - VK_COMPARE_OP_LESS = 1, - VK_COMPARE_OP_EQUAL = 2, - VK_COMPARE_OP_LESS_OR_EQUAL = 3, - VK_COMPARE_OP_GREATER = 4, - VK_COMPARE_OP_NOT_EQUAL = 5, - VK_COMPARE_OP_GREATER_OR_EQUAL = 6, - VK_COMPARE_OP_ALWAYS = 7, - VK_COMPARE_OP_BEGIN_RANGE = VK_COMPARE_OP_NEVER, - VK_COMPARE_OP_END_RANGE = VK_COMPARE_OP_ALWAYS, - VK_COMPARE_OP_RANGE_SIZE = (VK_COMPARE_OP_ALWAYS - VK_COMPARE_OP_NEVER + 1), - VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF -} VkCompareOp; - -typedef enum VkStencilOp { - VK_STENCIL_OP_KEEP = 0, - VK_STENCIL_OP_ZERO = 1, - VK_STENCIL_OP_REPLACE = 2, - VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3, - VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, - VK_STENCIL_OP_INVERT = 5, - VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, - VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, - VK_STENCIL_OP_BEGIN_RANGE = VK_STENCIL_OP_KEEP, - VK_STENCIL_OP_END_RANGE = VK_STENCIL_OP_DECREMENT_AND_WRAP, - VK_STENCIL_OP_RANGE_SIZE = (VK_STENCIL_OP_DECREMENT_AND_WRAP - VK_STENCIL_OP_KEEP + 1), - VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF -} VkStencilOp; - -typedef enum VkLogicOp { - VK_LOGIC_OP_CLEAR = 0, - VK_LOGIC_OP_AND = 1, - VK_LOGIC_OP_AND_REVERSE = 2, - VK_LOGIC_OP_COPY = 3, - VK_LOGIC_OP_AND_INVERTED = 4, - VK_LOGIC_OP_NO_OP = 5, - VK_LOGIC_OP_XOR = 6, - VK_LOGIC_OP_OR = 7, - VK_LOGIC_OP_NOR = 8, - VK_LOGIC_OP_EQUIVALENT = 9, - VK_LOGIC_OP_INVERT = 10, - VK_LOGIC_OP_OR_REVERSE = 11, - VK_LOGIC_OP_COPY_INVERTED = 12, - VK_LOGIC_OP_OR_INVERTED = 13, - VK_LOGIC_OP_NAND = 14, - VK_LOGIC_OP_SET = 15, - VK_LOGIC_OP_BEGIN_RANGE = VK_LOGIC_OP_CLEAR, - VK_LOGIC_OP_END_RANGE = VK_LOGIC_OP_SET, - VK_LOGIC_OP_RANGE_SIZE = (VK_LOGIC_OP_SET - VK_LOGIC_OP_CLEAR + 1), - VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF -} VkLogicOp; - -typedef enum VkBlendFactor { - VK_BLEND_FACTOR_ZERO = 0, - VK_BLEND_FACTOR_ONE = 1, - VK_BLEND_FACTOR_SRC_COLOR = 2, - VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3, - VK_BLEND_FACTOR_DST_COLOR = 4, - VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5, - VK_BLEND_FACTOR_SRC_ALPHA = 6, - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7, - VK_BLEND_FACTOR_DST_ALPHA = 8, - VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9, - VK_BLEND_FACTOR_CONSTANT_COLOR = 10, - VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11, - VK_BLEND_FACTOR_CONSTANT_ALPHA = 12, - VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13, - VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14, - VK_BLEND_FACTOR_SRC1_COLOR = 15, - VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, - VK_BLEND_FACTOR_SRC1_ALPHA = 17, - VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, - VK_BLEND_FACTOR_BEGIN_RANGE = VK_BLEND_FACTOR_ZERO, - VK_BLEND_FACTOR_END_RANGE = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, - VK_BLEND_FACTOR_RANGE_SIZE = (VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA - VK_BLEND_FACTOR_ZERO + 1), - VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF -} VkBlendFactor; - -typedef enum VkBlendOp { - VK_BLEND_OP_ADD = 0, - VK_BLEND_OP_SUBTRACT = 1, - VK_BLEND_OP_REVERSE_SUBTRACT = 2, - VK_BLEND_OP_MIN = 3, - VK_BLEND_OP_MAX = 4, - VK_BLEND_OP_BEGIN_RANGE = VK_BLEND_OP_ADD, - VK_BLEND_OP_END_RANGE = VK_BLEND_OP_MAX, - VK_BLEND_OP_RANGE_SIZE = (VK_BLEND_OP_MAX - VK_BLEND_OP_ADD + 1), - VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF -} VkBlendOp; - -typedef enum VkDynamicState { - VK_DYNAMIC_STATE_VIEWPORT = 0, - VK_DYNAMIC_STATE_SCISSOR = 1, - VK_DYNAMIC_STATE_LINE_WIDTH = 2, - VK_DYNAMIC_STATE_DEPTH_BIAS = 3, - VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4, - VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5, - VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, - VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, - VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, - VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE, - VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1), - VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF -} VkDynamicState; - -typedef enum VkFilter { - VK_FILTER_NEAREST = 0, - VK_FILTER_LINEAR = 1, - VK_FILTER_CUBIC_IMG = 1000015000, - VK_FILTER_BEGIN_RANGE = VK_FILTER_NEAREST, - VK_FILTER_END_RANGE = VK_FILTER_LINEAR, - VK_FILTER_RANGE_SIZE = (VK_FILTER_LINEAR - VK_FILTER_NEAREST + 1), - VK_FILTER_MAX_ENUM = 0x7FFFFFFF -} VkFilter; - -typedef enum VkSamplerMipmapMode { - VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, - VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, - VK_SAMPLER_MIPMAP_MODE_BEGIN_RANGE = VK_SAMPLER_MIPMAP_MODE_NEAREST, - VK_SAMPLER_MIPMAP_MODE_END_RANGE = VK_SAMPLER_MIPMAP_MODE_LINEAR, - VK_SAMPLER_MIPMAP_MODE_RANGE_SIZE = (VK_SAMPLER_MIPMAP_MODE_LINEAR - VK_SAMPLER_MIPMAP_MODE_NEAREST + 1), - VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF -} VkSamplerMipmapMode; - -typedef enum VkSamplerAddressMode { - VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, - VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, - VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, - VK_SAMPLER_ADDRESS_MODE_BEGIN_RANGE = VK_SAMPLER_ADDRESS_MODE_REPEAT, - VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, - VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1), - VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF -} VkSamplerAddressMode; - -typedef enum VkBorderColor { - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, - VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, - VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2, - VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3, - VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, - VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, - VK_BORDER_COLOR_BEGIN_RANGE = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, - VK_BORDER_COLOR_END_RANGE = VK_BORDER_COLOR_INT_OPAQUE_WHITE, - VK_BORDER_COLOR_RANGE_SIZE = (VK_BORDER_COLOR_INT_OPAQUE_WHITE - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + 1), - VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF -} VkBorderColor; - -typedef enum VkDescriptorType { - VK_DESCRIPTOR_TYPE_SAMPLER = 0, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, - VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2, - VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3, - VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4, - VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6, - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, - VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, - VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER, - VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, - VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1), - VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkDescriptorType; - -typedef enum VkAttachmentLoadOp { - VK_ATTACHMENT_LOAD_OP_LOAD = 0, - VK_ATTACHMENT_LOAD_OP_CLEAR = 1, - VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, - VK_ATTACHMENT_LOAD_OP_BEGIN_RANGE = VK_ATTACHMENT_LOAD_OP_LOAD, - VK_ATTACHMENT_LOAD_OP_END_RANGE = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_RANGE_SIZE = (VK_ATTACHMENT_LOAD_OP_DONT_CARE - VK_ATTACHMENT_LOAD_OP_LOAD + 1), - VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF -} VkAttachmentLoadOp; - -typedef enum VkAttachmentStoreOp { - VK_ATTACHMENT_STORE_OP_STORE = 0, - VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, - VK_ATTACHMENT_STORE_OP_BEGIN_RANGE = VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_STORE_OP_END_RANGE = VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_RANGE_SIZE = (VK_ATTACHMENT_STORE_OP_DONT_CARE - VK_ATTACHMENT_STORE_OP_STORE + 1), - VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF -} VkAttachmentStoreOp; - -typedef enum VkPipelineBindPoint { - VK_PIPELINE_BIND_POINT_GRAPHICS = 0, - VK_PIPELINE_BIND_POINT_COMPUTE = 1, - VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS, - VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE, - VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1), - VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF -} VkPipelineBindPoint; - -typedef enum VkCommandBufferLevel { - VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, - VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, - VK_COMMAND_BUFFER_LEVEL_BEGIN_RANGE = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - VK_COMMAND_BUFFER_LEVEL_END_RANGE = VK_COMMAND_BUFFER_LEVEL_SECONDARY, - VK_COMMAND_BUFFER_LEVEL_RANGE_SIZE = (VK_COMMAND_BUFFER_LEVEL_SECONDARY - VK_COMMAND_BUFFER_LEVEL_PRIMARY + 1), - VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF -} VkCommandBufferLevel; - -typedef enum VkIndexType { - VK_INDEX_TYPE_UINT16 = 0, - VK_INDEX_TYPE_UINT32 = 1, - VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16, - VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32, - VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1), - VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkIndexType; - -typedef enum VkSubpassContents { - VK_SUBPASS_CONTENTS_INLINE = 0, - VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, - VK_SUBPASS_CONTENTS_BEGIN_RANGE = VK_SUBPASS_CONTENTS_INLINE, - VK_SUBPASS_CONTENTS_END_RANGE = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, - VK_SUBPASS_CONTENTS_RANGE_SIZE = (VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS - VK_SUBPASS_CONTENTS_INLINE + 1), - VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF -} VkSubpassContents; - -typedef VkFlags VkInstanceCreateFlags; - -typedef enum VkFormatFeatureFlagBits { - VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, - VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, - VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, - VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, - VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, - VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, - VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, - VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, - VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, - VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, - VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000, - VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000, - VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkFormatFeatureFlagBits; -typedef VkFlags VkFormatFeatureFlags; - -typedef enum VkImageUsageFlagBits { - VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, - VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, - VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, - VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, - VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkImageUsageFlagBits; -typedef VkFlags VkImageUsageFlags; - -typedef enum VkImageCreateFlagBits { - VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, - VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, - VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, - VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, - VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, - VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020, - VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkImageCreateFlagBits; -typedef VkFlags VkImageCreateFlags; - -typedef enum VkSampleCountFlagBits { - VK_SAMPLE_COUNT_1_BIT = 0x00000001, - VK_SAMPLE_COUNT_2_BIT = 0x00000002, - VK_SAMPLE_COUNT_4_BIT = 0x00000004, - VK_SAMPLE_COUNT_8_BIT = 0x00000008, - VK_SAMPLE_COUNT_16_BIT = 0x00000010, - VK_SAMPLE_COUNT_32_BIT = 0x00000020, - VK_SAMPLE_COUNT_64_BIT = 0x00000040, - VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSampleCountFlagBits; -typedef VkFlags VkSampleCountFlags; - -typedef enum VkQueueFlagBits { - VK_QUEUE_GRAPHICS_BIT = 0x00000001, - VK_QUEUE_COMPUTE_BIT = 0x00000002, - VK_QUEUE_TRANSFER_BIT = 0x00000004, - VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, - VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueueFlagBits; -typedef VkFlags VkQueueFlags; - -typedef enum VkMemoryPropertyFlagBits { - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, - VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, - VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, - VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkMemoryPropertyFlagBits; -typedef VkFlags VkMemoryPropertyFlags; - -typedef enum VkMemoryHeapFlagBits { - VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, - VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkMemoryHeapFlagBits; -typedef VkFlags VkMemoryHeapFlags; -typedef VkFlags VkDeviceCreateFlags; -typedef VkFlags VkDeviceQueueCreateFlags; - -typedef enum VkPipelineStageFlagBits { - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, - VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, - VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, - VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, - VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, - VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, - VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, - VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, - VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000, - VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkPipelineStageFlagBits; -typedef VkFlags VkPipelineStageFlags; -typedef VkFlags VkMemoryMapFlags; - -typedef enum VkImageAspectFlagBits { - VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, - VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, - VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, - VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, - VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkImageAspectFlagBits; -typedef VkFlags VkImageAspectFlags; - -typedef enum VkSparseImageFormatFlagBits { - VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, - VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, - VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, - VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSparseImageFormatFlagBits; -typedef VkFlags VkSparseImageFormatFlags; - -typedef enum VkSparseMemoryBindFlagBits { - VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, - VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSparseMemoryBindFlagBits; -typedef VkFlags VkSparseMemoryBindFlags; - -typedef enum VkFenceCreateFlagBits { - VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, - VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkFenceCreateFlagBits; -typedef VkFlags VkFenceCreateFlags; -typedef VkFlags VkSemaphoreCreateFlags; -typedef VkFlags VkEventCreateFlags; -typedef VkFlags VkQueryPoolCreateFlags; - -typedef enum VkQueryPipelineStatisticFlagBits { - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, - VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, - VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, - VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, - VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, - VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, - VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, - VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, - VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueryPipelineStatisticFlagBits; -typedef VkFlags VkQueryPipelineStatisticFlags; - -typedef enum VkQueryResultFlagBits { - VK_QUERY_RESULT_64_BIT = 0x00000001, - VK_QUERY_RESULT_WAIT_BIT = 0x00000002, - VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, - VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, - VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueryResultFlagBits; -typedef VkFlags VkQueryResultFlags; - -typedef enum VkBufferCreateFlagBits { - VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, - VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, - VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, - VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkBufferCreateFlagBits; -typedef VkFlags VkBufferCreateFlags; - -typedef enum VkBufferUsageFlagBits { - VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, - VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, - VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, - VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, - VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, - VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkBufferUsageFlagBits; -typedef VkFlags VkBufferUsageFlags; -typedef VkFlags VkBufferViewCreateFlags; -typedef VkFlags VkImageViewCreateFlags; -typedef VkFlags VkShaderModuleCreateFlags; -typedef VkFlags VkPipelineCacheCreateFlags; - -typedef enum VkPipelineCreateFlagBits { - VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, - VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, - VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, - VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkPipelineCreateFlagBits; -typedef VkFlags VkPipelineCreateFlags; -typedef VkFlags VkPipelineShaderStageCreateFlags; - -typedef enum VkShaderStageFlagBits { - VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, - VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, - VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, - VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, - VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, - VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, - VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, - VK_SHADER_STAGE_ALL = 0x7FFFFFFF, - VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkShaderStageFlagBits; -typedef VkFlags VkPipelineVertexInputStateCreateFlags; -typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; -typedef VkFlags VkPipelineTessellationStateCreateFlags; -typedef VkFlags VkPipelineViewportStateCreateFlags; -typedef VkFlags VkPipelineRasterizationStateCreateFlags; - -typedef enum VkCullModeFlagBits { - VK_CULL_MODE_NONE = 0, - VK_CULL_MODE_FRONT_BIT = 0x00000001, - VK_CULL_MODE_BACK_BIT = 0x00000002, - VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, - VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCullModeFlagBits; -typedef VkFlags VkCullModeFlags; -typedef VkFlags VkPipelineMultisampleStateCreateFlags; -typedef VkFlags VkPipelineDepthStencilStateCreateFlags; -typedef VkFlags VkPipelineColorBlendStateCreateFlags; - -typedef enum VkColorComponentFlagBits { - VK_COLOR_COMPONENT_R_BIT = 0x00000001, - VK_COLOR_COMPONENT_G_BIT = 0x00000002, - VK_COLOR_COMPONENT_B_BIT = 0x00000004, - VK_COLOR_COMPONENT_A_BIT = 0x00000008, - VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkColorComponentFlagBits; -typedef VkFlags VkColorComponentFlags; -typedef VkFlags VkPipelineDynamicStateCreateFlags; -typedef VkFlags VkPipelineLayoutCreateFlags; -typedef VkFlags VkShaderStageFlags; -typedef VkFlags VkSamplerCreateFlags; -typedef VkFlags VkDescriptorSetLayoutCreateFlags; - -typedef enum VkDescriptorPoolCreateFlagBits { - VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, - VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkDescriptorPoolCreateFlagBits; -typedef VkFlags VkDescriptorPoolCreateFlags; -typedef VkFlags VkDescriptorPoolResetFlags; -typedef VkFlags VkFramebufferCreateFlags; -typedef VkFlags VkRenderPassCreateFlags; - -typedef enum VkAttachmentDescriptionFlagBits { - VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, - VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkAttachmentDescriptionFlagBits; -typedef VkFlags VkAttachmentDescriptionFlags; -typedef VkFlags VkSubpassDescriptionFlags; - -typedef enum VkAccessFlagBits { - VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, - VK_ACCESS_INDEX_READ_BIT = 0x00000002, - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, - VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, - VK_ACCESS_SHADER_READ_BIT = 0x00000020, - VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, - VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, - VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, - VK_ACCESS_HOST_READ_BIT = 0x00002000, - VK_ACCESS_HOST_WRITE_BIT = 0x00004000, - VK_ACCESS_MEMORY_READ_BIT = 0x00008000, - VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, - VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000, - VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000, - VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkAccessFlagBits; -typedef VkFlags VkAccessFlags; - -typedef enum VkDependencyFlagBits { - VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, - VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkDependencyFlagBits; -typedef VkFlags VkDependencyFlags; - -typedef enum VkCommandPoolCreateFlagBits { - VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, - VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, - VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandPoolCreateFlagBits; -typedef VkFlags VkCommandPoolCreateFlags; - -typedef enum VkCommandPoolResetFlagBits { - VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, - VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandPoolResetFlagBits; -typedef VkFlags VkCommandPoolResetFlags; - -typedef enum VkCommandBufferUsageFlagBits { - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, - VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, - VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandBufferUsageFlagBits; -typedef VkFlags VkCommandBufferUsageFlags; - -typedef enum VkQueryControlFlagBits { - VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, - VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueryControlFlagBits; -typedef VkFlags VkQueryControlFlags; - -typedef enum VkCommandBufferResetFlagBits { - VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, - VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandBufferResetFlagBits; -typedef VkFlags VkCommandBufferResetFlags; - -typedef enum VkStencilFaceFlagBits { - VK_STENCIL_FACE_FRONT_BIT = 0x00000001, - VK_STENCIL_FACE_BACK_BIT = 0x00000002, - VK_STENCIL_FRONT_AND_BACK = 0x00000003, - VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkStencilFaceFlagBits; -typedef VkFlags VkStencilFaceFlags; - -typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( - void* pUserData, - size_t size, - size_t alignment, - VkSystemAllocationScope allocationScope); - -typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( - void* pUserData, - void* pOriginal, - size_t size, - size_t alignment, - VkSystemAllocationScope allocationScope); - -typedef void (VKAPI_PTR *PFN_vkFreeFunction)( - void* pUserData, - void* pMemory); - -typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( - void* pUserData, - size_t size, - VkInternalAllocationType allocationType, - VkSystemAllocationScope allocationScope); - -typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( - void* pUserData, - size_t size, - VkInternalAllocationType allocationType, - VkSystemAllocationScope allocationScope); - -typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); - -typedef struct VkApplicationInfo { - VkStructureType sType; - const void* pNext; - const char* pApplicationName; - uint32_t applicationVersion; - const char* pEngineName; - uint32_t engineVersion; - uint32_t apiVersion; -} VkApplicationInfo; - -typedef struct VkInstanceCreateInfo { - VkStructureType sType; - const void* pNext; - VkInstanceCreateFlags flags; - const VkApplicationInfo* pApplicationInfo; - uint32_t enabledLayerCount; - const char* const* ppEnabledLayerNames; - uint32_t enabledExtensionCount; - const char* const* ppEnabledExtensionNames; -} VkInstanceCreateInfo; - -typedef struct VkAllocationCallbacks { - void* pUserData; - PFN_vkAllocationFunction pfnAllocation; - PFN_vkReallocationFunction pfnReallocation; - PFN_vkFreeFunction pfnFree; - PFN_vkInternalAllocationNotification pfnInternalAllocation; - PFN_vkInternalFreeNotification pfnInternalFree; -} VkAllocationCallbacks; - -typedef struct VkPhysicalDeviceFeatures { - VkBool32 robustBufferAccess; - VkBool32 fullDrawIndexUint32; - VkBool32 imageCubeArray; - VkBool32 independentBlend; - VkBool32 geometryShader; - VkBool32 tessellationShader; - VkBool32 sampleRateShading; - VkBool32 dualSrcBlend; - VkBool32 logicOp; - VkBool32 multiDrawIndirect; - VkBool32 drawIndirectFirstInstance; - VkBool32 depthClamp; - VkBool32 depthBiasClamp; - VkBool32 fillModeNonSolid; - VkBool32 depthBounds; - VkBool32 wideLines; - VkBool32 largePoints; - VkBool32 alphaToOne; - VkBool32 multiViewport; - VkBool32 samplerAnisotropy; - VkBool32 textureCompressionETC2; - VkBool32 textureCompressionASTC_LDR; - VkBool32 textureCompressionBC; - VkBool32 occlusionQueryPrecise; - VkBool32 pipelineStatisticsQuery; - VkBool32 vertexPipelineStoresAndAtomics; - VkBool32 fragmentStoresAndAtomics; - VkBool32 shaderTessellationAndGeometryPointSize; - VkBool32 shaderImageGatherExtended; - VkBool32 shaderStorageImageExtendedFormats; - VkBool32 shaderStorageImageMultisample; - VkBool32 shaderStorageImageReadWithoutFormat; - VkBool32 shaderStorageImageWriteWithoutFormat; - VkBool32 shaderUniformBufferArrayDynamicIndexing; - VkBool32 shaderSampledImageArrayDynamicIndexing; - VkBool32 shaderStorageBufferArrayDynamicIndexing; - VkBool32 shaderStorageImageArrayDynamicIndexing; - VkBool32 shaderClipDistance; - VkBool32 shaderCullDistance; - VkBool32 shaderFloat64; - VkBool32 shaderInt64; - VkBool32 shaderInt16; - VkBool32 shaderResourceResidency; - VkBool32 shaderResourceMinLod; - VkBool32 sparseBinding; - VkBool32 sparseResidencyBuffer; - VkBool32 sparseResidencyImage2D; - VkBool32 sparseResidencyImage3D; - VkBool32 sparseResidency2Samples; - VkBool32 sparseResidency4Samples; - VkBool32 sparseResidency8Samples; - VkBool32 sparseResidency16Samples; - VkBool32 sparseResidencyAliased; - VkBool32 variableMultisampleRate; - VkBool32 inheritedQueries; -} VkPhysicalDeviceFeatures; - -typedef struct VkFormatProperties { - VkFormatFeatureFlags linearTilingFeatures; - VkFormatFeatureFlags optimalTilingFeatures; - VkFormatFeatureFlags bufferFeatures; -} VkFormatProperties; - -typedef struct VkExtent3D { - uint32_t width; - uint32_t height; - uint32_t depth; -} VkExtent3D; - -typedef struct VkImageFormatProperties { - VkExtent3D maxExtent; - uint32_t maxMipLevels; - uint32_t maxArrayLayers; - VkSampleCountFlags sampleCounts; - VkDeviceSize maxResourceSize; -} VkImageFormatProperties; - -typedef struct VkPhysicalDeviceLimits { - uint32_t maxImageDimension1D; - uint32_t maxImageDimension2D; - uint32_t maxImageDimension3D; - uint32_t maxImageDimensionCube; - uint32_t maxImageArrayLayers; - uint32_t maxTexelBufferElements; - uint32_t maxUniformBufferRange; - uint32_t maxStorageBufferRange; - uint32_t maxPushConstantsSize; - uint32_t maxMemoryAllocationCount; - uint32_t maxSamplerAllocationCount; - VkDeviceSize bufferImageGranularity; - VkDeviceSize sparseAddressSpaceSize; - uint32_t maxBoundDescriptorSets; - uint32_t maxPerStageDescriptorSamplers; - uint32_t maxPerStageDescriptorUniformBuffers; - uint32_t maxPerStageDescriptorStorageBuffers; - uint32_t maxPerStageDescriptorSampledImages; - uint32_t maxPerStageDescriptorStorageImages; - uint32_t maxPerStageDescriptorInputAttachments; - uint32_t maxPerStageResources; - uint32_t maxDescriptorSetSamplers; - uint32_t maxDescriptorSetUniformBuffers; - uint32_t maxDescriptorSetUniformBuffersDynamic; - uint32_t maxDescriptorSetStorageBuffers; - uint32_t maxDescriptorSetStorageBuffersDynamic; - uint32_t maxDescriptorSetSampledImages; - uint32_t maxDescriptorSetStorageImages; - uint32_t maxDescriptorSetInputAttachments; - uint32_t maxVertexInputAttributes; - uint32_t maxVertexInputBindings; - uint32_t maxVertexInputAttributeOffset; - uint32_t maxVertexInputBindingStride; - uint32_t maxVertexOutputComponents; - uint32_t maxTessellationGenerationLevel; - uint32_t maxTessellationPatchSize; - uint32_t maxTessellationControlPerVertexInputComponents; - uint32_t maxTessellationControlPerVertexOutputComponents; - uint32_t maxTessellationControlPerPatchOutputComponents; - uint32_t maxTessellationControlTotalOutputComponents; - uint32_t maxTessellationEvaluationInputComponents; - uint32_t maxTessellationEvaluationOutputComponents; - uint32_t maxGeometryShaderInvocations; - uint32_t maxGeometryInputComponents; - uint32_t maxGeometryOutputComponents; - uint32_t maxGeometryOutputVertices; - uint32_t maxGeometryTotalOutputComponents; - uint32_t maxFragmentInputComponents; - uint32_t maxFragmentOutputAttachments; - uint32_t maxFragmentDualSrcAttachments; - uint32_t maxFragmentCombinedOutputResources; - uint32_t maxComputeSharedMemorySize; - uint32_t maxComputeWorkGroupCount[3]; - uint32_t maxComputeWorkGroupInvocations; - uint32_t maxComputeWorkGroupSize[3]; - uint32_t subPixelPrecisionBits; - uint32_t subTexelPrecisionBits; - uint32_t mipmapPrecisionBits; - uint32_t maxDrawIndexedIndexValue; - uint32_t maxDrawIndirectCount; - float maxSamplerLodBias; - float maxSamplerAnisotropy; - uint32_t maxViewports; - uint32_t maxViewportDimensions[2]; - float viewportBoundsRange[2]; - uint32_t viewportSubPixelBits; - size_t minMemoryMapAlignment; - VkDeviceSize minTexelBufferOffsetAlignment; - VkDeviceSize minUniformBufferOffsetAlignment; - VkDeviceSize minStorageBufferOffsetAlignment; - int32_t minTexelOffset; - uint32_t maxTexelOffset; - int32_t minTexelGatherOffset; - uint32_t maxTexelGatherOffset; - float minInterpolationOffset; - float maxInterpolationOffset; - uint32_t subPixelInterpolationOffsetBits; - uint32_t maxFramebufferWidth; - uint32_t maxFramebufferHeight; - uint32_t maxFramebufferLayers; - VkSampleCountFlags framebufferColorSampleCounts; - VkSampleCountFlags framebufferDepthSampleCounts; - VkSampleCountFlags framebufferStencilSampleCounts; - VkSampleCountFlags framebufferNoAttachmentsSampleCounts; - uint32_t maxColorAttachments; - VkSampleCountFlags sampledImageColorSampleCounts; - VkSampleCountFlags sampledImageIntegerSampleCounts; - VkSampleCountFlags sampledImageDepthSampleCounts; - VkSampleCountFlags sampledImageStencilSampleCounts; - VkSampleCountFlags storageImageSampleCounts; - uint32_t maxSampleMaskWords; - VkBool32 timestampComputeAndGraphics; - float timestampPeriod; - uint32_t maxClipDistances; - uint32_t maxCullDistances; - uint32_t maxCombinedClipAndCullDistances; - uint32_t discreteQueuePriorities; - float pointSizeRange[2]; - float lineWidthRange[2]; - float pointSizeGranularity; - float lineWidthGranularity; - VkBool32 strictLines; - VkBool32 standardSampleLocations; - VkDeviceSize optimalBufferCopyOffsetAlignment; - VkDeviceSize optimalBufferCopyRowPitchAlignment; - VkDeviceSize nonCoherentAtomSize; -} VkPhysicalDeviceLimits; - -typedef struct VkPhysicalDeviceSparseProperties { - VkBool32 residencyStandard2DBlockShape; - VkBool32 residencyStandard2DMultisampleBlockShape; - VkBool32 residencyStandard3DBlockShape; - VkBool32 residencyAlignedMipSize; - VkBool32 residencyNonResidentStrict; -} VkPhysicalDeviceSparseProperties; - -typedef struct VkPhysicalDeviceProperties { - uint32_t apiVersion; - uint32_t driverVersion; - uint32_t vendorID; - uint32_t deviceID; - VkPhysicalDeviceType deviceType; - char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; - uint8_t pipelineCacheUUID[VK_UUID_SIZE]; - VkPhysicalDeviceLimits limits; - VkPhysicalDeviceSparseProperties sparseProperties; -} VkPhysicalDeviceProperties; - -typedef struct VkQueueFamilyProperties { - VkQueueFlags queueFlags; - uint32_t queueCount; - uint32_t timestampValidBits; - VkExtent3D minImageTransferGranularity; -} VkQueueFamilyProperties; - -typedef struct VkMemoryType { - VkMemoryPropertyFlags propertyFlags; - uint32_t heapIndex; -} VkMemoryType; - -typedef struct VkMemoryHeap { - VkDeviceSize size; - VkMemoryHeapFlags flags; -} VkMemoryHeap; - -typedef struct VkPhysicalDeviceMemoryProperties { - uint32_t memoryTypeCount; - VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]; - uint32_t memoryHeapCount; - VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS]; -} VkPhysicalDeviceMemoryProperties; - -typedef struct VkDeviceQueueCreateInfo { - VkStructureType sType; - const void* pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueCount; - const float* pQueuePriorities; -} VkDeviceQueueCreateInfo; - -typedef struct VkDeviceCreateInfo { - VkStructureType sType; - const void* pNext; - VkDeviceCreateFlags flags; - uint32_t queueCreateInfoCount; - const VkDeviceQueueCreateInfo* pQueueCreateInfos; - uint32_t enabledLayerCount; - const char* const* ppEnabledLayerNames; - uint32_t enabledExtensionCount; - const char* const* ppEnabledExtensionNames; - const VkPhysicalDeviceFeatures* pEnabledFeatures; -} VkDeviceCreateInfo; - -typedef struct VkExtensionProperties { - char extensionName[VK_MAX_EXTENSION_NAME_SIZE]; - uint32_t specVersion; -} VkExtensionProperties; - -typedef struct VkLayerProperties { - char layerName[VK_MAX_EXTENSION_NAME_SIZE]; - uint32_t specVersion; - uint32_t implementationVersion; - char description[VK_MAX_DESCRIPTION_SIZE]; -} VkLayerProperties; - -typedef struct VkSubmitInfo { - VkStructureType sType; - const void* pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore* pWaitSemaphores; - const VkPipelineStageFlags* pWaitDstStageMask; - uint32_t commandBufferCount; - const VkCommandBuffer* pCommandBuffers; - uint32_t signalSemaphoreCount; - const VkSemaphore* pSignalSemaphores; -} VkSubmitInfo; - -typedef struct VkMemoryAllocateInfo { - VkStructureType sType; - const void* pNext; - VkDeviceSize allocationSize; - uint32_t memoryTypeIndex; -} VkMemoryAllocateInfo; - -typedef struct VkMappedMemoryRange { - VkStructureType sType; - const void* pNext; - VkDeviceMemory memory; - VkDeviceSize offset; - VkDeviceSize size; -} VkMappedMemoryRange; - -typedef struct VkMemoryRequirements { - VkDeviceSize size; - VkDeviceSize alignment; - uint32_t memoryTypeBits; -} VkMemoryRequirements; - -typedef struct VkSparseImageFormatProperties { - VkImageAspectFlags aspectMask; - VkExtent3D imageGranularity; - VkSparseImageFormatFlags flags; -} VkSparseImageFormatProperties; - -typedef struct VkSparseImageMemoryRequirements { - VkSparseImageFormatProperties formatProperties; - uint32_t imageMipTailFirstLod; - VkDeviceSize imageMipTailSize; - VkDeviceSize imageMipTailOffset; - VkDeviceSize imageMipTailStride; -} VkSparseImageMemoryRequirements; - -typedef struct VkSparseMemoryBind { - VkDeviceSize resourceOffset; - VkDeviceSize size; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseMemoryBind; - -typedef struct VkSparseBufferMemoryBindInfo { - VkBuffer buffer; - uint32_t bindCount; - const VkSparseMemoryBind* pBinds; -} VkSparseBufferMemoryBindInfo; - -typedef struct VkSparseImageOpaqueMemoryBindInfo { - VkImage image; - uint32_t bindCount; - const VkSparseMemoryBind* pBinds; -} VkSparseImageOpaqueMemoryBindInfo; - -typedef struct VkImageSubresource { - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t arrayLayer; -} VkImageSubresource; - -typedef struct VkOffset3D { - int32_t x; - int32_t y; - int32_t z; -} VkOffset3D; - -typedef struct VkSparseImageMemoryBind { - VkImageSubresource subresource; - VkOffset3D offset; - VkExtent3D extent; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseImageMemoryBind; - -typedef struct VkSparseImageMemoryBindInfo { - VkImage image; - uint32_t bindCount; - const VkSparseImageMemoryBind* pBinds; -} VkSparseImageMemoryBindInfo; - -typedef struct VkBindSparseInfo { - VkStructureType sType; - const void* pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore* pWaitSemaphores; - uint32_t bufferBindCount; - const VkSparseBufferMemoryBindInfo* pBufferBinds; - uint32_t imageOpaqueBindCount; - const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; - uint32_t imageBindCount; - const VkSparseImageMemoryBindInfo* pImageBinds; - uint32_t signalSemaphoreCount; - const VkSemaphore* pSignalSemaphores; -} VkBindSparseInfo; - -typedef struct VkFenceCreateInfo { - VkStructureType sType; - const void* pNext; - VkFenceCreateFlags flags; -} VkFenceCreateInfo; - -typedef struct VkSemaphoreCreateInfo { - VkStructureType sType; - const void* pNext; - VkSemaphoreCreateFlags flags; -} VkSemaphoreCreateInfo; - -typedef struct VkEventCreateInfo { - VkStructureType sType; - const void* pNext; - VkEventCreateFlags flags; -} VkEventCreateInfo; - -typedef struct VkQueryPoolCreateInfo { - VkStructureType sType; - const void* pNext; - VkQueryPoolCreateFlags flags; - VkQueryType queryType; - uint32_t queryCount; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkQueryPoolCreateInfo; - -typedef struct VkBufferCreateInfo { - VkStructureType sType; - const void* pNext; - VkBufferCreateFlags flags; - VkDeviceSize size; - VkBufferUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t* pQueueFamilyIndices; -} VkBufferCreateInfo; - -typedef struct VkBufferViewCreateInfo { - VkStructureType sType; - const void* pNext; - VkBufferViewCreateFlags flags; - VkBuffer buffer; - VkFormat format; - VkDeviceSize offset; - VkDeviceSize range; -} VkBufferViewCreateInfo; - -typedef struct VkImageCreateInfo { - VkStructureType sType; - const void* pNext; - VkImageCreateFlags flags; - VkImageType imageType; - VkFormat format; - VkExtent3D extent; - uint32_t mipLevels; - uint32_t arrayLayers; - VkSampleCountFlagBits samples; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t* pQueueFamilyIndices; - VkImageLayout initialLayout; -} VkImageCreateInfo; - -typedef struct VkSubresourceLayout { - VkDeviceSize offset; - VkDeviceSize size; - VkDeviceSize rowPitch; - VkDeviceSize arrayPitch; - VkDeviceSize depthPitch; -} VkSubresourceLayout; - -typedef struct VkComponentMapping { - VkComponentSwizzle r; - VkComponentSwizzle g; - VkComponentSwizzle b; - VkComponentSwizzle a; -} VkComponentMapping; - -typedef struct VkImageSubresourceRange { - VkImageAspectFlags aspectMask; - uint32_t baseMipLevel; - uint32_t levelCount; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceRange; - -typedef struct VkImageViewCreateInfo { - VkStructureType sType; - const void* pNext; - VkImageViewCreateFlags flags; - VkImage image; - VkImageViewType viewType; - VkFormat format; - VkComponentMapping components; - VkImageSubresourceRange subresourceRange; -} VkImageViewCreateInfo; - -typedef struct VkShaderModuleCreateInfo { - VkStructureType sType; - const void* pNext; - VkShaderModuleCreateFlags flags; - size_t codeSize; - const uint32_t* pCode; -} VkShaderModuleCreateInfo; - -typedef struct VkPipelineCacheCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineCacheCreateFlags flags; - size_t initialDataSize; - const void* pInitialData; -} VkPipelineCacheCreateInfo; - -typedef struct VkSpecializationMapEntry { - uint32_t constantID; - uint32_t offset; - size_t size; -} VkSpecializationMapEntry; - -typedef struct VkSpecializationInfo { - uint32_t mapEntryCount; - const VkSpecializationMapEntry* pMapEntries; - size_t dataSize; - const void* pData; -} VkSpecializationInfo; - -typedef struct VkPipelineShaderStageCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineShaderStageCreateFlags flags; - VkShaderStageFlagBits stage; - VkShaderModule module; - const char* pName; - const VkSpecializationInfo* pSpecializationInfo; -} VkPipelineShaderStageCreateInfo; - -typedef struct VkVertexInputBindingDescription { - uint32_t binding; - uint32_t stride; - VkVertexInputRate inputRate; -} VkVertexInputBindingDescription; - -typedef struct VkVertexInputAttributeDescription { - uint32_t location; - uint32_t binding; - VkFormat format; - uint32_t offset; -} VkVertexInputAttributeDescription; - -typedef struct VkPipelineVertexInputStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineVertexInputStateCreateFlags flags; - uint32_t vertexBindingDescriptionCount; - const VkVertexInputBindingDescription* pVertexBindingDescriptions; - uint32_t vertexAttributeDescriptionCount; - const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; -} VkPipelineVertexInputStateCreateInfo; - -typedef struct VkPipelineInputAssemblyStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineInputAssemblyStateCreateFlags flags; - VkPrimitiveTopology topology; - VkBool32 primitiveRestartEnable; -} VkPipelineInputAssemblyStateCreateInfo; - -typedef struct VkPipelineTessellationStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineTessellationStateCreateFlags flags; - uint32_t patchControlPoints; -} VkPipelineTessellationStateCreateInfo; - -typedef struct VkViewport { - float x; - float y; - float width; - float height; - float minDepth; - float maxDepth; -} VkViewport; - -typedef struct VkOffset2D { - int32_t x; - int32_t y; -} VkOffset2D; - -typedef struct VkExtent2D { - uint32_t width; - uint32_t height; -} VkExtent2D; - -typedef struct VkRect2D { - VkOffset2D offset; - VkExtent2D extent; -} VkRect2D; - -typedef struct VkPipelineViewportStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineViewportStateCreateFlags flags; - uint32_t viewportCount; - const VkViewport* pViewports; - uint32_t scissorCount; - const VkRect2D* pScissors; -} VkPipelineViewportStateCreateInfo; - -typedef struct VkPipelineRasterizationStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineRasterizationStateCreateFlags flags; - VkBool32 depthClampEnable; - VkBool32 rasterizerDiscardEnable; - VkPolygonMode polygonMode; - VkCullModeFlags cullMode; - VkFrontFace frontFace; - VkBool32 depthBiasEnable; - float depthBiasConstantFactor; - float depthBiasClamp; - float depthBiasSlopeFactor; - float lineWidth; -} VkPipelineRasterizationStateCreateInfo; - -typedef struct VkPipelineMultisampleStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineMultisampleStateCreateFlags flags; - VkSampleCountFlagBits rasterizationSamples; - VkBool32 sampleShadingEnable; - float minSampleShading; - const VkSampleMask* pSampleMask; - VkBool32 alphaToCoverageEnable; - VkBool32 alphaToOneEnable; -} VkPipelineMultisampleStateCreateInfo; - -typedef struct VkStencilOpState { - VkStencilOp failOp; - VkStencilOp passOp; - VkStencilOp depthFailOp; - VkCompareOp compareOp; - uint32_t compareMask; - uint32_t writeMask; - uint32_t reference; -} VkStencilOpState; - -typedef struct VkPipelineDepthStencilStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineDepthStencilStateCreateFlags flags; - VkBool32 depthTestEnable; - VkBool32 depthWriteEnable; - VkCompareOp depthCompareOp; - VkBool32 depthBoundsTestEnable; - VkBool32 stencilTestEnable; - VkStencilOpState front; - VkStencilOpState back; - float minDepthBounds; - float maxDepthBounds; -} VkPipelineDepthStencilStateCreateInfo; - -typedef struct VkPipelineColorBlendAttachmentState { - VkBool32 blendEnable; - VkBlendFactor srcColorBlendFactor; - VkBlendFactor dstColorBlendFactor; - VkBlendOp colorBlendOp; - VkBlendFactor srcAlphaBlendFactor; - VkBlendFactor dstAlphaBlendFactor; - VkBlendOp alphaBlendOp; - VkColorComponentFlags colorWriteMask; -} VkPipelineColorBlendAttachmentState; - -typedef struct VkPipelineColorBlendStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineColorBlendStateCreateFlags flags; - VkBool32 logicOpEnable; - VkLogicOp logicOp; - uint32_t attachmentCount; - const VkPipelineColorBlendAttachmentState* pAttachments; - float blendConstants[4]; -} VkPipelineColorBlendStateCreateInfo; - -typedef struct VkPipelineDynamicStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineDynamicStateCreateFlags flags; - uint32_t dynamicStateCount; - const VkDynamicState* pDynamicStates; -} VkPipelineDynamicStateCreateInfo; - -typedef struct VkGraphicsPipelineCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo* pStages; - const VkPipelineVertexInputStateCreateInfo* pVertexInputState; - const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; - const VkPipelineTessellationStateCreateInfo* pTessellationState; - const VkPipelineViewportStateCreateInfo* pViewportState; - const VkPipelineRasterizationStateCreateInfo* pRasterizationState; - const VkPipelineMultisampleStateCreateInfo* pMultisampleState; - const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; - const VkPipelineColorBlendStateCreateInfo* pColorBlendState; - const VkPipelineDynamicStateCreateInfo* pDynamicState; - VkPipelineLayout layout; - VkRenderPass renderPass; - uint32_t subpass; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkGraphicsPipelineCreateInfo; - -typedef struct VkComputePipelineCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineCreateFlags flags; - VkPipelineShaderStageCreateInfo stage; - VkPipelineLayout layout; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkComputePipelineCreateInfo; - -typedef struct VkPushConstantRange { - VkShaderStageFlags stageFlags; - uint32_t offset; - uint32_t size; -} VkPushConstantRange; - -typedef struct VkPipelineLayoutCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineLayoutCreateFlags flags; - uint32_t setLayoutCount; - const VkDescriptorSetLayout* pSetLayouts; - uint32_t pushConstantRangeCount; - const VkPushConstantRange* pPushConstantRanges; -} VkPipelineLayoutCreateInfo; - -typedef struct VkSamplerCreateInfo { - VkStructureType sType; - const void* pNext; - VkSamplerCreateFlags flags; - VkFilter magFilter; - VkFilter minFilter; - VkSamplerMipmapMode mipmapMode; - VkSamplerAddressMode addressModeU; - VkSamplerAddressMode addressModeV; - VkSamplerAddressMode addressModeW; - float mipLodBias; - VkBool32 anisotropyEnable; - float maxAnisotropy; - VkBool32 compareEnable; - VkCompareOp compareOp; - float minLod; - float maxLod; - VkBorderColor borderColor; - VkBool32 unnormalizedCoordinates; -} VkSamplerCreateInfo; - -typedef struct VkDescriptorSetLayoutBinding { - uint32_t binding; - VkDescriptorType descriptorType; - uint32_t descriptorCount; - VkShaderStageFlags stageFlags; - const VkSampler* pImmutableSamplers; -} VkDescriptorSetLayoutBinding; - -typedef struct VkDescriptorSetLayoutCreateInfo { - VkStructureType sType; - const void* pNext; - VkDescriptorSetLayoutCreateFlags flags; - uint32_t bindingCount; - const VkDescriptorSetLayoutBinding* pBindings; -} VkDescriptorSetLayoutCreateInfo; - -typedef struct VkDescriptorPoolSize { - VkDescriptorType type; - uint32_t descriptorCount; -} VkDescriptorPoolSize; - -typedef struct VkDescriptorPoolCreateInfo { - VkStructureType sType; - const void* pNext; - VkDescriptorPoolCreateFlags flags; - uint32_t maxSets; - uint32_t poolSizeCount; - const VkDescriptorPoolSize* pPoolSizes; -} VkDescriptorPoolCreateInfo; - -typedef struct VkDescriptorSetAllocateInfo { - VkStructureType sType; - const void* pNext; - VkDescriptorPool descriptorPool; - uint32_t descriptorSetCount; - const VkDescriptorSetLayout* pSetLayouts; -} VkDescriptorSetAllocateInfo; - -typedef struct VkDescriptorImageInfo { - VkSampler sampler; - VkImageView imageView; - VkImageLayout imageLayout; -} VkDescriptorImageInfo; - -typedef struct VkDescriptorBufferInfo { - VkBuffer buffer; - VkDeviceSize offset; - VkDeviceSize range; -} VkDescriptorBufferInfo; - -typedef struct VkWriteDescriptorSet { - VkStructureType sType; - const void* pNext; - VkDescriptorSet dstSet; - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; - VkDescriptorType descriptorType; - const VkDescriptorImageInfo* pImageInfo; - const VkDescriptorBufferInfo* pBufferInfo; - const VkBufferView* pTexelBufferView; -} VkWriteDescriptorSet; - -typedef struct VkCopyDescriptorSet { - VkStructureType sType; - const void* pNext; - VkDescriptorSet srcSet; - uint32_t srcBinding; - uint32_t srcArrayElement; - VkDescriptorSet dstSet; - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; -} VkCopyDescriptorSet; - -typedef struct VkFramebufferCreateInfo { - VkStructureType sType; - const void* pNext; - VkFramebufferCreateFlags flags; - VkRenderPass renderPass; - uint32_t attachmentCount; - const VkImageView* pAttachments; - uint32_t width; - uint32_t height; - uint32_t layers; -} VkFramebufferCreateInfo; - -typedef struct VkAttachmentDescription { - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkAttachmentLoadOp stencilLoadOp; - VkAttachmentStoreOp stencilStoreOp; - VkImageLayout initialLayout; - VkImageLayout finalLayout; -} VkAttachmentDescription; - -typedef struct VkAttachmentReference { - uint32_t attachment; - VkImageLayout layout; -} VkAttachmentReference; - -typedef struct VkSubpassDescription { - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t inputAttachmentCount; - const VkAttachmentReference* pInputAttachments; - uint32_t colorAttachmentCount; - const VkAttachmentReference* pColorAttachments; - const VkAttachmentReference* pResolveAttachments; - const VkAttachmentReference* pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - const uint32_t* pPreserveAttachments; -} VkSubpassDescription; - -typedef struct VkSubpassDependency { - uint32_t srcSubpass; - uint32_t dstSubpass; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkDependencyFlags dependencyFlags; -} VkSubpassDependency; - -typedef struct VkRenderPassCreateInfo { - VkStructureType sType; - const void* pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - const VkAttachmentDescription* pAttachments; - uint32_t subpassCount; - const VkSubpassDescription* pSubpasses; - uint32_t dependencyCount; - const VkSubpassDependency* pDependencies; -} VkRenderPassCreateInfo; - -typedef struct VkCommandPoolCreateInfo { - VkStructureType sType; - const void* pNext; - VkCommandPoolCreateFlags flags; - uint32_t queueFamilyIndex; -} VkCommandPoolCreateInfo; - -typedef struct VkCommandBufferAllocateInfo { - VkStructureType sType; - const void* pNext; - VkCommandPool commandPool; - VkCommandBufferLevel level; - uint32_t commandBufferCount; -} VkCommandBufferAllocateInfo; - -typedef struct VkCommandBufferInheritanceInfo { - VkStructureType sType; - const void* pNext; - VkRenderPass renderPass; - uint32_t subpass; - VkFramebuffer framebuffer; - VkBool32 occlusionQueryEnable; - VkQueryControlFlags queryFlags; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkCommandBufferInheritanceInfo; - -typedef struct VkCommandBufferBeginInfo { - VkStructureType sType; - const void* pNext; - VkCommandBufferUsageFlags flags; - const VkCommandBufferInheritanceInfo* pInheritanceInfo; -} VkCommandBufferBeginInfo; - -typedef struct VkBufferCopy { - VkDeviceSize srcOffset; - VkDeviceSize dstOffset; - VkDeviceSize size; -} VkBufferCopy; - -typedef struct VkImageSubresourceLayers { - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceLayers; - -typedef struct VkImageCopy { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageCopy; - -typedef struct VkImageBlit { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffsets[2]; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffsets[2]; -} VkImageBlit; - -typedef struct VkBufferImageCopy { - VkDeviceSize bufferOffset; - uint32_t bufferRowLength; - uint32_t bufferImageHeight; - VkImageSubresourceLayers imageSubresource; - VkOffset3D imageOffset; - VkExtent3D imageExtent; -} VkBufferImageCopy; - -typedef union VkClearColorValue { - float float32[4]; - int32_t int32[4]; - uint32_t uint32[4]; -} VkClearColorValue; - -typedef struct VkClearDepthStencilValue { - float depth; - uint32_t stencil; -} VkClearDepthStencilValue; - -typedef union VkClearValue { - VkClearColorValue color; - VkClearDepthStencilValue depthStencil; -} VkClearValue; - -typedef struct VkClearAttachment { - VkImageAspectFlags aspectMask; - uint32_t colorAttachment; - VkClearValue clearValue; -} VkClearAttachment; - -typedef struct VkClearRect { - VkRect2D rect; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkClearRect; - -typedef struct VkImageResolve { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageResolve; - -typedef struct VkMemoryBarrier { - VkStructureType sType; - const void* pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; -} VkMemoryBarrier; - -typedef struct VkBufferMemoryBarrier { - VkStructureType sType; - const void* pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkBuffer buffer; - VkDeviceSize offset; - VkDeviceSize size; -} VkBufferMemoryBarrier; - -typedef struct VkImageMemoryBarrier { - VkStructureType sType; - const void* pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkImageLayout oldLayout; - VkImageLayout newLayout; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkImage image; - VkImageSubresourceRange subresourceRange; -} VkImageMemoryBarrier; - -typedef struct VkRenderPassBeginInfo { - VkStructureType sType; - const void* pNext; - VkRenderPass renderPass; - VkFramebuffer framebuffer; - VkRect2D renderArea; - uint32_t clearValueCount; - const VkClearValue* pClearValues; -} VkRenderPassBeginInfo; - -typedef struct VkDispatchIndirectCommand { - uint32_t x; - uint32_t y; - uint32_t z; -} VkDispatchIndirectCommand; - -typedef struct VkDrawIndexedIndirectCommand { - uint32_t indexCount; - uint32_t instanceCount; - uint32_t firstIndex; - int32_t vertexOffset; - uint32_t firstInstance; -} VkDrawIndexedIndirectCommand; - -typedef struct VkDrawIndirectCommand { - uint32_t vertexCount; - uint32_t instanceCount; - uint32_t firstVertex; - uint32_t firstInstance; -} VkDrawIndirectCommand; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); -typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); -typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); -typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); -typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); -typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); -typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); -typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); -typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); -typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); -typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); -typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); -typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); -typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); -typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); -typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); -typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); -typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences); -typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); -typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); -typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); -typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); -typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); -typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event); -typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); -typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); -typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); -typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); -typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); -typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); -typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); -typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); -typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); -typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); -typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); -typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); -typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); -typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); -typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); -typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); -typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); -typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); -typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); -typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); -typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); -typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); -typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); -typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); -typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); -typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer); -typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); -typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); -typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); -typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); -typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); -typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); -typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); -typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); -typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); -typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); -typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z); -typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData); -typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); -typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); -typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); -typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); -typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); -typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); -typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); -typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); -typedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); -typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); -typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); -typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); -typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); -typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); -typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); -typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); -typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( - const VkInstanceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkInstance* pInstance); - -VKAPI_ATTR void VKAPI_CALL vkDestroyInstance( - VkInstance instance, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices( - VkInstance instance, - uint32_t* pPhysicalDeviceCount, - VkPhysicalDevice* pPhysicalDevices); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures* pFeatures); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties* pFormatProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags, - VkImageFormatProperties* pImageFormatProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties( - VkPhysicalDevice physicalDevice, - uint32_t* pQueueFamilyPropertyCount, - VkQueueFamilyProperties* pQueueFamilyProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties* pMemoryProperties); - -VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr( - VkInstance instance, - const char* pName); - -VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr( - VkDevice device, - const char* pName); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice( - VkPhysicalDevice physicalDevice, - const VkDeviceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDevice* pDevice); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDevice( - VkDevice device, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties( - const char* pLayerName, - uint32_t* pPropertyCount, - VkExtensionProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties( - VkPhysicalDevice physicalDevice, - const char* pLayerName, - uint32_t* pPropertyCount, - VkExtensionProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( - uint32_t* pPropertyCount, - VkLayerProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkLayerProperties* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue( - VkDevice device, - uint32_t queueFamilyIndex, - uint32_t queueIndex, - VkQueue* pQueue); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit( - VkQueue queue, - uint32_t submitCount, - const VkSubmitInfo* pSubmits, - VkFence fence); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle( - VkQueue queue); - -VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle( - VkDevice device); - -VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory( - VkDevice device, - const VkMemoryAllocateInfo* pAllocateInfo, - const VkAllocationCallbacks* pAllocator, - VkDeviceMemory* pMemory); - -VKAPI_ATTR void VKAPI_CALL vkFreeMemory( - VkDevice device, - VkDeviceMemory memory, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory( - VkDevice device, - VkDeviceMemory memory, - VkDeviceSize offset, - VkDeviceSize size, - VkMemoryMapFlags flags, - void** ppData); - -VKAPI_ATTR void VKAPI_CALL vkUnmapMemory( - VkDevice device, - VkDeviceMemory memory); - -VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges( - VkDevice device, - uint32_t memoryRangeCount, - const VkMappedMemoryRange* pMemoryRanges); - -VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges( - VkDevice device, - uint32_t memoryRangeCount, - const VkMappedMemoryRange* pMemoryRanges); - -VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment( - VkDevice device, - VkDeviceMemory memory, - VkDeviceSize* pCommittedMemoryInBytes); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory( - VkDevice device, - VkBuffer buffer, - VkDeviceMemory memory, - VkDeviceSize memoryOffset); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory( - VkDevice device, - VkImage image, - VkDeviceMemory memory, - VkDeviceSize memoryOffset); - -VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements( - VkDevice device, - VkBuffer buffer, - VkMemoryRequirements* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements( - VkDevice device, - VkImage image, - VkMemoryRequirements* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements( - VkDevice device, - VkImage image, - uint32_t* pSparseMemoryRequirementCount, - VkSparseImageMemoryRequirements* pSparseMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkSampleCountFlagBits samples, - VkImageUsageFlags usage, - VkImageTiling tiling, - uint32_t* pPropertyCount, - VkSparseImageFormatProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse( - VkQueue queue, - uint32_t bindInfoCount, - const VkBindSparseInfo* pBindInfo, - VkFence fence); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence( - VkDevice device, - const VkFenceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence); - -VKAPI_ATTR void VKAPI_CALL vkDestroyFence( - VkDevice device, - VkFence fence, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetFences( - VkDevice device, - uint32_t fenceCount, - const VkFence* pFences); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus( - VkDevice device, - VkFence fence); - -VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences( - VkDevice device, - uint32_t fenceCount, - const VkFence* pFences, - VkBool32 waitAll, - uint64_t timeout); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore( - VkDevice device, - const VkSemaphoreCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSemaphore* pSemaphore); - -VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore( - VkDevice device, - VkSemaphore semaphore, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent( - VkDevice device, - const VkEventCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkEvent* pEvent); - -VKAPI_ATTR void VKAPI_CALL vkDestroyEvent( - VkDevice device, - VkEvent event, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus( - VkDevice device, - VkEvent event); - -VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent( - VkDevice device, - VkEvent event); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent( - VkDevice device, - VkEvent event); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool( - VkDevice device, - const VkQueryPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkQueryPool* pQueryPool); - -VKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool( - VkDevice device, - VkQueryPool queryPool, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults( - VkDevice device, - VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount, - size_t dataSize, - void* pData, - VkDeviceSize stride, - VkQueryResultFlags flags); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer( - VkDevice device, - const VkBufferCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkBuffer* pBuffer); - -VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer( - VkDevice device, - VkBuffer buffer, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView( - VkDevice device, - const VkBufferViewCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkBufferView* pView); - -VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView( - VkDevice device, - VkBufferView bufferView, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage( - VkDevice device, - const VkImageCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkImage* pImage); - -VKAPI_ATTR void VKAPI_CALL vkDestroyImage( - VkDevice device, - VkImage image, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout( - VkDevice device, - VkImage image, - const VkImageSubresource* pSubresource, - VkSubresourceLayout* pLayout); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView( - VkDevice device, - const VkImageViewCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkImageView* pView); - -VKAPI_ATTR void VKAPI_CALL vkDestroyImageView( - VkDevice device, - VkImageView imageView, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule( - VkDevice device, - const VkShaderModuleCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkShaderModule* pShaderModule); - -VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule( - VkDevice device, - VkShaderModule shaderModule, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache( - VkDevice device, - const VkPipelineCacheCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkPipelineCache* pPipelineCache); - -VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache( - VkDevice device, - VkPipelineCache pipelineCache, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData( - VkDevice device, - VkPipelineCache pipelineCache, - size_t* pDataSize, - void* pData); - -VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches( - VkDevice device, - VkPipelineCache dstCache, - uint32_t srcCacheCount, - const VkPipelineCache* pSrcCaches); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines( - VkDevice device, - VkPipelineCache pipelineCache, - uint32_t createInfoCount, - const VkGraphicsPipelineCreateInfo* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline* pPipelines); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines( - VkDevice device, - VkPipelineCache pipelineCache, - uint32_t createInfoCount, - const VkComputePipelineCreateInfo* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline* pPipelines); - -VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline( - VkDevice device, - VkPipeline pipeline, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout( - VkDevice device, - const VkPipelineLayoutCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkPipelineLayout* pPipelineLayout); - -VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout( - VkDevice device, - VkPipelineLayout pipelineLayout, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler( - VkDevice device, - const VkSamplerCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSampler* pSampler); - -VKAPI_ATTR void VKAPI_CALL vkDestroySampler( - VkDevice device, - VkSampler sampler, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout( - VkDevice device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorSetLayout* pSetLayout); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout( - VkDevice device, - VkDescriptorSetLayout descriptorSetLayout, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool( - VkDevice device, - const VkDescriptorPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorPool* pDescriptorPool); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool( - VkDevice device, - VkDescriptorPool descriptorPool, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool( - VkDevice device, - VkDescriptorPool descriptorPool, - VkDescriptorPoolResetFlags flags); - -VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets( - VkDevice device, - const VkDescriptorSetAllocateInfo* pAllocateInfo, - VkDescriptorSet* pDescriptorSets); - -VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets( - VkDevice device, - VkDescriptorPool descriptorPool, - uint32_t descriptorSetCount, - const VkDescriptorSet* pDescriptorSets); - -VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets( - VkDevice device, - uint32_t descriptorWriteCount, - const VkWriteDescriptorSet* pDescriptorWrites, - uint32_t descriptorCopyCount, - const VkCopyDescriptorSet* pDescriptorCopies); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer( - VkDevice device, - const VkFramebufferCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkFramebuffer* pFramebuffer); - -VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer( - VkDevice device, - VkFramebuffer framebuffer, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass( - VkDevice device, - const VkRenderPassCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkRenderPass* pRenderPass); - -VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass( - VkDevice device, - VkRenderPass renderPass, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity( - VkDevice device, - VkRenderPass renderPass, - VkExtent2D* pGranularity); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool( - VkDevice device, - const VkCommandPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkCommandPool* pCommandPool); - -VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool( - VkDevice device, - VkCommandPool commandPool, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool( - VkDevice device, - VkCommandPool commandPool, - VkCommandPoolResetFlags flags); - -VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers( - VkDevice device, - const VkCommandBufferAllocateInfo* pAllocateInfo, - VkCommandBuffer* pCommandBuffers); - -VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers( - VkDevice device, - VkCommandPool commandPool, - uint32_t commandBufferCount, - const VkCommandBuffer* pCommandBuffers); - -VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer( - VkCommandBuffer commandBuffer, - const VkCommandBufferBeginInfo* pBeginInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer( - VkCommandBuffer commandBuffer); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer( - VkCommandBuffer commandBuffer, - VkCommandBufferResetFlags flags); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline( - VkCommandBuffer commandBuffer, - VkPipelineBindPoint pipelineBindPoint, - VkPipeline pipeline); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetViewport( - VkCommandBuffer commandBuffer, - uint32_t firstViewport, - uint32_t viewportCount, - const VkViewport* pViewports); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetScissor( - VkCommandBuffer commandBuffer, - uint32_t firstScissor, - uint32_t scissorCount, - const VkRect2D* pScissors); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth( - VkCommandBuffer commandBuffer, - float lineWidth); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias( - VkCommandBuffer commandBuffer, - float depthBiasConstantFactor, - float depthBiasClamp, - float depthBiasSlopeFactor); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants( - VkCommandBuffer commandBuffer, - const float blendConstants[4]); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds( - VkCommandBuffer commandBuffer, - float minDepthBounds, - float maxDepthBounds); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - uint32_t compareMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - uint32_t writeMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - uint32_t reference); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets( - VkCommandBuffer commandBuffer, - VkPipelineBindPoint pipelineBindPoint, - VkPipelineLayout layout, - uint32_t firstSet, - uint32_t descriptorSetCount, - const VkDescriptorSet* pDescriptorSets, - uint32_t dynamicOffsetCount, - const uint32_t* pDynamicOffsets); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkIndexType indexType); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers( - VkCommandBuffer commandBuffer, - uint32_t firstBinding, - uint32_t bindingCount, - const VkBuffer* pBuffers, - const VkDeviceSize* pOffsets); - -VKAPI_ATTR void VKAPI_CALL vkCmdDraw( - VkCommandBuffer commandBuffer, - uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed( - VkCommandBuffer commandBuffer, - uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride); - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatch( - VkCommandBuffer commandBuffer, - uint32_t x, - uint32_t y, - uint32_t z); - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer( - VkCommandBuffer commandBuffer, - VkBuffer srcBuffer, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageBlit* pRegions, - VkFilter filter); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage( - VkCommandBuffer commandBuffer, - VkBuffer srcBuffer, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkBufferImageCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferImageCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer( - VkCommandBuffer commandBuffer, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize dataSize, - const void* pData); - -VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer( - VkCommandBuffer commandBuffer, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize size, - uint32_t data); - -VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage( - VkCommandBuffer commandBuffer, - VkImage image, - VkImageLayout imageLayout, - const VkClearColorValue* pColor, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges); - -VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage( - VkCommandBuffer commandBuffer, - VkImage image, - VkImageLayout imageLayout, - const VkClearDepthStencilValue* pDepthStencil, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges); - -VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments( - VkCommandBuffer commandBuffer, - uint32_t attachmentCount, - const VkClearAttachment* pAttachments, - uint32_t rectCount, - const VkClearRect* pRects); - -VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageResolve* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent( - VkCommandBuffer commandBuffer, - VkEvent event, - VkPipelineStageFlags stageMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent( - VkCommandBuffer commandBuffer, - VkEvent event, - VkPipelineStageFlags stageMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents( - VkCommandBuffer commandBuffer, - uint32_t eventCount, - const VkEvent* pEvents, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - uint32_t memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers); - -VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier( - VkCommandBuffer commandBuffer, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - VkDependencyFlags dependencyFlags, - uint32_t memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers); - -VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t query, - VkQueryControlFlags flags); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t query); - -VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount); - -VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp( - VkCommandBuffer commandBuffer, - VkPipelineStageFlagBits pipelineStage, - VkQueryPool queryPool, - uint32_t query); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize stride, - VkQueryResultFlags flags); - -VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants( - VkCommandBuffer commandBuffer, - VkPipelineLayout layout, - VkShaderStageFlags stageFlags, - uint32_t offset, - uint32_t size, - const void* pValues); - -VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass( - VkCommandBuffer commandBuffer, - const VkRenderPassBeginInfo* pRenderPassBegin, - VkSubpassContents contents); - -VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass( - VkCommandBuffer commandBuffer, - VkSubpassContents contents); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass( - VkCommandBuffer commandBuffer); - -VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands( - VkCommandBuffer commandBuffer, - uint32_t commandBufferCount, - const VkCommandBuffer* pCommandBuffers); -#endif - -#define VK_KHR_surface 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) - -#define VK_KHR_SURFACE_SPEC_VERSION 25 -#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" -#define VK_COLORSPACE_SRGB_NONLINEAR_KHR VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - - -typedef enum VkColorSpaceKHR { - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, - VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104001, - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104002, - VK_COLOR_SPACE_SCRGB_LINEAR_EXT = 1000104003, - VK_COLOR_SPACE_SCRGB_NONLINEAR_EXT = 1000104004, - VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104005, - VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104006, - VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104007, - VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104008, - VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104009, - VK_COLOR_SPACE_BT2020_NONLINEAR_EXT = 1000104010, - VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, - VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, - VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1), - VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF -} VkColorSpaceKHR; - -typedef enum VkPresentModeKHR { - VK_PRESENT_MODE_IMMEDIATE_KHR = 0, - VK_PRESENT_MODE_MAILBOX_KHR = 1, - VK_PRESENT_MODE_FIFO_KHR = 2, - VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, - VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1), - VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF -} VkPresentModeKHR; - - -typedef enum VkSurfaceTransformFlagBitsKHR { - VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, - VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, - VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, - VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, - VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, - VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkSurfaceTransformFlagBitsKHR; -typedef VkFlags VkSurfaceTransformFlagsKHR; - -typedef enum VkCompositeAlphaFlagBitsKHR { - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, - VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, - VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, - VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkCompositeAlphaFlagBitsKHR; -typedef VkFlags VkCompositeAlphaFlagsKHR; - -typedef struct VkSurfaceCapabilitiesKHR { - uint32_t minImageCount; - uint32_t maxImageCount; - VkExtent2D currentExtent; - VkExtent2D minImageExtent; - VkExtent2D maxImageExtent; - uint32_t maxImageArrayLayers; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkSurfaceTransformFlagBitsKHR currentTransform; - VkCompositeAlphaFlagsKHR supportedCompositeAlpha; - VkImageUsageFlags supportedUsageFlags; -} VkSurfaceCapabilitiesKHR; - -typedef struct VkSurfaceFormatKHR { - VkFormat format; - VkColorSpaceKHR colorSpace; -} VkSurfaceFormatKHR; - - -typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR( - VkInstance instance, - VkSurfaceKHR surface, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR( - VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - VkSurfaceKHR surface, - VkBool32* pSupported); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - uint32_t* pSurfaceFormatCount, - VkSurfaceFormatKHR* pSurfaceFormats); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - uint32_t* pPresentModeCount, - VkPresentModeKHR* pPresentModes); -#endif - -#define VK_KHR_swapchain 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) - -#define VK_KHR_SWAPCHAIN_SPEC_VERSION 68 -#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" - -typedef VkFlags VkSwapchainCreateFlagsKHR; - -typedef struct VkSwapchainCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkSwapchainCreateFlagsKHR flags; - VkSurfaceKHR surface; - uint32_t minImageCount; - VkFormat imageFormat; - VkColorSpaceKHR imageColorSpace; - VkExtent2D imageExtent; - uint32_t imageArrayLayers; - VkImageUsageFlags imageUsage; - VkSharingMode imageSharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t* pQueueFamilyIndices; - VkSurfaceTransformFlagBitsKHR preTransform; - VkCompositeAlphaFlagBitsKHR compositeAlpha; - VkPresentModeKHR presentMode; - VkBool32 clipped; - VkSwapchainKHR oldSwapchain; -} VkSwapchainCreateInfoKHR; - -typedef struct VkPresentInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore* pWaitSemaphores; - uint32_t swapchainCount; - const VkSwapchainKHR* pSwapchains; - const uint32_t* pImageIndices; - VkResult* pResults; -} VkPresentInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); -typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); -typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); -typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( - VkDevice device, - const VkSwapchainCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSwapchainKHR* pSwapchain); - -VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR( - VkDevice device, - VkSwapchainKHR swapchain, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR( - VkDevice device, - VkSwapchainKHR swapchain, - uint32_t* pSwapchainImageCount, - VkImage* pSwapchainImages); - -VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( - VkDevice device, - VkSwapchainKHR swapchain, - uint64_t timeout, - VkSemaphore semaphore, - VkFence fence, - uint32_t* pImageIndex); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR( - VkQueue queue, - const VkPresentInfoKHR* pPresentInfo); -#endif - -#define VK_KHR_display 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) - -#define VK_KHR_DISPLAY_SPEC_VERSION 21 -#define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display" - - -typedef enum VkDisplayPlaneAlphaFlagBitsKHR { - VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, - VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, - VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, - VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, - VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkDisplayPlaneAlphaFlagBitsKHR; -typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; -typedef VkFlags VkDisplayModeCreateFlagsKHR; -typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; - -typedef struct VkDisplayPropertiesKHR { - VkDisplayKHR display; - const char* displayName; - VkExtent2D physicalDimensions; - VkExtent2D physicalResolution; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkBool32 planeReorderPossible; - VkBool32 persistentContent; -} VkDisplayPropertiesKHR; - -typedef struct VkDisplayModeParametersKHR { - VkExtent2D visibleRegion; - uint32_t refreshRate; -} VkDisplayModeParametersKHR; - -typedef struct VkDisplayModePropertiesKHR { - VkDisplayModeKHR displayMode; - VkDisplayModeParametersKHR parameters; -} VkDisplayModePropertiesKHR; - -typedef struct VkDisplayModeCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkDisplayModeCreateFlagsKHR flags; - VkDisplayModeParametersKHR parameters; -} VkDisplayModeCreateInfoKHR; - -typedef struct VkDisplayPlaneCapabilitiesKHR { - VkDisplayPlaneAlphaFlagsKHR supportedAlpha; - VkOffset2D minSrcPosition; - VkOffset2D maxSrcPosition; - VkExtent2D minSrcExtent; - VkExtent2D maxSrcExtent; - VkOffset2D minDstPosition; - VkOffset2D maxDstPosition; - VkExtent2D minDstExtent; - VkExtent2D maxDstExtent; -} VkDisplayPlaneCapabilitiesKHR; - -typedef struct VkDisplayPlanePropertiesKHR { - VkDisplayKHR currentDisplay; - uint32_t currentStackIndex; -} VkDisplayPlanePropertiesKHR; - -typedef struct VkDisplaySurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkDisplaySurfaceCreateFlagsKHR flags; - VkDisplayModeKHR displayMode; - uint32_t planeIndex; - uint32_t planeStackIndex; - VkSurfaceTransformFlagBitsKHR transform; - float globalAlpha; - VkDisplayPlaneAlphaFlagBitsKHR alphaMode; - VkExtent2D imageExtent; -} VkDisplaySurfaceCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays); -typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); -typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkDisplayPropertiesKHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkDisplayPlanePropertiesKHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR( - VkPhysicalDevice physicalDevice, - uint32_t planeIndex, - uint32_t* pDisplayCount, - VkDisplayKHR* pDisplays); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - uint32_t* pPropertyCount, - VkDisplayModePropertiesKHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - const VkDisplayModeCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDisplayModeKHR* pMode); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR( - VkPhysicalDevice physicalDevice, - VkDisplayModeKHR mode, - uint32_t planeIndex, - VkDisplayPlaneCapabilitiesKHR* pCapabilities); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR( - VkInstance instance, - const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif - -#define VK_KHR_display_swapchain 1 -#define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9 -#define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain" - -typedef struct VkDisplayPresentInfoKHR { - VkStructureType sType; - const void* pNext; - VkRect2D srcRect; - VkRect2D dstRect; - VkBool32 persistent; -} VkDisplayPresentInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR( - VkDevice device, - uint32_t swapchainCount, - const VkSwapchainCreateInfoKHR* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkSwapchainKHR* pSwapchains); -#endif - -#ifdef VK_USE_PLATFORM_XLIB_KHR -#define VK_KHR_xlib_surface 1 -#include - -#define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 -#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface" - -typedef VkFlags VkXlibSurfaceCreateFlagsKHR; - -typedef struct VkXlibSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkXlibSurfaceCreateFlagsKHR flags; - Display* dpy; - Window window; -} VkXlibSurfaceCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); -typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR( - VkInstance instance, - const VkXlibSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); - -VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR( - VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - Display* dpy, - VisualID visualID); -#endif -#endif /* VK_USE_PLATFORM_XLIB_KHR */ - -#ifdef VK_USE_PLATFORM_XCB_KHR -#define VK_KHR_xcb_surface 1 -#include - -#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 -#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" - -typedef VkFlags VkXcbSurfaceCreateFlagsKHR; - -typedef struct VkXcbSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkXcbSurfaceCreateFlagsKHR flags; - xcb_connection_t* connection; - xcb_window_t window; -} VkXcbSurfaceCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); -typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR( - VkInstance instance, - const VkXcbSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); - -VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR( - VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - xcb_connection_t* connection, - xcb_visualid_t visual_id); -#endif -#endif /* VK_USE_PLATFORM_XCB_KHR */ - -#ifdef VK_USE_PLATFORM_WAYLAND_KHR -#define VK_KHR_wayland_surface 1 -#include - -#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 5 -#define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface" - -typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; - -typedef struct VkWaylandSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkWaylandSurfaceCreateFlagsKHR flags; - struct wl_display* display; - struct wl_surface* surface; -} VkWaylandSurfaceCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); -typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR( - VkInstance instance, - const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); - -VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresentationSupportKHR( - VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - struct wl_display* display); -#endif -#endif /* VK_USE_PLATFORM_WAYLAND_KHR */ - -#ifdef VK_USE_PLATFORM_MIR_KHR -#define VK_KHR_mir_surface 1 -#include - -#define VK_KHR_MIR_SURFACE_SPEC_VERSION 4 -#define VK_KHR_MIR_SURFACE_EXTENSION_NAME "VK_KHR_mir_surface" - -typedef VkFlags VkMirSurfaceCreateFlagsKHR; - -typedef struct VkMirSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkMirSurfaceCreateFlagsKHR flags; - MirConnection* connection; - MirSurface* mirSurface; -} VkMirSurfaceCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateMirSurfaceKHR)(VkInstance instance, const VkMirSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); -typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, MirConnection* connection); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateMirSurfaceKHR( - VkInstance instance, - const VkMirSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); - -VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceMirPresentationSupportKHR( - VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - MirConnection* connection); -#endif -#endif /* VK_USE_PLATFORM_MIR_KHR */ - -#ifdef VK_USE_PLATFORM_ANDROID_KHR -#define VK_KHR_android_surface 1 -#include - -#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 -#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface" - -typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; - -typedef struct VkAndroidSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkAndroidSurfaceCreateFlagsKHR flags; - ANativeWindow* window; -} VkAndroidSurfaceCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR( - VkInstance instance, - const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif -#endif /* VK_USE_PLATFORM_ANDROID_KHR */ - -#ifdef VK_USE_PLATFORM_WIN32_KHR -#define VK_KHR_win32_surface 1 -#include - -#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 5 -#define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface" - -typedef VkFlags VkWin32SurfaceCreateFlagsKHR; - -typedef struct VkWin32SurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkWin32SurfaceCreateFlagsKHR flags; - HINSTANCE hinstance; - HWND hwnd; -} VkWin32SurfaceCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); -typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR( - VkInstance instance, - const VkWin32SurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); - -VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR( - VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex); -#endif -#endif /* VK_USE_PLATFORM_WIN32_KHR */ - -#define VK_KHR_sampler_mirror_clamp_to_edge 1 -#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1 -#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" - - -#define VK_KHR_get_physical_device_properties2 1 -#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1 -#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" - -typedef struct VkPhysicalDeviceFeatures2KHR { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceFeatures features; -} VkPhysicalDeviceFeatures2KHR; - -typedef struct VkPhysicalDeviceProperties2KHR { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceProperties properties; -} VkPhysicalDeviceProperties2KHR; - -typedef struct VkFormatProperties2KHR { - VkStructureType sType; - void* pNext; - VkFormatProperties formatProperties; -} VkFormatProperties2KHR; - -typedef struct VkImageFormatProperties2KHR { - VkStructureType sType; - void* pNext; - VkImageFormatProperties imageFormatProperties; -} VkImageFormatProperties2KHR; - -typedef struct VkPhysicalDeviceImageFormatInfo2KHR { - VkStructureType sType; - const void* pNext; - VkFormat format; - VkImageType type; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkImageCreateFlags flags; -} VkPhysicalDeviceImageFormatInfo2KHR; - -typedef struct VkQueueFamilyProperties2KHR { - VkStructureType sType; - void* pNext; - VkQueueFamilyProperties queueFamilyProperties; -} VkQueueFamilyProperties2KHR; - -typedef struct VkPhysicalDeviceMemoryProperties2KHR { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceMemoryProperties memoryProperties; -} VkPhysicalDeviceMemoryProperties2KHR; - -typedef struct VkSparseImageFormatProperties2KHR { - VkStructureType sType; - void* pNext; - VkSparseImageFormatProperties properties; -} VkSparseImageFormatProperties2KHR; - -typedef struct VkPhysicalDeviceSparseImageFormatInfo2KHR { - VkStructureType sType; - const void* pNext; - VkFormat format; - VkImageType type; - VkSampleCountFlagBits samples; - VkImageUsageFlags usage; - VkImageTiling tiling; -} VkPhysicalDeviceSparseImageFormatInfo2KHR; - - -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR* pFeatures); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2KHR* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2KHR* pFormatProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, VkImageFormatProperties2KHR* pImageFormatProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR* pQueueFamilyProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2KHR* pProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures2KHR* pFeatures); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties2KHR* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties2KHR* pFormatProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, - VkImageFormatProperties2KHR* pImageFormatProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR( - VkPhysicalDevice physicalDevice, - uint32_t* pQueueFamilyPropertyCount, - VkQueueFamilyProperties2KHR* pQueueFamilyProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, - uint32_t* pPropertyCount, - VkSparseImageFormatProperties2KHR* pProperties); -#endif - -#define VK_KHR_shader_draw_parameters 1 -#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1 -#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters" - - -#define VK_KHR_maintenance1 1 -#define VK_KHR_MAINTENANCE1_SPEC_VERSION 1 -#define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" - -typedef VkFlags VkCommandPoolTrimFlagsKHR; - -typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlagsKHR flags); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR( - VkDevice device, - VkCommandPool commandPool, - VkCommandPoolTrimFlagsKHR flags); -#endif - -#define VK_EXT_debug_report 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) - -#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 4 -#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" -#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT - - -typedef enum VkDebugReportObjectTypeEXT { - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, - VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, - VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, - VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, - VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, - VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, - VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, - VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, - VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, - VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, - VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, - VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, - VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, - VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, - VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, - VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, - VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, - VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28, - VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29, - VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, - VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31, - VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32, - VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1), - VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDebugReportObjectTypeEXT; - -typedef enum VkDebugReportErrorEXT { - VK_DEBUG_REPORT_ERROR_NONE_EXT = 0, - VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1, - VK_DEBUG_REPORT_ERROR_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_ERROR_NONE_EXT, - VK_DEBUG_REPORT_ERROR_END_RANGE_EXT = VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, - VK_DEBUG_REPORT_ERROR_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT - VK_DEBUG_REPORT_ERROR_NONE_EXT + 1), - VK_DEBUG_REPORT_ERROR_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDebugReportErrorEXT; - - -typedef enum VkDebugReportFlagBitsEXT { - VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, - VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, - VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, - VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, - VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, - VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDebugReportFlagBitsEXT; -typedef VkFlags VkDebugReportFlagsEXT; - -typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage, - void* pUserData); - - -typedef struct VkDebugReportCallbackCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkDebugReportFlagsEXT flags; - PFN_vkDebugReportCallbackEXT pfnCallback; - void* pUserData; -} VkDebugReportCallbackCreateInfoEXT; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); -typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT( - VkInstance instance, - const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDebugReportCallbackEXT* pCallback); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT( - VkInstance instance, - VkDebugReportCallbackEXT callback, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( - VkInstance instance, - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage); -#endif - -#define VK_NV_glsl_shader 1 -#define VK_NV_GLSL_SHADER_SPEC_VERSION 1 -#define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" - - -#define VK_IMG_filter_cubic 1 -#define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 -#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" - - -#define VK_AMD_rasterization_order 1 -#define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1 -#define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME "VK_AMD_rasterization_order" - - -typedef enum VkRasterizationOrderAMD { - VK_RASTERIZATION_ORDER_STRICT_AMD = 0, - VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, - VK_RASTERIZATION_ORDER_BEGIN_RANGE_AMD = VK_RASTERIZATION_ORDER_STRICT_AMD, - VK_RASTERIZATION_ORDER_END_RANGE_AMD = VK_RASTERIZATION_ORDER_RELAXED_AMD, - VK_RASTERIZATION_ORDER_RANGE_SIZE_AMD = (VK_RASTERIZATION_ORDER_RELAXED_AMD - VK_RASTERIZATION_ORDER_STRICT_AMD + 1), - VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF -} VkRasterizationOrderAMD; - -typedef struct VkPipelineRasterizationStateRasterizationOrderAMD { - VkStructureType sType; - const void* pNext; - VkRasterizationOrderAMD rasterizationOrder; -} VkPipelineRasterizationStateRasterizationOrderAMD; - - - -#define VK_AMD_shader_trinary_minmax 1 -#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1 -#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax" - - -#define VK_AMD_shader_explicit_vertex_parameter 1 -#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1 -#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter" - - -#define VK_EXT_debug_marker 1 -#define VK_EXT_DEBUG_MARKER_SPEC_VERSION 3 -#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker" - -typedef struct VkDebugMarkerObjectNameInfoEXT { - VkStructureType sType; - const void* pNext; - VkDebugReportObjectTypeEXT objectType; - uint64_t object; - const char* pObjectName; -} VkDebugMarkerObjectNameInfoEXT; - -typedef struct VkDebugMarkerObjectTagInfoEXT { - VkStructureType sType; - const void* pNext; - VkDebugReportObjectTypeEXT objectType; - uint64_t object; - uint64_t tagName; - size_t tagSize; - const void* pTag; -} VkDebugMarkerObjectTagInfoEXT; - -typedef struct VkDebugMarkerMarkerInfoEXT { - VkStructureType sType; - const void* pNext; - const char* pMarkerName; - float color[4]; -} VkDebugMarkerMarkerInfoEXT; - - -typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, VkDebugMarkerObjectTagInfoEXT* pTagInfo); -typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, VkDebugMarkerObjectNameInfoEXT* pNameInfo); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT( - VkDevice device, - VkDebugMarkerObjectTagInfoEXT* pTagInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT( - VkDevice device, - VkDebugMarkerObjectNameInfoEXT* pNameInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT( - VkCommandBuffer commandBuffer, - VkDebugMarkerMarkerInfoEXT* pMarkerInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT( - VkCommandBuffer commandBuffer); - -VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT( - VkCommandBuffer commandBuffer, - VkDebugMarkerMarkerInfoEXT* pMarkerInfo); -#endif - -#define VK_AMD_gcn_shader 1 -#define VK_AMD_GCN_SHADER_SPEC_VERSION 1 -#define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader" - - -#define VK_NV_dedicated_allocation 1 -#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1 -#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation" - -typedef struct VkDedicatedAllocationImageCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationImageCreateInfoNV; - -typedef struct VkDedicatedAllocationBufferCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationBufferCreateInfoNV; - -typedef struct VkDedicatedAllocationMemoryAllocateInfoNV { - VkStructureType sType; - const void* pNext; - VkImage image; - VkBuffer buffer; -} VkDedicatedAllocationMemoryAllocateInfoNV; - - - -#define VK_AMD_draw_indirect_count 1 -#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 -#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" - -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - uint32_t maxDrawCount, - uint32_t stride); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - uint32_t maxDrawCount, - uint32_t stride); -#endif - -#define VK_AMD_negative_viewport_height 1 -#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1 -#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height" - - -#define VK_AMD_gpu_shader_half_float 1 -#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1 -#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float" - - -#define VK_AMD_shader_ballot 1 -#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1 -#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot" - - -#define VK_IMG_format_pvrtc 1 -#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 -#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" - - -#define VK_NV_external_memory_capabilities 1 -#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 -#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities" - - -typedef enum VkExternalMemoryHandleTypeFlagBitsNV { - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkExternalMemoryHandleTypeFlagBitsNV; -typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; - -typedef enum VkExternalMemoryFeatureFlagBitsNV { - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004, - VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkExternalMemoryFeatureFlagBitsNV; -typedef VkFlags VkExternalMemoryFeatureFlagsNV; - -typedef struct VkExternalImageFormatPropertiesNV { - VkImageFormatProperties imageFormatProperties; - VkExternalMemoryFeatureFlagsNV externalMemoryFeatures; - VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes; - VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes; -} VkExternalImageFormatPropertiesNV; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType, VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceExternalImageFormatPropertiesNV( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags, - VkExternalMemoryHandleTypeFlagsNV externalHandleType, - VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); -#endif - -#define VK_NV_external_memory 1 -#define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1 -#define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory" - -typedef struct VkExternalMemoryImageCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagsNV handleTypes; -} VkExternalMemoryImageCreateInfoNV; - -typedef struct VkExportMemoryAllocateInfoNV { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagsNV handleTypes; -} VkExportMemoryAllocateInfoNV; - - - -#ifdef VK_USE_PLATFORM_WIN32_KHR -#define VK_NV_external_memory_win32 1 -#define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 -#define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32" - -typedef struct VkImportMemoryWin32HandleInfoNV { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagsNV handleType; - HANDLE handle; -} VkImportMemoryWin32HandleInfoNV; - -typedef struct VkExportMemoryWin32HandleInfoNV { - VkStructureType sType; - const void* pNext; - const SECURITY_ATTRIBUTES* pAttributes; - DWORD dwAccess; -} VkExportMemoryWin32HandleInfoNV; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleNV)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE* pHandle); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleNV( - VkDevice device, - VkDeviceMemory memory, - VkExternalMemoryHandleTypeFlagsNV handleType, - HANDLE* pHandle); -#endif -#endif /* VK_USE_PLATFORM_WIN32_KHR */ - -#ifdef VK_USE_PLATFORM_WIN32_KHR -#define VK_NV_win32_keyed_mutex 1 -#define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 1 -#define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex" - -typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV { - VkStructureType sType; - const void* pNext; - uint32_t acquireCount; - const VkDeviceMemory* pAcquireSyncs; - const uint64_t* pAcquireKeys; - const uint32_t* pAcquireTimeoutMilliseconds; - uint32_t releaseCount; - const VkDeviceMemory* pReleaseSyncs; - const uint64_t* pReleaseKeys; -} VkWin32KeyedMutexAcquireReleaseInfoNV; - - -#endif /* VK_USE_PLATFORM_WIN32_KHR */ - -#define VK_EXT_validation_flags 1 -#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1 -#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" - - -typedef enum VkValidationCheckEXT { - VK_VALIDATION_CHECK_ALL_EXT = 0, - VK_VALIDATION_CHECK_BEGIN_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT, - VK_VALIDATION_CHECK_END_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT, - VK_VALIDATION_CHECK_RANGE_SIZE_EXT = (VK_VALIDATION_CHECK_ALL_EXT - VK_VALIDATION_CHECK_ALL_EXT + 1), - VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF -} VkValidationCheckEXT; - -typedef struct VkValidationFlagsEXT { - VkStructureType sType; - const void* pNext; - uint32_t disabledValidationCheckCount; - VkValidationCheckEXT* pDisabledValidationChecks; -} VkValidationFlagsEXT; - - - -#ifdef VK_USE_PLATFORM_VI_NN -#define VK_NN_vi_surface 1 -#define VK_NN_VI_SURFACE_SPEC_VERSION 1 -#define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface" - -typedef VkFlags VkViSurfaceCreateFlagsNN; - -typedef struct VkViSurfaceCreateInfoNN { - VkStructureType sType; - const void* pNext; - VkViSurfaceCreateFlagsNN flags; - void* window; -} VkViSurfaceCreateInfoNN; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN( - VkInstance instance, - const VkViSurfaceCreateInfoNN* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif -#endif /* VK_USE_PLATFORM_VI_NN */ - -#define VK_EXT_shader_subgroup_ballot 1 -#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1 -#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot" - - -#define VK_EXT_shader_subgroup_vote 1 -#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1 -#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" - - -#define VK_NVX_device_generated_commands 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX) - -#define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1 -#define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands" - - -typedef enum VkIndirectCommandsTokenTypeNVX { - VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX = 0, - VK_INDIRECT_COMMANDS_TOKEN_DESCRIPTOR_SET_NVX = 1, - VK_INDIRECT_COMMANDS_TOKEN_INDEX_BUFFER_NVX = 2, - VK_INDIRECT_COMMANDS_TOKEN_VERTEX_BUFFER_NVX = 3, - VK_INDIRECT_COMMANDS_TOKEN_PUSH_CONSTANT_NVX = 4, - VK_INDIRECT_COMMANDS_TOKEN_DRAW_INDEXED_NVX = 5, - VK_INDIRECT_COMMANDS_TOKEN_DRAW_NVX = 6, - VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX = 7, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_BEGIN_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_END_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_RANGE_SIZE_NVX = (VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX - VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX + 1), - VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF -} VkIndirectCommandsTokenTypeNVX; - -typedef enum VkObjectEntryTypeNVX { - VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX = 0, - VK_OBJECT_ENTRY_PIPELINE_NVX = 1, - VK_OBJECT_ENTRY_INDEX_BUFFER_NVX = 2, - VK_OBJECT_ENTRY_VERTEX_BUFFER_NVX = 3, - VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX = 4, - VK_OBJECT_ENTRY_TYPE_BEGIN_RANGE_NVX = VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX, - VK_OBJECT_ENTRY_TYPE_END_RANGE_NVX = VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX, - VK_OBJECT_ENTRY_TYPE_RANGE_SIZE_NVX = (VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX - VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX + 1), - VK_OBJECT_ENTRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF -} VkObjectEntryTypeNVX; - - -typedef enum VkIndirectCommandsLayoutUsageFlagBitsNVX { - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF -} VkIndirectCommandsLayoutUsageFlagBitsNVX; -typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNVX; - -typedef enum VkObjectEntryUsageFlagBitsNVX { - VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001, - VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002, - VK_OBJECT_ENTRY_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF -} VkObjectEntryUsageFlagBitsNVX; -typedef VkFlags VkObjectEntryUsageFlagsNVX; - -typedef struct VkDeviceGeneratedCommandsFeaturesNVX { - VkStructureType sType; - const void* pNext; - VkBool32 computeBindingPointSupport; -} VkDeviceGeneratedCommandsFeaturesNVX; - -typedef struct VkDeviceGeneratedCommandsLimitsNVX { - VkStructureType sType; - const void* pNext; - uint32_t maxIndirectCommandsLayoutTokenCount; - uint32_t maxObjectEntryCounts; - uint32_t minSequenceCountBufferOffsetAlignment; - uint32_t minSequenceIndexBufferOffsetAlignment; - uint32_t minCommandsTokenBufferOffsetAlignment; -} VkDeviceGeneratedCommandsLimitsNVX; - -typedef struct VkIndirectCommandsTokenNVX { - VkIndirectCommandsTokenTypeNVX tokenType; - VkBuffer buffer; - VkDeviceSize offset; -} VkIndirectCommandsTokenNVX; - -typedef struct VkIndirectCommandsLayoutTokenNVX { - VkIndirectCommandsTokenTypeNVX tokenType; - uint32_t bindingUnit; - uint32_t dynamicCount; - uint32_t divisor; -} VkIndirectCommandsLayoutTokenNVX; - -typedef struct VkIndirectCommandsLayoutCreateInfoNVX { - VkStructureType sType; - const void* pNext; - VkPipelineBindPoint pipelineBindPoint; - VkIndirectCommandsLayoutUsageFlagsNVX flags; - uint32_t tokenCount; - const VkIndirectCommandsLayoutTokenNVX* pTokens; -} VkIndirectCommandsLayoutCreateInfoNVX; - -typedef struct VkCmdProcessCommandsInfoNVX { - VkStructureType sType; - const void* pNext; - VkObjectTableNVX objectTable; - VkIndirectCommandsLayoutNVX indirectCommandsLayout; - uint32_t indirectCommandsTokenCount; - const VkIndirectCommandsTokenNVX* pIndirectCommandsTokens; - uint32_t maxSequencesCount; - VkCommandBuffer targetCommandBuffer; - VkBuffer sequencesCountBuffer; - VkDeviceSize sequencesCountOffset; - VkBuffer sequencesIndexBuffer; - VkDeviceSize sequencesIndexOffset; -} VkCmdProcessCommandsInfoNVX; - -typedef struct VkCmdReserveSpaceForCommandsInfoNVX { - VkStructureType sType; - const void* pNext; - VkObjectTableNVX objectTable; - VkIndirectCommandsLayoutNVX indirectCommandsLayout; - uint32_t maxSequencesCount; -} VkCmdReserveSpaceForCommandsInfoNVX; - -typedef struct VkObjectTableCreateInfoNVX { - VkStructureType sType; - const void* pNext; - uint32_t objectCount; - const VkObjectEntryTypeNVX* pObjectEntryTypes; - const uint32_t* pObjectEntryCounts; - const VkObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags; - uint32_t maxUniformBuffersPerDescriptor; - uint32_t maxStorageBuffersPerDescriptor; - uint32_t maxStorageImagesPerDescriptor; - uint32_t maxSampledImagesPerDescriptor; - uint32_t maxPipelineLayouts; -} VkObjectTableCreateInfoNVX; - -typedef struct VkObjectTableEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; -} VkObjectTableEntryNVX; - -typedef struct VkObjectTablePipelineEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipeline pipeline; -} VkObjectTablePipelineEntryNVX; - -typedef struct VkObjectTableDescriptorSetEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; -} VkObjectTableDescriptorSetEntryNVX; - -typedef struct VkObjectTableVertexBufferEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkBuffer buffer; -} VkObjectTableVertexBufferEntryNVX; - -typedef struct VkObjectTableIndexBufferEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkBuffer buffer; - VkIndexType indexType; -} VkObjectTableIndexBufferEntryNVX; - -typedef struct VkObjectTablePushConstantEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipelineLayout pipelineLayout; - VkShaderStageFlags stageFlags; -} VkObjectTablePushConstantEntryNVX; - - -typedef void (VKAPI_PTR *PFN_vkCmdProcessCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo); -typedef void (VKAPI_PTR *PFN_vkCmdReserveSpaceForCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo); -typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNVX)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout); -typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNVX)(VkDevice device, VkIndirectCommandsLayoutNVX indirectCommandsLayout, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateObjectTableNVX)(VkDevice device, const VkObjectTableCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkObjectTableNVX* pObjectTable); -typedef void (VKAPI_PTR *PFN_vkDestroyObjectTableNVX)(VkDevice device, VkObjectTableNVX objectTable, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkRegisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectTableEntryNVX* const* ppObjectTableEntries, const uint32_t* pObjectIndices); -typedef VkResult (VKAPI_PTR *PFN_vkUnregisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectEntryTypeNVX* pObjectEntryTypes, const uint32_t* pObjectIndices); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX)(VkPhysicalDevice physicalDevice, VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, VkDeviceGeneratedCommandsLimitsNVX* pLimits); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdProcessCommandsNVX( - VkCommandBuffer commandBuffer, - const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdReserveSpaceForCommandsNVX( - VkCommandBuffer commandBuffer, - const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNVX( - VkDevice device, - const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout); - -VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNVX( - VkDevice device, - VkIndirectCommandsLayoutNVX indirectCommandsLayout, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateObjectTableNVX( - VkDevice device, - const VkObjectTableCreateInfoNVX* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkObjectTableNVX* pObjectTable); - -VKAPI_ATTR void VKAPI_CALL vkDestroyObjectTableNVX( - VkDevice device, - VkObjectTableNVX objectTable, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkRegisterObjectsNVX( - VkDevice device, - VkObjectTableNVX objectTable, - uint32_t objectCount, - const VkObjectTableEntryNVX* const* ppObjectTableEntries, - const uint32_t* pObjectIndices); - -VKAPI_ATTR VkResult VKAPI_CALL vkUnregisterObjectsNVX( - VkDevice device, - VkObjectTableNVX objectTable, - uint32_t objectCount, - const VkObjectEntryTypeNVX* pObjectEntryTypes, - const uint32_t* pObjectIndices); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX( - VkPhysicalDevice physicalDevice, - VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, - VkDeviceGeneratedCommandsLimitsNVX* pLimits); -#endif - -#define VK_EXT_direct_mode_display 1 -#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1 -#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display" - -typedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display); -#endif - -#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT -#define VK_EXT_acquire_xlib_display 1 -#include - -#define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1 -#define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display" - -typedef VkResult (VKAPI_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, VkDisplayKHR display); -typedef VkResult (VKAPI_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, RROutput rrOutput, VkDisplayKHR* pDisplay); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT( - VkPhysicalDevice physicalDevice, - Display* dpy, - VkDisplayKHR display); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetRandROutputDisplayEXT( - VkPhysicalDevice physicalDevice, - Display* dpy, - RROutput rrOutput, - VkDisplayKHR* pDisplay); -#endif -#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */ - -#define VK_EXT_display_surface_counter 1 -#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1 -#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter" - - -typedef enum VkSurfaceCounterFlagBitsEXT { - VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001, - VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkSurfaceCounterFlagBitsEXT; -typedef VkFlags VkSurfaceCounterFlagsEXT; - -typedef struct VkSurfaceCapabilities2EXT { - VkStructureType sType; - void* pNext; - uint32_t minImageCount; - uint32_t maxImageCount; - VkExtent2D currentExtent; - VkExtent2D minImageExtent; - VkExtent2D maxImageExtent; - uint32_t maxImageArrayLayers; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkSurfaceTransformFlagBitsKHR currentTransform; - VkCompositeAlphaFlagsKHR supportedCompositeAlpha; - VkImageUsageFlags supportedUsageFlags; - VkSurfaceCounterFlagsEXT supportedSurfaceCounters; -} VkSurfaceCapabilities2EXT; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - VkSurfaceCapabilities2EXT* pSurfaceCapabilities); -#endif - -#define VK_EXT_display_control 1 -#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1 -#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control" - - -typedef enum VkDisplayPowerStateEXT { - VK_DISPLAY_POWER_STATE_OFF_EXT = 0, - VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1, - VK_DISPLAY_POWER_STATE_ON_EXT = 2, - VK_DISPLAY_POWER_STATE_BEGIN_RANGE_EXT = VK_DISPLAY_POWER_STATE_OFF_EXT, - VK_DISPLAY_POWER_STATE_END_RANGE_EXT = VK_DISPLAY_POWER_STATE_ON_EXT, - VK_DISPLAY_POWER_STATE_RANGE_SIZE_EXT = (VK_DISPLAY_POWER_STATE_ON_EXT - VK_DISPLAY_POWER_STATE_OFF_EXT + 1), - VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDisplayPowerStateEXT; - -typedef enum VkDeviceEventTypeEXT { - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0, - VK_DEVICE_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT, - VK_DEVICE_EVENT_TYPE_END_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT, - VK_DEVICE_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT + 1), - VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDeviceEventTypeEXT; - -typedef enum VkDisplayEventTypeEXT { - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0, - VK_DISPLAY_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT, - VK_DISPLAY_EVENT_TYPE_END_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT, - VK_DISPLAY_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT + 1), - VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDisplayEventTypeEXT; - -typedef struct VkDisplayPowerInfoEXT { - VkStructureType sType; - const void* pNext; - VkDisplayPowerStateEXT powerState; -} VkDisplayPowerInfoEXT; - -typedef struct VkDeviceEventInfoEXT { - VkStructureType sType; - const void* pNext; - VkDeviceEventTypeEXT deviceEvent; -} VkDeviceEventInfoEXT; - -typedef struct VkDisplayEventInfoEXT { - VkStructureType sType; - const void* pNext; - VkDisplayEventTypeEXT displayEvent; -} VkDisplayEventInfoEXT; - -typedef struct VkSwapchainCounterCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkSurfaceCounterFlagsEXT surfaceCounters; -} VkSwapchainCounterCreateInfoEXT; - - -typedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo); -typedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); -typedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); -typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT( - VkDevice device, - VkDisplayKHR display, - const VkDisplayPowerInfoEXT* pDisplayPowerInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT( - VkDevice device, - const VkDeviceEventInfoEXT* pDeviceEventInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence); - -VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT( - VkDevice device, - VkDisplayKHR display, - const VkDisplayEventInfoEXT* pDisplayEventInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT( - VkDevice device, - VkSwapchainKHR swapchain, - VkSurfaceCounterFlagBitsEXT counter, - uint64_t* pCounterValue); -#endif - -#define VK_EXT_swapchain_colorspace 1 -#define VK_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 1 -#define VK_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" - - -#ifdef __cplusplus -} -#endif - -#endif From 6d317c7afe92424b5a5ec406b5c0952ac322aaa4 Mon Sep 17 00:00:00 2001 From: Ray San Date: Fri, 17 Nov 2017 18:43:39 +0100 Subject: [PATCH 020/139] Remove glfw3 dependency Full sources already included and compiled with raylib (rglfw) --- src/external/include/GLFW/glfw3.h | 4235 ----------------------- src/external/include/GLFW/glfw3native.h | 456 --- src/external/include/GLFW_COPYING.txt | 22 - 3 files changed, 4713 deletions(-) delete mode 100644 src/external/include/GLFW/glfw3.h delete mode 100644 src/external/include/GLFW/glfw3native.h delete mode 100644 src/external/include/GLFW_COPYING.txt diff --git a/src/external/include/GLFW/glfw3.h b/src/external/include/GLFW/glfw3.h deleted file mode 100644 index 5a0c4508..00000000 --- a/src/external/include/GLFW/glfw3.h +++ /dev/null @@ -1,4235 +0,0 @@ -/************************************************************************* - * GLFW 3.2 - www.glfw.org - * A library for OpenGL, window and input - *------------------------------------------------------------------------ - * Copyright (c) 2002-2006 Marcus Geelnard - * Copyright (c) 2006-2016 Camilla Berglund - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would - * be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - * - *************************************************************************/ - -#ifndef _glfw3_h_ -#define _glfw3_h_ - -#ifdef __cplusplus -extern "C" { -#endif - - -/************************************************************************* - * Doxygen documentation - *************************************************************************/ - -/*! @file glfw3.h - * @brief The header of the GLFW 3 API. - * - * This is the header file of the GLFW 3 API. It defines all its types and - * declares all its functions. - * - * For more information about how to use this file, see @ref build_include. - */ -/*! @defgroup context Context reference - * - * This is the reference documentation for OpenGL and OpenGL ES context related - * functions. For more task-oriented information, see the @ref context_guide. - */ -/*! @defgroup vulkan Vulkan reference - * - * This is the reference documentation for Vulkan related functions and types. - * For more task-oriented information, see the @ref vulkan_guide. - */ -/*! @defgroup init Initialization, version and error reference - * - * This is the reference documentation for initialization and termination of - * the library, version management and error handling. For more task-oriented - * information, see the @ref intro_guide. - */ -/*! @defgroup input Input reference - * - * This is the reference documentation for input related functions and types. - * For more task-oriented information, see the @ref input_guide. - */ -/*! @defgroup monitor Monitor reference - * - * This is the reference documentation for monitor related functions and types. - * For more task-oriented information, see the @ref monitor_guide. - */ -/*! @defgroup window Window reference - * - * This is the reference documentation for window related functions and types, - * including creation, deletion and event polling. For more task-oriented - * information, see the @ref window_guide. - */ - - -/************************************************************************* - * Compiler- and platform-specific preprocessor work - *************************************************************************/ - -/* If we are we on Windows, we want a single define for it. - */ -#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)) - #define _WIN32 -#endif /* _WIN32 */ - -/* It is customary to use APIENTRY for OpenGL function pointer declarations on - * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. - */ -#ifndef APIENTRY - #ifdef _WIN32 - #define APIENTRY __stdcall - #else - #define APIENTRY - #endif -#endif /* APIENTRY */ - -/* Some Windows OpenGL headers need this. - */ -#if !defined(WINGDIAPI) && defined(_WIN32) - #define WINGDIAPI __declspec(dllimport) - #define GLFW_WINGDIAPI_DEFINED -#endif /* WINGDIAPI */ - -/* Some Windows GLU headers need this. - */ -#if !defined(CALLBACK) && defined(_WIN32) - #define CALLBACK __stdcall - #define GLFW_CALLBACK_DEFINED -#endif /* CALLBACK */ - -/* Most Windows GLU headers need wchar_t. - * The OS X OpenGL header blocks the definition of ptrdiff_t by glext.h. - * Include it unconditionally to avoid surprising side-effects. - */ -#include -#include - -/* Include the chosen client API headers. - */ -#if defined(__APPLE__) - #if defined(GLFW_INCLUDE_GLCOREARB) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif !defined(GLFW_INCLUDE_NONE) - #if !defined(GLFW_INCLUDE_GLEXT) - #define GL_GLEXT_LEGACY - #endif - #include - #endif - #if defined(GLFW_INCLUDE_GLU) - #include - #endif -#else - #if defined(GLFW_INCLUDE_GLCOREARB) - #include - #elif defined(GLFW_INCLUDE_ES1) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_ES2) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_ES3) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_ES31) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_VULKAN) - #include - #elif !defined(GLFW_INCLUDE_NONE) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #endif - #if defined(GLFW_INCLUDE_GLU) - #include - #endif -#endif - -#if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) - /* GLFW_DLL must be defined by applications that are linking against the DLL - * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW - * configuration header when compiling the DLL version of the library. - */ - #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined" -#endif - -/* GLFWAPI is used to declare public API functions for export - * from the DLL / shared library / dynamic library. - */ -#if defined(_WIN32) && defined(_GLFW_BUILD_DLL) - /* We are building GLFW as a Win32 DLL */ - #define GLFWAPI __declspec(dllexport) -#elif defined(_WIN32) && defined(GLFW_DLL) - /* We are calling GLFW as a Win32 DLL */ - #define GLFWAPI __declspec(dllimport) -#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) - /* We are building GLFW as a shared / dynamic library */ - #define GLFWAPI __attribute__((visibility("default"))) -#else - /* We are building or calling GLFW as a static library */ - #define GLFWAPI -#endif - - -/************************************************************************* - * GLFW API tokens - *************************************************************************/ - -/*! @name GLFW version macros - * @{ */ -/*! @brief The major version number of the GLFW library. - * - * This is incremented when the API is changed in non-compatible ways. - * @ingroup init - */ -#define GLFW_VERSION_MAJOR 3 -/*! @brief The minor version number of the GLFW library. - * - * This is incremented when features are added to the API but it remains - * backward-compatible. - * @ingroup init - */ -#define GLFW_VERSION_MINOR 2 -/*! @brief The revision number of the GLFW library. - * - * This is incremented when a bug fix release is made that does not contain any - * API changes. - * @ingroup init - */ -#define GLFW_VERSION_REVISION 0 -/*! @} */ - -/*! @name Boolean values - * @{ */ -/*! @brief One. - * - * One. Seriously. You don't _need_ to use this symbol in your code. It's - * just semantic sugar for the number 1. You can use `1` or `true` or `_True` - * or `GL_TRUE` or whatever you want. - */ -#define GLFW_TRUE 1 -/*! @brief Zero. - * - * Zero. Seriously. You don't _need_ to use this symbol in your code. It's - * just just semantic sugar for the number 0. You can use `0` or `false` or - * `_False` or `GL_FALSE` or whatever you want. - */ -#define GLFW_FALSE 0 -/*! @} */ - -/*! @name Key and button actions - * @{ */ -/*! @brief The key or mouse button was released. - * - * The key or mouse button was released. - * - * @ingroup input - */ -#define GLFW_RELEASE 0 -/*! @brief The key or mouse button was pressed. - * - * The key or mouse button was pressed. - * - * @ingroup input - */ -#define GLFW_PRESS 1 -/*! @brief The key was held down until it repeated. - * - * The key was held down until it repeated. - * - * @ingroup input - */ -#define GLFW_REPEAT 2 -/*! @} */ - -/*! @defgroup keys Keyboard keys - * - * See [key input](@ref input_key) for how these are used. - * - * These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60), - * but re-arranged to map to 7-bit ASCII for printable keys (function keys are - * put in the 256+ range). - * - * The naming of the key codes follow these rules: - * - The US keyboard layout is used - * - Names of printable alpha-numeric characters are used (e.g. "A", "R", - * "3", etc.) - * - For non-alphanumeric characters, Unicode:ish names are used (e.g. - * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not - * correspond to the Unicode standard (usually for brevity) - * - Keys that lack a clear US mapping are named "WORLD_x" - * - For non-printable keys, custom names are used (e.g. "F4", - * "BACKSPACE", etc.) - * - * @ingroup input - * @{ - */ - -/* The unknown key */ -#define GLFW_KEY_UNKNOWN -1 - -/* Printable keys */ -#define GLFW_KEY_SPACE 32 -#define GLFW_KEY_APOSTROPHE 39 /* ' */ -#define GLFW_KEY_COMMA 44 /* , */ -#define GLFW_KEY_MINUS 45 /* - */ -#define GLFW_KEY_PERIOD 46 /* . */ -#define GLFW_KEY_SLASH 47 /* / */ -#define GLFW_KEY_0 48 -#define GLFW_KEY_1 49 -#define GLFW_KEY_2 50 -#define GLFW_KEY_3 51 -#define GLFW_KEY_4 52 -#define GLFW_KEY_5 53 -#define GLFW_KEY_6 54 -#define GLFW_KEY_7 55 -#define GLFW_KEY_8 56 -#define GLFW_KEY_9 57 -#define GLFW_KEY_SEMICOLON 59 /* ; */ -#define GLFW_KEY_EQUAL 61 /* = */ -#define GLFW_KEY_A 65 -#define GLFW_KEY_B 66 -#define GLFW_KEY_C 67 -#define GLFW_KEY_D 68 -#define GLFW_KEY_E 69 -#define GLFW_KEY_F 70 -#define GLFW_KEY_G 71 -#define GLFW_KEY_H 72 -#define GLFW_KEY_I 73 -#define GLFW_KEY_J 74 -#define GLFW_KEY_K 75 -#define GLFW_KEY_L 76 -#define GLFW_KEY_M 77 -#define GLFW_KEY_N 78 -#define GLFW_KEY_O 79 -#define GLFW_KEY_P 80 -#define GLFW_KEY_Q 81 -#define GLFW_KEY_R 82 -#define GLFW_KEY_S 83 -#define GLFW_KEY_T 84 -#define GLFW_KEY_U 85 -#define GLFW_KEY_V 86 -#define GLFW_KEY_W 87 -#define GLFW_KEY_X 88 -#define GLFW_KEY_Y 89 -#define GLFW_KEY_Z 90 -#define GLFW_KEY_LEFT_BRACKET 91 /* [ */ -#define GLFW_KEY_BACKSLASH 92 /* \ */ -#define GLFW_KEY_RIGHT_BRACKET 93 /* ] */ -#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */ -#define GLFW_KEY_WORLD_1 161 /* non-US #1 */ -#define GLFW_KEY_WORLD_2 162 /* non-US #2 */ - -/* Function keys */ -#define GLFW_KEY_ESCAPE 256 -#define GLFW_KEY_ENTER 257 -#define GLFW_KEY_TAB 258 -#define GLFW_KEY_BACKSPACE 259 -#define GLFW_KEY_INSERT 260 -#define GLFW_KEY_DELETE 261 -#define GLFW_KEY_RIGHT 262 -#define GLFW_KEY_LEFT 263 -#define GLFW_KEY_DOWN 264 -#define GLFW_KEY_UP 265 -#define GLFW_KEY_PAGE_UP 266 -#define GLFW_KEY_PAGE_DOWN 267 -#define GLFW_KEY_HOME 268 -#define GLFW_KEY_END 269 -#define GLFW_KEY_CAPS_LOCK 280 -#define GLFW_KEY_SCROLL_LOCK 281 -#define GLFW_KEY_NUM_LOCK 282 -#define GLFW_KEY_PRINT_SCREEN 283 -#define GLFW_KEY_PAUSE 284 -#define GLFW_KEY_F1 290 -#define GLFW_KEY_F2 291 -#define GLFW_KEY_F3 292 -#define GLFW_KEY_F4 293 -#define GLFW_KEY_F5 294 -#define GLFW_KEY_F6 295 -#define GLFW_KEY_F7 296 -#define GLFW_KEY_F8 297 -#define GLFW_KEY_F9 298 -#define GLFW_KEY_F10 299 -#define GLFW_KEY_F11 300 -#define GLFW_KEY_F12 301 -#define GLFW_KEY_F13 302 -#define GLFW_KEY_F14 303 -#define GLFW_KEY_F15 304 -#define GLFW_KEY_F16 305 -#define GLFW_KEY_F17 306 -#define GLFW_KEY_F18 307 -#define GLFW_KEY_F19 308 -#define GLFW_KEY_F20 309 -#define GLFW_KEY_F21 310 -#define GLFW_KEY_F22 311 -#define GLFW_KEY_F23 312 -#define GLFW_KEY_F24 313 -#define GLFW_KEY_F25 314 -#define GLFW_KEY_KP_0 320 -#define GLFW_KEY_KP_1 321 -#define GLFW_KEY_KP_2 322 -#define GLFW_KEY_KP_3 323 -#define GLFW_KEY_KP_4 324 -#define GLFW_KEY_KP_5 325 -#define GLFW_KEY_KP_6 326 -#define GLFW_KEY_KP_7 327 -#define GLFW_KEY_KP_8 328 -#define GLFW_KEY_KP_9 329 -#define GLFW_KEY_KP_DECIMAL 330 -#define GLFW_KEY_KP_DIVIDE 331 -#define GLFW_KEY_KP_MULTIPLY 332 -#define GLFW_KEY_KP_SUBTRACT 333 -#define GLFW_KEY_KP_ADD 334 -#define GLFW_KEY_KP_ENTER 335 -#define GLFW_KEY_KP_EQUAL 336 -#define GLFW_KEY_LEFT_SHIFT 340 -#define GLFW_KEY_LEFT_CONTROL 341 -#define GLFW_KEY_LEFT_ALT 342 -#define GLFW_KEY_LEFT_SUPER 343 -#define GLFW_KEY_RIGHT_SHIFT 344 -#define GLFW_KEY_RIGHT_CONTROL 345 -#define GLFW_KEY_RIGHT_ALT 346 -#define GLFW_KEY_RIGHT_SUPER 347 -#define GLFW_KEY_MENU 348 - -#define GLFW_KEY_LAST GLFW_KEY_MENU - -/*! @} */ - -/*! @defgroup mods Modifier key flags - * - * See [key input](@ref input_key) for how these are used. - * - * @ingroup input - * @{ */ - -/*! @brief If this bit is set one or more Shift keys were held down. - */ -#define GLFW_MOD_SHIFT 0x0001 -/*! @brief If this bit is set one or more Control keys were held down. - */ -#define GLFW_MOD_CONTROL 0x0002 -/*! @brief If this bit is set one or more Alt keys were held down. - */ -#define GLFW_MOD_ALT 0x0004 -/*! @brief If this bit is set one or more Super keys were held down. - */ -#define GLFW_MOD_SUPER 0x0008 - -/*! @} */ - -/*! @defgroup buttons Mouse buttons - * - * See [mouse button input](@ref input_mouse_button) for how these are used. - * - * @ingroup input - * @{ */ -#define GLFW_MOUSE_BUTTON_1 0 -#define GLFW_MOUSE_BUTTON_2 1 -#define GLFW_MOUSE_BUTTON_3 2 -#define GLFW_MOUSE_BUTTON_4 3 -#define GLFW_MOUSE_BUTTON_5 4 -#define GLFW_MOUSE_BUTTON_6 5 -#define GLFW_MOUSE_BUTTON_7 6 -#define GLFW_MOUSE_BUTTON_8 7 -#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8 -#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1 -#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2 -#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3 -/*! @} */ - -/*! @defgroup joysticks Joysticks - * - * See [joystick input](@ref joystick) for how these are used. - * - * @ingroup input - * @{ */ -#define GLFW_JOYSTICK_1 0 -#define GLFW_JOYSTICK_2 1 -#define GLFW_JOYSTICK_3 2 -#define GLFW_JOYSTICK_4 3 -#define GLFW_JOYSTICK_5 4 -#define GLFW_JOYSTICK_6 5 -#define GLFW_JOYSTICK_7 6 -#define GLFW_JOYSTICK_8 7 -#define GLFW_JOYSTICK_9 8 -#define GLFW_JOYSTICK_10 9 -#define GLFW_JOYSTICK_11 10 -#define GLFW_JOYSTICK_12 11 -#define GLFW_JOYSTICK_13 12 -#define GLFW_JOYSTICK_14 13 -#define GLFW_JOYSTICK_15 14 -#define GLFW_JOYSTICK_16 15 -#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16 -/*! @} */ - -/*! @defgroup errors Error codes - * - * See [error handling](@ref error_handling) for how these are used. - * - * @ingroup init - * @{ */ -/*! @brief GLFW has not been initialized. - * - * This occurs if a GLFW function was called that must not be called unless the - * library is [initialized](@ref intro_init). - * - * @analysis Application programmer error. Initialize GLFW before calling any - * function that requires initialization. - */ -#define GLFW_NOT_INITIALIZED 0x00010001 -/*! @brief No context is current for this thread. - * - * This occurs if a GLFW function was called that needs and operates on the - * current OpenGL or OpenGL ES context but no context is current on the calling - * thread. One such function is @ref glfwSwapInterval. - * - * @analysis Application programmer error. Ensure a context is current before - * calling functions that require a current context. - */ -#define GLFW_NO_CURRENT_CONTEXT 0x00010002 -/*! @brief One of the arguments to the function was an invalid enum value. - * - * One of the arguments to the function was an invalid enum value, for example - * requesting [GLFW_RED_BITS](@ref window_hints_fb) with @ref - * glfwGetWindowAttrib. - * - * @analysis Application programmer error. Fix the offending call. - */ -#define GLFW_INVALID_ENUM 0x00010003 -/*! @brief One of the arguments to the function was an invalid value. - * - * One of the arguments to the function was an invalid value, for example - * requesting a non-existent OpenGL or OpenGL ES version like 2.7. - * - * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead - * result in a @ref GLFW_VERSION_UNAVAILABLE error. - * - * @analysis Application programmer error. Fix the offending call. - */ -#define GLFW_INVALID_VALUE 0x00010004 -/*! @brief A memory allocation failed. - * - * A memory allocation failed. - * - * @analysis A bug in GLFW or the underlying operating system. Report the bug - * to our [issue tracker](https://github.com/glfw/glfw/issues). - */ -#define GLFW_OUT_OF_MEMORY 0x00010005 -/*! @brief GLFW could not find support for the requested API on the system. - * - * GLFW could not find support for the requested API on the system. - * - * @analysis The installed graphics driver does not support the requested - * API, or does not support it via the chosen context creation backend. - * Below are a few examples. - * - * @par - * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only - * supports OpenGL ES via EGL, while Nvidia and Intel only support it via - * a WGL or GLX extension. OS X does not provide OpenGL ES at all. The Mesa - * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary - * driver. Older graphics drivers do not support Vulkan. - */ -#define GLFW_API_UNAVAILABLE 0x00010006 -/*! @brief The requested OpenGL or OpenGL ES version is not available. - * - * The requested OpenGL or OpenGL ES version (including any requested context - * or framebuffer hints) is not available on this machine. - * - * @analysis The machine does not support your requirements. If your - * application is sufficiently flexible, downgrade your requirements and try - * again. Otherwise, inform the user that their machine does not match your - * requirements. - * - * @par - * Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 - * comes out before the 4.x series gets that far, also fail with this error and - * not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions - * will exist. - */ -#define GLFW_VERSION_UNAVAILABLE 0x00010007 -/*! @brief A platform-specific error occurred that does not match any of the - * more specific categories. - * - * A platform-specific error occurred that does not match any of the more - * specific categories. - * - * @analysis A bug or configuration error in GLFW, the underlying operating - * system or its drivers, or a lack of required resources. Report the issue to - * our [issue tracker](https://github.com/glfw/glfw/issues). - */ -#define GLFW_PLATFORM_ERROR 0x00010008 -/*! @brief The requested format is not supported or available. - * - * If emitted during window creation, the requested pixel format is not - * supported. - * - * If emitted when querying the clipboard, the contents of the clipboard could - * not be converted to the requested format. - * - * @analysis If emitted during window creation, one or more - * [hard constraints](@ref window_hints_hard) did not match any of the - * available pixel formats. If your application is sufficiently flexible, - * downgrade your requirements and try again. Otherwise, inform the user that - * their machine does not match your requirements. - * - * @par - * If emitted when querying the clipboard, ignore the error or report it to - * the user, as appropriate. - */ -#define GLFW_FORMAT_UNAVAILABLE 0x00010009 -/*! @brief The specified window does not have an OpenGL or OpenGL ES context. - * - * A window that does not have an OpenGL or OpenGL ES context was passed to - * a function that requires it to have one. - * - * @analysis Application programmer error. Fix the offending call. - */ -#define GLFW_NO_WINDOW_CONTEXT 0x0001000A -/*! @} */ - -#define GLFW_FOCUSED 0x00020001 -#define GLFW_ICONIFIED 0x00020002 -#define GLFW_RESIZABLE 0x00020003 -#define GLFW_VISIBLE 0x00020004 -#define GLFW_DECORATED 0x00020005 -#define GLFW_AUTO_ICONIFY 0x00020006 -#define GLFW_FLOATING 0x00020007 -#define GLFW_MAXIMIZED 0x00020008 - -#define GLFW_RED_BITS 0x00021001 -#define GLFW_GREEN_BITS 0x00021002 -#define GLFW_BLUE_BITS 0x00021003 -#define GLFW_ALPHA_BITS 0x00021004 -#define GLFW_DEPTH_BITS 0x00021005 -#define GLFW_STENCIL_BITS 0x00021006 -#define GLFW_ACCUM_RED_BITS 0x00021007 -#define GLFW_ACCUM_GREEN_BITS 0x00021008 -#define GLFW_ACCUM_BLUE_BITS 0x00021009 -#define GLFW_ACCUM_ALPHA_BITS 0x0002100A -#define GLFW_AUX_BUFFERS 0x0002100B -#define GLFW_STEREO 0x0002100C -#define GLFW_SAMPLES 0x0002100D -#define GLFW_SRGB_CAPABLE 0x0002100E -#define GLFW_REFRESH_RATE 0x0002100F -#define GLFW_DOUBLEBUFFER 0x00021010 - -#define GLFW_CLIENT_API 0x00022001 -#define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 -#define GLFW_CONTEXT_VERSION_MINOR 0x00022003 -#define GLFW_CONTEXT_REVISION 0x00022004 -#define GLFW_CONTEXT_ROBUSTNESS 0x00022005 -#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 -#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 -#define GLFW_OPENGL_PROFILE 0x00022008 -#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 -#define GLFW_CONTEXT_NO_ERROR 0x0002200A -#define GLFW_CONTEXT_CREATION_API 0x0002200B - -#define GLFW_NO_API 0 -#define GLFW_OPENGL_API 0x00030001 -#define GLFW_OPENGL_ES_API 0x00030002 - -#define GLFW_NO_ROBUSTNESS 0 -#define GLFW_NO_RESET_NOTIFICATION 0x00031001 -#define GLFW_LOSE_CONTEXT_ON_RESET 0x00031002 - -#define GLFW_OPENGL_ANY_PROFILE 0 -#define GLFW_OPENGL_CORE_PROFILE 0x00032001 -#define GLFW_OPENGL_COMPAT_PROFILE 0x00032002 - -#define GLFW_CURSOR 0x00033001 -#define GLFW_STICKY_KEYS 0x00033002 -#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 - -#define GLFW_CURSOR_NORMAL 0x00034001 -#define GLFW_CURSOR_HIDDEN 0x00034002 -#define GLFW_CURSOR_DISABLED 0x00034003 - -#define GLFW_ANY_RELEASE_BEHAVIOR 0 -#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 -#define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 - -#define GLFW_NATIVE_CONTEXT_API 0x00036001 -#define GLFW_EGL_CONTEXT_API 0x00036002 - -/*! @defgroup shapes Standard cursor shapes - * - * See [standard cursor creation](@ref cursor_standard) for how these are used. - * - * @ingroup input - * @{ */ - -/*! @brief The regular arrow cursor shape. - * - * The regular arrow cursor. - */ -#define GLFW_ARROW_CURSOR 0x00036001 -/*! @brief The text input I-beam cursor shape. - * - * The text input I-beam cursor shape. - */ -#define GLFW_IBEAM_CURSOR 0x00036002 -/*! @brief The crosshair shape. - * - * The crosshair shape. - */ -#define GLFW_CROSSHAIR_CURSOR 0x00036003 -/*! @brief The hand shape. - * - * The hand shape. - */ -#define GLFW_HAND_CURSOR 0x00036004 -/*! @brief The horizontal resize arrow shape. - * - * The horizontal resize arrow shape. - */ -#define GLFW_HRESIZE_CURSOR 0x00036005 -/*! @brief The vertical resize arrow shape. - * - * The vertical resize arrow shape. - */ -#define GLFW_VRESIZE_CURSOR 0x00036006 -/*! @} */ - -#define GLFW_CONNECTED 0x00040001 -#define GLFW_DISCONNECTED 0x00040002 - -#define GLFW_DONT_CARE -1 - - -/************************************************************************* - * GLFW API types - *************************************************************************/ - -/*! @brief Client API function pointer type. - * - * Generic function pointer used for returning client API function pointers - * without forcing a cast from a regular pointer. - * - * @sa @ref context_glext - * @sa glfwGetProcAddress - * - * @since Added in version 3.0. - - * @ingroup context - */ -typedef void (*GLFWglproc)(void); - -/*! @brief Vulkan API function pointer type. - * - * Generic function pointer used for returning Vulkan API function pointers - * without forcing a cast from a regular pointer. - * - * @sa @ref vulkan_proc - * @sa glfwGetInstanceProcAddress - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -typedef void (*GLFWvkproc)(void); - -/*! @brief Opaque monitor object. - * - * Opaque monitor object. - * - * @see @ref monitor_object - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -typedef struct GLFWmonitor GLFWmonitor; - -/*! @brief Opaque window object. - * - * Opaque window object. - * - * @see @ref window_object - * - * @since Added in version 3.0. - * - * @ingroup window - */ -typedef struct GLFWwindow GLFWwindow; - -/*! @brief Opaque cursor object. - * - * Opaque cursor object. - * - * @see @ref cursor_object - * - * @since Added in version 3.1. - * - * @ingroup cursor - */ -typedef struct GLFWcursor GLFWcursor; - -/*! @brief The function signature for error callbacks. - * - * This is the function signature for error callback functions. - * - * @param[in] error An [error code](@ref errors). - * @param[in] description A UTF-8 encoded string describing the error. - * - * @sa @ref error_handling - * @sa glfwSetErrorCallback - * - * @since Added in version 3.0. - * - * @ingroup init - */ -typedef void (* GLFWerrorfun)(int,const char*); - -/*! @brief The function signature for window position callbacks. - * - * This is the function signature for window position callback functions. - * - * @param[in] window The window that was moved. - * @param[in] xpos The new x-coordinate, in screen coordinates, of the - * upper-left corner of the client area of the window. - * @param[in] ypos The new y-coordinate, in screen coordinates, of the - * upper-left corner of the client area of the window. - * - * @sa @ref window_pos - * @sa glfwSetWindowPosCallback - * - * @since Added in version 3.0. - * - * @ingroup window - */ -typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); - -/*! @brief The function signature for window resize callbacks. - * - * This is the function signature for window size callback functions. - * - * @param[in] window The window that was resized. - * @param[in] width The new width, in screen coordinates, of the window. - * @param[in] height The new height, in screen coordinates, of the window. - * - * @sa @ref window_size - * @sa glfwSetWindowSizeCallback - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); - -/*! @brief The function signature for window close callbacks. - * - * This is the function signature for window close callback functions. - * - * @param[in] window The window that the user attempted to close. - * - * @sa @ref window_close - * @sa glfwSetWindowCloseCallback - * - * @since Added in version 2.5. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -typedef void (* GLFWwindowclosefun)(GLFWwindow*); - -/*! @brief The function signature for window content refresh callbacks. - * - * This is the function signature for window refresh callback functions. - * - * @param[in] window The window whose content needs to be refreshed. - * - * @sa @ref window_refresh - * @sa glfwSetWindowRefreshCallback - * - * @since Added in version 2.5. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); - -/*! @brief The function signature for window focus/defocus callbacks. - * - * This is the function signature for window focus callback functions. - * - * @param[in] window The window that gained or lost input focus. - * @param[in] focused `GLFW_TRUE` if the window was given input focus, or - * `GLFW_FALSE` if it lost it. - * - * @sa @ref window_focus - * @sa glfwSetWindowFocusCallback - * - * @since Added in version 3.0. - * - * @ingroup window - */ -typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); - -/*! @brief The function signature for window iconify/restore callbacks. - * - * This is the function signature for window iconify/restore callback - * functions. - * - * @param[in] window The window that was iconified or restored. - * @param[in] iconified `GLFW_TRUE` if the window was iconified, or - * `GLFW_FALSE` if it was restored. - * - * @sa @ref window_iconify - * @sa glfwSetWindowIconifyCallback - * - * @since Added in version 3.0. - * - * @ingroup window - */ -typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); - -/*! @brief The function signature for framebuffer resize callbacks. - * - * This is the function signature for framebuffer resize callback - * functions. - * - * @param[in] window The window whose framebuffer was resized. - * @param[in] width The new width, in pixels, of the framebuffer. - * @param[in] height The new height, in pixels, of the framebuffer. - * - * @sa @ref window_fbsize - * @sa glfwSetFramebufferSizeCallback - * - * @since Added in version 3.0. - * - * @ingroup window - */ -typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); - -/*! @brief The function signature for mouse button callbacks. - * - * This is the function signature for mouse button callback functions. - * - * @param[in] window The window that received the event. - * @param[in] button The [mouse button](@ref buttons) that was pressed or - * released. - * @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`. - * @param[in] mods Bit field describing which [modifier keys](@ref mods) were - * held down. - * - * @sa @ref input_mouse_button - * @sa glfwSetMouseButtonCallback - * - * @since Added in version 1.0. - * @glfw3 Added window handle and modifier mask parameters. - * - * @ingroup input - */ -typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); - -/*! @brief The function signature for cursor position callbacks. - * - * This is the function signature for cursor position callback functions. - * - * @param[in] window The window that received the event. - * @param[in] xpos The new cursor x-coordinate, relative to the left edge of - * the client area. - * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the - * client area. - * - * @sa @ref cursor_pos - * @sa glfwSetCursorPosCallback - * - * @since Added in version 3.0. Replaces `GLFWmouseposfun`. - * - * @ingroup input - */ -typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); - -/*! @brief The function signature for cursor enter/leave callbacks. - * - * This is the function signature for cursor enter/leave callback functions. - * - * @param[in] window The window that received the event. - * @param[in] entered `GLFW_TRUE` if the cursor entered the window's client - * area, or `GLFW_FALSE` if it left it. - * - * @sa @ref cursor_enter - * @sa glfwSetCursorEnterCallback - * - * @since Added in version 3.0. - * - * @ingroup input - */ -typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); - -/*! @brief The function signature for scroll callbacks. - * - * This is the function signature for scroll callback functions. - * - * @param[in] window The window that received the event. - * @param[in] xoffset The scroll offset along the x-axis. - * @param[in] yoffset The scroll offset along the y-axis. - * - * @sa @ref scrolling - * @sa glfwSetScrollCallback - * - * @since Added in version 3.0. Replaces `GLFWmousewheelfun`. - * - * @ingroup input - */ -typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); - -/*! @brief The function signature for keyboard key callbacks. - * - * This is the function signature for keyboard key callback functions. - * - * @param[in] window The window that received the event. - * @param[in] key The [keyboard key](@ref keys) that was pressed or released. - * @param[in] scancode The system-specific scancode of the key. - * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. - * @param[in] mods Bit field describing which [modifier keys](@ref mods) were - * held down. - * - * @sa @ref input_key - * @sa glfwSetKeyCallback - * - * @since Added in version 1.0. - * @glfw3 Added window handle, scancode and modifier mask parameters. - * - * @ingroup input - */ -typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); - -/*! @brief The function signature for Unicode character callbacks. - * - * This is the function signature for Unicode character callback functions. - * - * @param[in] window The window that received the event. - * @param[in] codepoint The Unicode code point of the character. - * - * @sa @ref input_char - * @sa glfwSetCharCallback - * - * @since Added in version 2.4. - * @glfw3 Added window handle parameter. - * - * @ingroup input - */ -typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); - -/*! @brief The function signature for Unicode character with modifiers - * callbacks. - * - * This is the function signature for Unicode character with modifiers callback - * functions. It is called for each input character, regardless of what - * modifier keys are held down. - * - * @param[in] window The window that received the event. - * @param[in] codepoint The Unicode code point of the character. - * @param[in] mods Bit field describing which [modifier keys](@ref mods) were - * held down. - * - * @sa @ref input_char - * @sa glfwSetCharModsCallback - * - * @since Added in version 3.1. - * - * @ingroup input - */ -typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); - -/*! @brief The function signature for file drop callbacks. - * - * This is the function signature for file drop callbacks. - * - * @param[in] window The window that received the event. - * @param[in] count The number of dropped files. - * @param[in] paths The UTF-8 encoded file and/or directory path names. - * - * @sa @ref path_drop - * @sa glfwSetDropCallback - * - * @since Added in version 3.1. - * - * @ingroup input - */ -typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); - -/*! @brief The function signature for monitor configuration callbacks. - * - * This is the function signature for monitor configuration callback functions. - * - * @param[in] monitor The monitor that was connected or disconnected. - * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. - * - * @sa @ref monitor_event - * @sa glfwSetMonitorCallback - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); - -/*! @brief The function signature for joystick configuration callbacks. - * - * This is the function signature for joystick configuration callback - * functions. - * - * @param[in] joy The joystick that was connected or disconnected. - * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. - * - * @sa @ref joystick_event - * @sa glfwSetJoystickCallback - * - * @since Added in version 3.2. - * - * @ingroup input - */ -typedef void (* GLFWjoystickfun)(int,int); - -/*! @brief Video mode type. - * - * This describes a single video mode. - * - * @sa @ref monitor_modes - * @sa glfwGetVideoMode glfwGetVideoModes - * - * @since Added in version 1.0. - * @glfw3 Added refresh rate member. - * - * @ingroup monitor - */ -typedef struct GLFWvidmode -{ - /*! The width, in screen coordinates, of the video mode. - */ - int width; - /*! The height, in screen coordinates, of the video mode. - */ - int height; - /*! The bit depth of the red channel of the video mode. - */ - int redBits; - /*! The bit depth of the green channel of the video mode. - */ - int greenBits; - /*! The bit depth of the blue channel of the video mode. - */ - int blueBits; - /*! The refresh rate, in Hz, of the video mode. - */ - int refreshRate; -} GLFWvidmode; - -/*! @brief Gamma ramp. - * - * This describes the gamma ramp for a monitor. - * - * @sa @ref monitor_gamma - * @sa glfwGetGammaRamp glfwSetGammaRamp - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -typedef struct GLFWgammaramp -{ - /*! An array of value describing the response of the red channel. - */ - unsigned short* red; - /*! An array of value describing the response of the green channel. - */ - unsigned short* green; - /*! An array of value describing the response of the blue channel. - */ - unsigned short* blue; - /*! The number of elements in each array. - */ - unsigned int size; -} GLFWgammaramp; - -/*! @brief Image data. - * - * @sa @ref cursor_custom - * - * @since Added in version 2.1. - * @glfw3 Removed format and bytes-per-pixel members. - */ -typedef struct GLFWimage -{ - /*! The width, in pixels, of this image. - */ - int width; - /*! The height, in pixels, of this image. - */ - int height; - /*! The pixel data of this image, arranged left-to-right, top-to-bottom. - */ - unsigned char* pixels; -} GLFWimage; - - -/************************************************************************* - * GLFW API functions - *************************************************************************/ - -/*! @brief Initializes the GLFW library. - * - * This function initializes the GLFW library. Before most GLFW functions can - * be used, GLFW must be initialized, and before an application terminates GLFW - * should be terminated in order to free any resources allocated during or - * after initialization. - * - * If this function fails, it calls @ref glfwTerminate before returning. If it - * succeeds, you should call @ref glfwTerminate before the application exits. - * - * Additional calls to this function after successful initialization but before - * termination will return `GLFW_TRUE` immediately. - * - * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. - * - * @remark @osx This function will change the current directory of the - * application to the `Contents/Resources` subdirectory of the application's - * bundle, if present. This can be disabled with a - * [compile-time option](@ref compile_options_osx). - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref intro_init - * @sa glfwTerminate - * - * @since Added in version 1.0. - * - * @ingroup init - */ -GLFWAPI int glfwInit(void); - -/*! @brief Terminates the GLFW library. - * - * This function destroys all remaining windows and cursors, restores any - * modified gamma ramps and frees any other allocated resources. Once this - * function is called, you must again call @ref glfwInit successfully before - * you will be able to use most GLFW functions. - * - * If GLFW has been successfully initialized, this function should be called - * before the application exits. If initialization fails, there is no need to - * call this function, as it is called by @ref glfwInit before it returns - * failure. - * - * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. - * - * @remark This function may be called before @ref glfwInit. - * - * @warning The contexts of any remaining windows must not be current on any - * other thread when this function is called. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref intro_init - * @sa glfwInit - * - * @since Added in version 1.0. - * - * @ingroup init - */ -GLFWAPI void glfwTerminate(void); - -/*! @brief Retrieves the version of the GLFW library. - * - * This function retrieves the major, minor and revision numbers of the GLFW - * library. It is intended for when you are using GLFW as a shared library and - * want to ensure that you are using the minimum required version. - * - * Any or all of the version arguments may be `NULL`. - * - * @param[out] major Where to store the major version number, or `NULL`. - * @param[out] minor Where to store the minor version number, or `NULL`. - * @param[out] rev Where to store the revision number, or `NULL`. - * - * @errors None. - * - * @remark This function may be called before @ref glfwInit. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref intro_version - * @sa glfwGetVersionString - * - * @since Added in version 1.0. - * - * @ingroup init - */ -GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); - -/*! @brief Returns a string describing the compile-time configuration. - * - * This function returns the compile-time generated - * [version string](@ref intro_version_string) of the GLFW library binary. It - * describes the version, platform, compiler and any platform-specific - * compile-time options. It should not be confused with the OpenGL or OpenGL - * ES version string, queried with `glGetString`. - * - * __Do not use the version string__ to parse the GLFW library version. The - * @ref glfwGetVersion function provides the version of the running library - * binary in numerical format. - * - * @return The ASCII encoded GLFW version string. - * - * @errors None. - * - * @remark This function may be called before @ref glfwInit. - * - * @pointer_lifetime The returned string is static and compile-time generated. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref intro_version - * @sa glfwGetVersion - * - * @since Added in version 3.0. - * - * @ingroup init - */ -GLFWAPI const char* glfwGetVersionString(void); - -/*! @brief Sets the error callback. - * - * This function sets the error callback, which is called with an error code - * and a human-readable description each time a GLFW error occurs. - * - * The error callback is called on the thread where the error occurred. If you - * are using GLFW from multiple threads, your error callback needs to be - * written accordingly. - * - * Because the description string may have been generated specifically for that - * error, it is not guaranteed to be valid after the callback has returned. If - * you wish to use it after the callback returns, you need to make a copy. - * - * Once set, the error callback remains set even after the library has been - * terminated. - * - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set. - * - * @errors None. - * - * @remark This function may be called before @ref glfwInit. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref error_handling - * - * @since Added in version 3.0. - * - * @ingroup init - */ -GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); - -/*! @brief Returns the currently connected monitors. - * - * This function returns an array of handles for all currently connected - * monitors. The primary monitor is always first in the returned array. If no - * monitors were found, this function returns `NULL`. - * - * @param[out] count Where to store the number of monitors in the returned - * array. This is set to zero if an error occurred. - * @return An array of monitor handles, or `NULL` if no monitors were found or - * if an [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is guaranteed to be valid only until the - * monitor configuration changes or the library is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_monitors - * @sa @ref monitor_event - * @sa glfwGetPrimaryMonitor - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); - -/*! @brief Returns the primary monitor. - * - * This function returns the primary monitor. This is usually the monitor - * where elements like the task bar or global menu bar are located. - * - * @return The primary monitor, or `NULL` if no monitors were found or if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @remark The primary monitor is always first in the array returned by @ref - * glfwGetMonitors. - * - * @sa @ref monitor_monitors - * @sa glfwGetMonitors - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); - -/*! @brief Returns the position of the monitor's viewport on the virtual screen. - * - * This function returns the position, in screen coordinates, of the upper-left - * corner of the specified monitor. - * - * Any or all of the position arguments may be `NULL`. If an error occurs, all - * non-`NULL` position arguments will be set to zero. - * - * @param[in] monitor The monitor to query. - * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. - * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_properties - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); - -/*! @brief Returns the physical size of the monitor. - * - * This function returns the size, in millimetres, of the display area of the - * specified monitor. - * - * Some systems do not provide accurate monitor size information, either - * because the monitor - * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data) - * data is incorrect or because the driver does not report it accurately. - * - * Any or all of the size arguments may be `NULL`. If an error occurs, all - * non-`NULL` size arguments will be set to zero. - * - * @param[in] monitor The monitor to query. - * @param[out] widthMM Where to store the width, in millimetres, of the - * monitor's display area, or `NULL`. - * @param[out] heightMM Where to store the height, in millimetres, of the - * monitor's display area, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @remark @win32 calculates the returned physical size from the - * current resolution and system DPI instead of querying the monitor EDID data. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_properties - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM); - -/*! @brief Returns the name of the specified monitor. - * - * This function returns a human-readable name, encoded as UTF-8, of the - * specified monitor. The name typically reflects the make and model of the - * monitor and is not guaranteed to be unique among the connected monitors. - * - * @param[in] monitor The monitor to query. - * @return The UTF-8 encoded name of the monitor, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @pointer_lifetime The returned string is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified monitor is - * disconnected or the library is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_properties - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); - -/*! @brief Sets the monitor configuration callback. - * - * This function sets the monitor configuration callback, or removes the - * currently set callback. This is called when a monitor is connected to or - * disconnected from the system. - * - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_event - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); - -/*! @brief Returns the available video modes for the specified monitor. - * - * This function returns an array of all video modes supported by the specified - * monitor. The returned array is sorted in ascending order, first by color - * bit depth (the sum of all channel depths) and then by resolution area (the - * product of width and height). - * - * @param[in] monitor The monitor to query. - * @param[out] count Where to store the number of video modes in the returned - * array. This is set to zero if an error occurred. - * @return An array of video modes, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified monitor is - * disconnected, this function is called again for that monitor or the library - * is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_modes - * @sa glfwGetVideoMode - * - * @since Added in version 1.0. - * @glfw3 Changed to return an array of modes for a specific monitor. - * - * @ingroup monitor - */ -GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); - -/*! @brief Returns the current mode of the specified monitor. - * - * This function returns the current video mode of the specified monitor. If - * you have created a full screen window for that monitor, the return value - * will depend on whether that window is iconified. - * - * @param[in] monitor The monitor to query. - * @return The current mode of the monitor, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified monitor is - * disconnected or the library is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_modes - * @sa glfwGetVideoModes - * - * @since Added in version 3.0. Replaces `glfwGetDesktopMode`. - * - * @ingroup monitor - */ -GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); - -/*! @brief Generates a gamma ramp and sets it for the specified monitor. - * - * This function generates a 256-element gamma ramp from the specified exponent - * and then calls @ref glfwSetGammaRamp with it. The value must be a finite - * number greater than zero. - * - * @param[in] monitor The monitor whose gamma ramp to set. - * @param[in] gamma The desired exponent. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_gamma - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); - -/*! @brief Returns the current gamma ramp for the specified monitor. - * - * This function returns the current gamma ramp of the specified monitor. - * - * @param[in] monitor The monitor to query. - * @return The current gamma ramp, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned structure and its arrays are allocated and - * freed by GLFW. You should not free them yourself. They are valid until the - * specified monitor is disconnected, this function is called again for that - * monitor or the library is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_gamma - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); - -/*! @brief Sets the current gamma ramp for the specified monitor. - * - * This function sets the current gamma ramp for the specified monitor. The - * original gamma ramp for that monitor is saved by GLFW the first time this - * function is called and is restored by @ref glfwTerminate. - * - * @param[in] monitor The monitor whose gamma ramp to set. - * @param[in] ramp The gamma ramp to use. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @remark Gamma ramp sizes other than 256 are not supported by all platforms - * or graphics hardware. - * - * @remark @win32 The gamma ramp size must be 256. - * - * @pointer_lifetime The specified gamma ramp is copied before this function - * returns. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_gamma - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); - -/*! @brief Resets all window hints to their default values. - * - * This function resets all window hints to their - * [default values](@ref window_hints_values). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_hints - * @sa glfwWindowHint - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwDefaultWindowHints(void); - -/*! @brief Sets the specified window hint to the desired value. - * - * This function sets hints for the next call to @ref glfwCreateWindow. The - * hints, once set, retain their values until changed by a call to @ref - * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is - * terminated. - * - * This function does not check whether the specified hint values are valid. - * If you set hints to invalid values this will instead be reported by the next - * call to @ref glfwCreateWindow. - * - * @param[in] hint The [window hint](@ref window_hints) to set. - * @param[in] value The new value of the window hint. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_ENUM. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_hints - * @sa glfwDefaultWindowHints - * - * @since Added in version 3.0. Replaces `glfwOpenWindowHint`. - * - * @ingroup window - */ -GLFWAPI void glfwWindowHint(int hint, int value); - -/*! @brief Creates a window and its associated context. - * - * This function creates a window and its associated OpenGL or OpenGL ES - * context. Most of the options controlling how the window and its context - * should be created are specified with [window hints](@ref window_hints). - * - * Successful creation does not change which context is current. Before you - * can use the newly created context, you need to - * [make it current](@ref context_current). For information about the `share` - * parameter, see @ref context_sharing. - * - * The created window, framebuffer and context may differ from what you - * requested, as not all parameters and hints are - * [hard constraints](@ref window_hints_hard). This includes the size of the - * window, especially for full screen windows. To query the actual attributes - * of the created window, framebuffer and context, see @ref - * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. - * - * To create a full screen window, you need to specify the monitor the window - * will cover. If no monitor is specified, the window will be windowed mode. - * Unless you have a way for the user to choose a specific monitor, it is - * recommended that you pick the primary monitor. For more information on how - * to query connected monitors, see @ref monitor_monitors. - * - * For full screen windows, the specified size becomes the resolution of the - * window's _desired video mode_. As long as a full screen window is not - * iconified, the supported video mode most closely matching the desired video - * mode is set for the specified monitor. For more information about full - * screen windows, including the creation of so called _windowed full screen_ - * or _borderless full screen_ windows, see @ref window_windowed_full_screen. - * - * By default, newly created windows use the placement recommended by the - * window system. To create the window at a specific position, make it - * initially invisible using the [GLFW_VISIBLE](@ref window_hints_wnd) window - * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) - * it. - * - * As long as at least one full screen window is not iconified, the screensaver - * is prohibited from starting. - * - * Window systems put limits on window sizes. Very large or very small window - * dimensions may be overridden by the window system on creation. Check the - * actual [size](@ref window_size) after creation. - * - * The [swap interval](@ref buffer_swap) is not set during window creation and - * the initial value may vary depending on driver settings and defaults. - * - * @param[in] width The desired width, in screen coordinates, of the window. - * This must be greater than zero. - * @param[in] height The desired height, in screen coordinates, of the window. - * This must be greater than zero. - * @param[in] title The initial, UTF-8 encoded window title. - * @param[in] monitor The monitor to use for full screen mode, or `NULL` for - * windowed mode. - * @param[in] share The window whose context to share resources with, or `NULL` - * to not share resources. - * @return The handle of the created window, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref - * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref - * GLFW_PLATFORM_ERROR. - * - * @remark @win32 Window creation will fail if the Microsoft GDI software - * OpenGL implementation is the only one available. - * - * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it - * will be set as the initial icon for the window. If no such icon is present, - * the `IDI_WINLOGO` icon will be used instead. To set a different icon, see - * @ref glfwSetWindowIcon. - * - * @remark @win32 The context to share resources with must not be current on - * any other thread. - * - * @remark @osx The GLFW window has no icon, as it is not a document - * window, but the dock icon will be the same as the application bundle's icon. - * For more information on bundles, see the - * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) - * in the Mac Developer Library. - * - * @remark @osx The first time a window is created the menu bar is populated - * with common commands like Hide, Quit and About. The About entry opens - * a minimal about dialog with information from the application's bundle. The - * menu bar can be disabled with a - * [compile-time option](@ref compile_options_osx). - * - * @remark @osx On OS X 10.10 and later the window frame will not be rendered - * at full resolution on Retina displays unless the `NSHighResolutionCapable` - * key is enabled in the application bundle's `Info.plist`. For more - * information, see - * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) - * in the Mac Developer Library. The GLFW test and example programs use - * a custom `Info.plist` template for this, which can be found as - * `CMake/MacOSXBundleInfo.plist.in` in the source tree. - * - * @remark @x11 Some window managers will not respect the placement of - * initially hidden windows. - * - * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for - * a window to reach its requested state. This means you may not be able to - * query the final size, position or other attributes directly after window - * creation. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_creation - * @sa glfwDestroyWindow - * - * @since Added in version 3.0. Replaces `glfwOpenWindow`. - * - * @ingroup window - */ -GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); - -/*! @brief Destroys the specified window and its context. - * - * This function destroys the specified window and its context. On calling - * this function, no further callbacks will be called for that window. - * - * If the context of the specified window is current on the main thread, it is - * detached before being destroyed. - * - * @param[in] window The window to destroy. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @note The context of the specified window must not be current on any other - * thread when this function is called. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_creation - * @sa glfwCreateWindow - * - * @since Added in version 3.0. Replaces `glfwCloseWindow`. - * - * @ingroup window - */ -GLFWAPI void glfwDestroyWindow(GLFWwindow* window); - -/*! @brief Checks the close flag of the specified window. - * - * This function returns the value of the close flag of the specified window. - * - * @param[in] window The window to query. - * @return The value of the close flag. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @sa @ref window_close - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); - -/*! @brief Sets the close flag of the specified window. - * - * This function sets the value of the close flag of the specified window. - * This can be used to override the user's attempt to close the window, or - * to signal that it should be closed. - * - * @param[in] window The window whose flag to change. - * @param[in] value The new value. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @sa @ref window_close - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); - -/*! @brief Sets the title of the specified window. - * - * This function sets the window title, encoded as UTF-8, of the specified - * window. - * - * @param[in] window The window whose title to change. - * @param[in] title The UTF-8 encoded window title. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @remark @osx The window title will not be updated until the next time you - * process events. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_title - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); - -/*! @brief Sets the icon for the specified window. - * - * This function sets the icon of the specified window. If passed an array of - * candidate images, those of or closest to the sizes desired by the system are - * selected. If no images are specified, the window reverts to its default - * icon. - * - * The desired image sizes varies depending on platform and system settings. - * The selected images will be rescaled as needed. Good sizes include 16x16, - * 32x32 and 48x48. - * - * @param[in] window The window whose icon to set. - * @param[in] count The number of images in the specified array, or zero to - * revert to the default window icon. - * @param[in] images The images to create the icon from. This is ignored if - * count is zero. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The specified image data is copied before this function - * returns. - * - * @remark @osx The GLFW window has no icon, as it is not a document - * window, so this function does nothing. The dock icon will be the same as - * the application bundle's icon. For more information on bundles, see the - * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) - * in the Mac Developer Library. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_icon - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images); - -/*! @brief Retrieves the position of the client area of the specified window. - * - * This function retrieves the position, in screen coordinates, of the - * upper-left corner of the client area of the specified window. - * - * Any or all of the position arguments may be `NULL`. If an error occurs, all - * non-`NULL` position arguments will be set to zero. - * - * @param[in] window The window to query. - * @param[out] xpos Where to store the x-coordinate of the upper-left corner of - * the client area, or `NULL`. - * @param[out] ypos Where to store the y-coordinate of the upper-left corner of - * the client area, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_pos - * @sa glfwSetWindowPos - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); - -/*! @brief Sets the position of the client area of the specified window. - * - * This function sets the position, in screen coordinates, of the upper-left - * corner of the client area of the specified windowed mode window. If the - * window is a full screen window, this function does nothing. - * - * __Do not use this function__ to move an already visible window unless you - * have very good reasons for doing so, as it will confuse and annoy the user. - * - * The window manager may put limits on what positions are allowed. GLFW - * cannot and should not override these limits. - * - * @param[in] window The window to query. - * @param[in] xpos The x-coordinate of the upper-left corner of the client area. - * @param[in] ypos The y-coordinate of the upper-left corner of the client area. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_pos - * @sa glfwGetWindowPos - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); - -/*! @brief Retrieves the size of the client area of the specified window. - * - * This function retrieves the size, in screen coordinates, of the client area - * of the specified window. If you wish to retrieve the size of the - * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize. - * - * Any or all of the size arguments may be `NULL`. If an error occurs, all - * non-`NULL` size arguments will be set to zero. - * - * @param[in] window The window whose size to retrieve. - * @param[out] width Where to store the width, in screen coordinates, of the - * client area, or `NULL`. - * @param[out] height Where to store the height, in screen coordinates, of the - * client area, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_size - * @sa glfwSetWindowSize - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); - -/*! @brief Sets the size limits of the specified window. - * - * This function sets the size limits of the client area of the specified - * window. If the window is full screen, the size limits only take effect - * once it is made windowed. If the window is not resizable, this function - * does nothing. - * - * The size limits are applied immediately to a windowed mode window and may - * cause it to be resized. - * - * The maximum dimensions must be greater than or equal to the minimum - * dimensions and all must be greater than or equal to zero. - * - * @param[in] window The window to set limits for. - * @param[in] minwidth The minimum width, in screen coordinates, of the client - * area, or `GLFW_DONT_CARE`. - * @param[in] minheight The minimum height, in screen coordinates, of the - * client area, or `GLFW_DONT_CARE`. - * @param[in] maxwidth The maximum width, in screen coordinates, of the client - * area, or `GLFW_DONT_CARE`. - * @param[in] maxheight The maximum height, in screen coordinates, of the - * client area, or `GLFW_DONT_CARE`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. - * - * @remark If you set size limits and an aspect ratio that conflict, the - * results are undefined. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_sizelimits - * @sa glfwSetWindowAspectRatio - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); - -/*! @brief Sets the aspect ratio of the specified window. - * - * This function sets the required aspect ratio of the client area of the - * specified window. If the window is full screen, the aspect ratio only takes - * effect once it is made windowed. If the window is not resizable, this - * function does nothing. - * - * The aspect ratio is specified as a numerator and a denominator and both - * values must be greater than zero. For example, the common 16:9 aspect ratio - * is specified as 16 and 9, respectively. - * - * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect - * ratio limit is disabled. - * - * The aspect ratio is applied immediately to a windowed mode window and may - * cause it to be resized. - * - * @param[in] window The window to set limits for. - * @param[in] numer The numerator of the desired aspect ratio, or - * `GLFW_DONT_CARE`. - * @param[in] denom The denominator of the desired aspect ratio, or - * `GLFW_DONT_CARE`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. - * - * @remark If you set size limits and an aspect ratio that conflict, the - * results are undefined. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_sizelimits - * @sa glfwSetWindowSizeLimits - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); - -/*! @brief Sets the size of the client area of the specified window. - * - * This function sets the size, in screen coordinates, of the client area of - * the specified window. - * - * For full screen windows, this function updates the resolution of its desired - * video mode and switches to the video mode closest to it, without affecting - * the window's context. As the context is unaffected, the bit depths of the - * framebuffer remain unchanged. - * - * If you wish to update the refresh rate of the desired video mode in addition - * to its resolution, see @ref glfwSetWindowMonitor. - * - * The window manager may put limits on what sizes are allowed. GLFW cannot - * and should not override these limits. - * - * @param[in] window The window to resize. - * @param[in] width The desired width, in screen coordinates, of the window - * client area. - * @param[in] height The desired height, in screen coordinates, of the window - * client area. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_size - * @sa glfwGetWindowSize - * @sa glfwSetWindowMonitor - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); - -/*! @brief Retrieves the size of the framebuffer of the specified window. - * - * This function retrieves the size, in pixels, of the framebuffer of the - * specified window. If you wish to retrieve the size of the window in screen - * coordinates, see @ref glfwGetWindowSize. - * - * Any or all of the size arguments may be `NULL`. If an error occurs, all - * non-`NULL` size arguments will be set to zero. - * - * @param[in] window The window whose framebuffer to query. - * @param[out] width Where to store the width, in pixels, of the framebuffer, - * or `NULL`. - * @param[out] height Where to store the height, in pixels, of the framebuffer, - * or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_fbsize - * @sa glfwSetFramebufferSizeCallback - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); - -/*! @brief Retrieves the size of the frame of the window. - * - * This function retrieves the size, in screen coordinates, of each edge of the - * frame of the specified window. This size includes the title bar, if the - * window has one. The size of the frame may vary depending on the - * [window-related hints](@ref window_hints_wnd) used to create it. - * - * Because this function retrieves the size of each window frame edge and not - * the offset along a particular coordinate axis, the retrieved values will - * always be zero or positive. - * - * Any or all of the size arguments may be `NULL`. If an error occurs, all - * non-`NULL` size arguments will be set to zero. - * - * @param[in] window The window whose frame size to query. - * @param[out] left Where to store the size, in screen coordinates, of the left - * edge of the window frame, or `NULL`. - * @param[out] top Where to store the size, in screen coordinates, of the top - * edge of the window frame, or `NULL`. - * @param[out] right Where to store the size, in screen coordinates, of the - * right edge of the window frame, or `NULL`. - * @param[out] bottom Where to store the size, in screen coordinates, of the - * bottom edge of the window frame, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_size - * - * @since Added in version 3.1. - * - * @ingroup window - */ -GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); - -/*! @brief Iconifies the specified window. - * - * This function iconifies (minimizes) the specified window if it was - * previously restored. If the window is already iconified, this function does - * nothing. - * - * If the specified window is a full screen window, the original monitor - * resolution is restored until the window is restored. - * - * @param[in] window The window to iconify. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_iconify - * @sa glfwRestoreWindow - * @sa glfwMaximizeWindow - * - * @since Added in version 2.1. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwIconifyWindow(GLFWwindow* window); - -/*! @brief Restores the specified window. - * - * This function restores the specified window if it was previously iconified - * (minimized) or maximized. If the window is already restored, this function - * does nothing. - * - * If the specified window is a full screen window, the resolution chosen for - * the window is restored on the selected monitor. - * - * @param[in] window The window to restore. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_iconify - * @sa glfwIconifyWindow - * @sa glfwMaximizeWindow - * - * @since Added in version 2.1. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwRestoreWindow(GLFWwindow* window); - -/*! @brief Maximizes the specified window. - * - * This function maximizes the specified window if it was previously not - * maximized. If the window is already maximized, this function does nothing. - * - * If the specified window is a full screen window, this function does nothing. - * - * @param[in] window The window to maximize. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @par Thread Safety - * This function may only be called from the main thread. - * - * @sa @ref window_iconify - * @sa glfwIconifyWindow - * @sa glfwRestoreWindow - * - * @since Added in GLFW 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); - -/*! @brief Makes the specified window visible. - * - * This function makes the specified window visible if it was previously - * hidden. If the window is already visible or is in full screen mode, this - * function does nothing. - * - * @param[in] window The window to make visible. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_hide - * @sa glfwHideWindow - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwShowWindow(GLFWwindow* window); - -/*! @brief Hides the specified window. - * - * This function hides the specified window if it was previously visible. If - * the window is already hidden or is in full screen mode, this function does - * nothing. - * - * @param[in] window The window to hide. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_hide - * @sa glfwShowWindow - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwHideWindow(GLFWwindow* window); - -/*! @brief Brings the specified window to front and sets input focus. - * - * This function brings the specified window to front and sets input focus. - * The window should already be visible and not iconified. - * - * By default, both windowed and full screen mode windows are focused when - * initially created. Set the [GLFW_FOCUSED](@ref window_hints_wnd) to disable - * this behavior. - * - * __Do not use this function__ to steal focus from other applications unless - * you are certain that is what the user wants. Focus stealing can be - * extremely disruptive. - * - * @param[in] window The window to give input focus. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_focus - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwFocusWindow(GLFWwindow* window); - -/*! @brief Returns the monitor that the window uses for full screen mode. - * - * This function returns the handle of the monitor that the specified window is - * in full screen on. - * - * @param[in] window The window to query. - * @return The monitor, or `NULL` if the window is in windowed mode or an error - * occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_monitor - * @sa glfwSetWindowMonitor - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); - -/*! @brief Sets the mode, monitor, video mode and placement of a window. - * - * This function sets the monitor that the window uses for full screen mode or, - * if the monitor is `NULL`, makes it windowed mode. - * - * When setting a monitor, this function updates the width, height and refresh - * rate of the desired video mode and switches to the video mode closest to it. - * The window position is ignored when setting a monitor. - * - * When the monitor is `NULL`, the position, width and height are used to - * place the window client area. The refresh rate is ignored when no monitor - * is specified. - * - * If you only wish to update the resolution of a full screen window or the - * size of a windowed mode window, see @ref glfwSetWindowSize. - * - * When a window transitions from full screen to windowed mode, this function - * restores any previous window settings such as whether it is decorated, - * floating, resizable, has size or aspect ratio limits, etc.. - * - * @param[in] window The window whose monitor, size or video mode to set. - * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. - * @param[in] xpos The desired x-coordinate of the upper-left corner of the - * client area. - * @param[in] ypos The desired y-coordinate of the upper-left corner of the - * client area. - * @param[in] width The desired with, in screen coordinates, of the client area - * or video mode. - * @param[in] height The desired height, in screen coordinates, of the client - * area or video mode. - * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode, - * or `GLFW_DONT_CARE`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_monitor - * @sa @ref window_full_screen - * @sa glfwGetWindowMonitor - * @sa glfwSetWindowSize - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); - -/*! @brief Returns an attribute of the specified window. - * - * This function returns the value of an attribute of the specified window or - * its OpenGL or OpenGL ES context. - * - * @param[in] window The window to query. - * @param[in] attrib The [window attribute](@ref window_attribs) whose value to - * return. - * @return The value of the attribute, or zero if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @remark Framebuffer related hints are not window attributes. See @ref - * window_attribs_fb for more information. - * - * @remark Zero is a valid value for many window and context related - * attributes so you cannot use a return value of zero as an indication of - * errors. However, this function should not fail as long as it is passed - * valid arguments and the library has been [initialized](@ref intro_init). - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_attribs - * - * @since Added in version 3.0. Replaces `glfwGetWindowParam` and - * `glfwGetGLVersion`. - * - * @ingroup window - */ -GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); - -/*! @brief Sets the user pointer of the specified window. - * - * This function sets the user-defined pointer of the specified window. The - * current value is retained until the window is destroyed. The initial value - * is `NULL`. - * - * @param[in] window The window whose pointer to set. - * @param[in] pointer The new value. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @sa @ref window_userptr - * @sa glfwGetWindowUserPointer - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); - -/*! @brief Returns the user pointer of the specified window. - * - * This function returns the current value of the user-defined pointer of the - * specified window. The initial value is `NULL`. - * - * @param[in] window The window whose pointer to return. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @sa @ref window_userptr - * @sa glfwSetWindowUserPointer - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); - -/*! @brief Sets the position callback for the specified window. - * - * This function sets the position callback of the specified window, which is - * called when the window is moved. The callback is provided with the screen - * position of the upper-left corner of the client area of the window. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_pos - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun cbfun); - -/*! @brief Sets the size callback for the specified window. - * - * This function sets the size callback of the specified window, which is - * called when the window is resized. The callback is provided with the size, - * in screen coordinates, of the client area of the window. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_size - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup window - */ -GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun cbfun); - -/*! @brief Sets the close callback for the specified window. - * - * This function sets the close callback of the specified window, which is - * called when the user attempts to close the window, for example by clicking - * the close widget in the title bar. - * - * The close flag is set before this callback is called, but you can modify it - * at any time with @ref glfwSetWindowShouldClose. - * - * The close callback is not triggered by @ref glfwDestroyWindow. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @remark @osx Selecting Quit from the application menu will trigger the close - * callback for all windows. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_close - * - * @since Added in version 2.5. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup window - */ -GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun cbfun); - -/*! @brief Sets the refresh callback for the specified window. - * - * This function sets the refresh callback of the specified window, which is - * called when the client area of the window needs to be redrawn, for example - * if the window has been exposed after having been covered by another window. - * - * On compositing window systems such as Aero, Compiz or Aqua, where the window - * contents are saved off-screen, this callback may be called only very - * infrequently or never at all. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_refresh - * - * @since Added in version 2.5. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup window - */ -GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun cbfun); - -/*! @brief Sets the focus callback for the specified window. - * - * This function sets the focus callback of the specified window, which is - * called when the window gains or loses input focus. - * - * After the focus callback is called for a window that lost input focus, - * synthetic key and mouse button release events will be generated for all such - * that had been pressed. For more information, see @ref glfwSetKeyCallback - * and @ref glfwSetMouseButtonCallback. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_focus - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun cbfun); - -/*! @brief Sets the iconify callback for the specified window. - * - * This function sets the iconification callback of the specified window, which - * is called when the window is iconified or restored. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_iconify - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun cbfun); - -/*! @brief Sets the framebuffer resize callback for the specified window. - * - * This function sets the framebuffer resize callback of the specified window, - * which is called when the framebuffer of the specified window is resized. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_fbsize - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun); - -/*! @brief Processes all pending events. - * - * This function processes only those events that are already in the event - * queue and then returns immediately. Processing events will cause the window - * and input callbacks associated with those events to be called. - * - * On some platforms, a window move, resize or menu operation will cause event - * processing to block. This is due to how event processing is designed on - * those platforms. You can use the - * [window refresh callback](@ref window_refresh) to redraw the contents of - * your window when necessary during such operations. - * - * On some platforms, certain events are sent directly to the application - * without going through the event queue, causing callbacks to be called - * outside of a call to one of the event processing functions. - * - * Event processing is not required for joystick input to work. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref events - * @sa glfwWaitEvents - * @sa glfwWaitEventsTimeout - * - * @since Added in version 1.0. - * - * @ingroup window - */ -GLFWAPI void glfwPollEvents(void); - -/*! @brief Waits until events are queued and processes them. - * - * This function puts the calling thread to sleep until at least one event is - * available in the event queue. Once one or more events are available, - * it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue - * are processed and the function then returns immediately. Processing events - * will cause the window and input callbacks associated with those events to be - * called. - * - * Since not all events are associated with callbacks, this function may return - * without a callback having been called even if you are monitoring all - * callbacks. - * - * On some platforms, a window move, resize or menu operation will cause event - * processing to block. This is due to how event processing is designed on - * those platforms. You can use the - * [window refresh callback](@ref window_refresh) to redraw the contents of - * your window when necessary during such operations. - * - * On some platforms, certain callbacks may be called outside of a call to one - * of the event processing functions. - * - * If no windows exist, this function returns immediately. For synchronization - * of threads in applications that do not create windows, use your threading - * library of choice. - * - * Event processing is not required for joystick input to work. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref events - * @sa glfwPollEvents - * @sa glfwWaitEventsTimeout - * - * @since Added in version 2.5. - * - * @ingroup window - */ -GLFWAPI void glfwWaitEvents(void); - -/*! @brief Waits with timeout until events are queued and processes them. - * - * This function puts the calling thread to sleep until at least one event is - * available in the event queue, or until the specified timeout is reached. If - * one or more events are available, it behaves exactly like @ref - * glfwPollEvents, i.e. the events in the queue are processed and the function - * then returns immediately. Processing events will cause the window and input - * callbacks associated with those events to be called. - * - * The timeout value must be a positive finite number. - * - * Since not all events are associated with callbacks, this function may return - * without a callback having been called even if you are monitoring all - * callbacks. - * - * On some platforms, a window move, resize or menu operation will cause event - * processing to block. This is due to how event processing is designed on - * those platforms. You can use the - * [window refresh callback](@ref window_refresh) to redraw the contents of - * your window when necessary during such operations. - * - * On some platforms, certain callbacks may be called outside of a call to one - * of the event processing functions. - * - * If no windows exist, this function returns immediately. For synchronization - * of threads in applications that do not create windows, use your threading - * library of choice. - * - * Event processing is not required for joystick input to work. - * - * @param[in] timeout The maximum amount of time, in seconds, to wait. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref events - * @sa glfwPollEvents - * @sa glfwWaitEvents - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwWaitEventsTimeout(double timeout); - -/*! @brief Posts an empty event to the event queue. - * - * This function posts an empty event from the current thread to the event - * queue, causing @ref glfwWaitEvents to return. - * - * If no windows exist, this function returns immediately. For synchronization - * of threads in applications that do not create windows, use your threading - * library of choice. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref events - * @sa glfwWaitEvents - * - * @since Added in version 3.1. - * - * @ingroup window - */ -GLFWAPI void glfwPostEmptyEvent(void); - -/*! @brief Returns the value of an input option for the specified window. - * - * This function returns the value of an input option for the specified window. - * The mode must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. - * - * @param[in] window The window to query. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_ENUM. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa glfwSetInputMode - * - * @since Added in version 3.0. - * - * @ingroup input - */ -GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); - -/*! @brief Sets an input option for the specified window. - * - * This function sets an input mode option for the specified window. The mode - * must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. - * - * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor - * modes: - * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. - * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client - * area of the window but does not restrict the cursor from leaving. - * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual - * and unlimited cursor movement. This is useful for implementing for - * example 3D camera controls. - * - * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to - * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are - * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` - * the next time it is called even if the key had been released before the - * call. This is useful when you are only interested in whether keys have been - * pressed but not when or in which order. - * - * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either - * `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it. - * If sticky mouse buttons are enabled, a mouse button press will ensure that - * @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even - * if the mouse button had been released before the call. This is useful when - * you are only interested in whether mouse buttons have been pressed but not - * when or in which order. - * - * @param[in] window The window whose input mode to set. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. - * @param[in] value The new value of the specified input mode. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa glfwGetInputMode - * - * @since Added in version 3.0. Replaces `glfwEnable` and `glfwDisable`. - * - * @ingroup input - */ -GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); - -/*! @brief Returns the localized name of the specified printable key. - * - * This function returns the localized name of the specified printable key. - * This is intended for displaying key bindings to the user. - * - * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used instead, otherwise - * the scancode is ignored. If a non-printable key or (if the key is - * `GLFW_KEY_UNKNOWN`) a scancode that maps to a non-printable key is - * specified, this function returns `NULL`. - * - * This behavior allows you to pass in the arguments passed to the - * [key callback](@ref input_key) without modification. - * - * The printable keys are: - * - `GLFW_KEY_APOSTROPHE` - * - `GLFW_KEY_COMMA` - * - `GLFW_KEY_MINUS` - * - `GLFW_KEY_PERIOD` - * - `GLFW_KEY_SLASH` - * - `GLFW_KEY_SEMICOLON` - * - `GLFW_KEY_EQUAL` - * - `GLFW_KEY_LEFT_BRACKET` - * - `GLFW_KEY_RIGHT_BRACKET` - * - `GLFW_KEY_BACKSLASH` - * - `GLFW_KEY_WORLD_1` - * - `GLFW_KEY_WORLD_2` - * - `GLFW_KEY_0` to `GLFW_KEY_9` - * - `GLFW_KEY_A` to `GLFW_KEY_Z` - * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9` - * - `GLFW_KEY_KP_DECIMAL` - * - `GLFW_KEY_KP_DIVIDE` - * - `GLFW_KEY_KP_MULTIPLY` - * - `GLFW_KEY_KP_SUBTRACT` - * - `GLFW_KEY_KP_ADD` - * - `GLFW_KEY_KP_EQUAL` - * - * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`. - * @param[in] scancode The scancode of the key to query. - * @return The localized name of the key, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned string is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the next call to @ref - * glfwGetKeyName, or until the library is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_key_name - * - * @since Added in version 3.2. - * - * @ingroup input - */ -GLFWAPI const char* glfwGetKeyName(int key, int scancode); - -/*! @brief Returns the last reported state of a keyboard key for the specified - * window. - * - * This function returns the last state reported for the specified key to the - * specified window. The returned state is one of `GLFW_PRESS` or - * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to - * the key callback. - * - * If the `GLFW_STICKY_KEYS` input mode is enabled, this function returns - * `GLFW_PRESS` the first time you call it for a key that was pressed, even if - * that key has already been released. - * - * The key functions deal with physical keys, with [key tokens](@ref keys) - * named after their use on the standard US keyboard layout. If you want to - * input text, use the Unicode character callback instead. - * - * The [modifier key bit masks](@ref mods) are not key tokens and cannot be - * used with this function. - * - * __Do not use this function__ to implement [text input](@ref input_char). - * - * @param[in] window The desired window. - * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is - * not a valid key for this function. - * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_ENUM. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_key - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup input - */ -GLFWAPI int glfwGetKey(GLFWwindow* window, int key); - -/*! @brief Returns the last reported state of a mouse button for the specified - * window. - * - * This function returns the last state reported for the specified mouse button - * to the specified window. The returned state is one of `GLFW_PRESS` or - * `GLFW_RELEASE`. - * - * If the `GLFW_STICKY_MOUSE_BUTTONS` input mode is enabled, this function - * `GLFW_PRESS` the first time you call it for a mouse button that was pressed, - * even if that mouse button has already been released. - * - * @param[in] window The desired window. - * @param[in] button The desired [mouse button](@ref buttons). - * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_ENUM. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_mouse_button - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup input - */ -GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); - -/*! @brief Retrieves the position of the cursor relative to the client area of - * the window. - * - * This function returns the position of the cursor, in screen coordinates, - * relative to the upper-left corner of the client area of the specified - * window. - * - * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor - * position is unbounded and limited only by the minimum and maximum values of - * a `double`. - * - * The coordinate can be converted to their integer equivalents with the - * `floor` function. Casting directly to an integer type works for positive - * coordinates, but fails for negative ones. - * - * Any or all of the position arguments may be `NULL`. If an error occurs, all - * non-`NULL` position arguments will be set to zero. - * - * @param[in] window The desired window. - * @param[out] xpos Where to store the cursor x-coordinate, relative to the - * left edge of the client area, or `NULL`. - * @param[out] ypos Where to store the cursor y-coordinate, relative to the to - * top edge of the client area, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_pos - * @sa glfwSetCursorPos - * - * @since Added in version 3.0. Replaces `glfwGetMousePos`. - * - * @ingroup input - */ -GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); - -/*! @brief Sets the position of the cursor, relative to the client area of the - * window. - * - * This function sets the position, in screen coordinates, of the cursor - * relative to the upper-left corner of the client area of the specified - * window. The window must have input focus. If the window does not have - * input focus when this function is called, it fails silently. - * - * __Do not use this function__ to implement things like camera controls. GLFW - * already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the - * cursor, transparently re-centers it and provides unconstrained cursor - * motion. See @ref glfwSetInputMode for more information. - * - * If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is - * unconstrained and limited only by the minimum and maximum values of - * a `double`. - * - * @param[in] window The desired window. - * @param[in] xpos The desired x-coordinate, relative to the left edge of the - * client area. - * @param[in] ypos The desired y-coordinate, relative to the top edge of the - * client area. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_pos - * @sa glfwGetCursorPos - * - * @since Added in version 3.0. Replaces `glfwSetMousePos`. - * - * @ingroup input - */ -GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); - -/*! @brief Creates a custom cursor. - * - * Creates a new custom cursor image that can be set for a window with @ref - * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. - * Any remaining cursors are destroyed by @ref glfwTerminate. - * - * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight - * bits per channel. They are arranged canonically as packed sequential rows, - * starting from the top-left corner. - * - * The cursor hotspot is specified in pixels, relative to the upper-left corner - * of the cursor image. Like all other coordinate systems in GLFW, the X-axis - * points to the right and the Y-axis points down. - * - * @param[in] image The desired cursor image. - * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot. - * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. - * @return The handle of the created cursor, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The specified image data is copied before this function - * returns. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_object - * @sa glfwDestroyCursor - * @sa glfwCreateStandardCursor - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); - -/*! @brief Creates a cursor with a standard shape. - * - * Returns a cursor with a [standard shape](@ref shapes), that can be set for - * a window with @ref glfwSetCursor. - * - * @param[in] shape One of the [standard shapes](@ref shapes). - * @return A new cursor ready to use or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_object - * @sa glfwCreateCursor - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); - -/*! @brief Destroys a cursor. - * - * This function destroys a cursor previously created with @ref - * glfwCreateCursor. Any remaining cursors will be destroyed by @ref - * glfwTerminate. - * - * @param[in] cursor The cursor object to destroy. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_object - * @sa glfwCreateCursor - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); - -/*! @brief Sets the cursor for the window. - * - * This function sets the cursor image to be used when the cursor is over the - * client area of the specified window. The set cursor will only be visible - * when the [cursor mode](@ref cursor_mode) of the window is - * `GLFW_CURSOR_NORMAL`. - * - * On some platforms, the set cursor may not be visible unless the window also - * has input focus. - * - * @param[in] window The window to set the cursor for. - * @param[in] cursor The cursor to set, or `NULL` to switch back to the default - * arrow cursor. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_object - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); - -/*! @brief Sets the key callback. - * - * This function sets the key callback of the specified window, which is called - * when a key is pressed, repeated or released. - * - * The key functions deal with physical keys, with layout independent - * [key tokens](@ref keys) named after their values in the standard US keyboard - * layout. If you want to input text, use the - * [character callback](@ref glfwSetCharCallback) instead. - * - * When a window loses input focus, it will generate synthetic key release - * events for all pressed keys. You can tell these events from user-generated - * events by the fact that the synthetic ones are generated after the focus - * loss event has been processed, i.e. after the - * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. - * - * The scancode of a key is specific to that platform or sometimes even to that - * machine. Scancodes are intended to allow users to bind keys that don't have - * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their - * state is not saved and so it cannot be queried with @ref glfwGetKey. - * - * Sometimes GLFW needs to generate synthetic key events, in which case the - * scancode may be zero. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new key callback, or `NULL` to remove the currently - * set callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_key - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup input - */ -GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); - -/*! @brief Sets the Unicode character callback. - * - * This function sets the character callback of the specified window, which is - * called when a Unicode character is input. - * - * The character callback is intended for Unicode text input. As it deals with - * characters, it is keyboard layout dependent, whereas the - * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1 - * to physical keys, as a key may produce zero, one or more characters. If you - * want to know whether a specific physical key was pressed or released, see - * the key callback instead. - * - * The character callback behaves as system text input normally does and will - * not be called if modifier keys are held down that would prevent normal text - * input on that platform, for example a Super (Command) key on OS X or Alt key - * on Windows. There is a - * [character with modifiers callback](@ref glfwSetCharModsCallback) that - * receives these events. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_char - * - * @since Added in version 2.4. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup input - */ -GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); - -/*! @brief Sets the Unicode character with modifiers callback. - * - * This function sets the character with modifiers callback of the specified - * window, which is called when a Unicode character is input regardless of what - * modifier keys are used. - * - * The character with modifiers callback is intended for implementing custom - * Unicode character input. For regular Unicode text input, see the - * [character callback](@ref glfwSetCharCallback). Like the character - * callback, the character with modifiers callback deals with characters and is - * keyboard layout dependent. Characters do not map 1:1 to physical keys, as - * a key may produce zero, one or more characters. If you want to know whether - * a specific physical key was pressed or released, see the - * [key callback](@ref glfwSetKeyCallback) instead. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_char - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun); - -/*! @brief Sets the mouse button callback. - * - * This function sets the mouse button callback of the specified window, which - * is called when a mouse button is pressed or released. - * - * When a window loses input focus, it will generate synthetic mouse button - * release events for all pressed mouse buttons. You can tell these events - * from user-generated events by the fact that the synthetic ones are generated - * after the focus loss event has been processed, i.e. after the - * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_mouse_button - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup input - */ -GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun cbfun); - -/*! @brief Sets the cursor position callback. - * - * This function sets the cursor position callback of the specified window, - * which is called when the cursor is moved. The callback is provided with the - * position, in screen coordinates, relative to the upper-left corner of the - * client area of the window. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_pos - * - * @since Added in version 3.0. Replaces `glfwSetMousePosCallback`. - * - * @ingroup input - */ -GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun cbfun); - -/*! @brief Sets the cursor enter/exit callback. - * - * This function sets the cursor boundary crossing callback of the specified - * window, which is called when the cursor enters or leaves the client area of - * the window. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_enter - * - * @since Added in version 3.0. - * - * @ingroup input - */ -GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun cbfun); - -/*! @brief Sets the scroll callback. - * - * This function sets the scroll callback of the specified window, which is - * called when a scrolling device is used, such as a mouse wheel or scrolling - * area of a touchpad. - * - * The scroll callback receives all scrolling input, like that from a mouse - * wheel or a touchpad scrolling area. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new scroll callback, or `NULL` to remove the currently - * set callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref scrolling - * - * @since Added in version 3.0. Replaces `glfwSetMouseWheelCallback`. - * - * @ingroup input - */ -GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun); - -/*! @brief Sets the file drop callback. - * - * This function sets the file drop callback of the specified window, which is - * called when one or more dragged files are dropped on the window. - * - * Because the path array and its strings may have been generated specifically - * for that event, they are not guaranteed to be valid after the callback has - * returned. If you wish to use them after the callback returns, you need to - * make a deep copy. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new file drop callback, or `NULL` to remove the - * currently set callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref path_drop - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); - -/*! @brief Returns whether the specified joystick is present. - * - * This function returns whether the specified joystick is present. - * - * @param[in] joy The [joystick](@ref joysticks) to query. - * @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref joystick - * - * @since Added in version 3.0. Replaces `glfwGetJoystickParam`. - * - * @ingroup input - */ -GLFWAPI int glfwJoystickPresent(int joy); - -/*! @brief Returns the values of all axes of the specified joystick. - * - * This function returns the values of all axes of the specified joystick. - * Each element in the array is a value between -1.0 and 1.0. - * - * Querying a joystick slot with no device present is not an error, but will - * cause this function to return `NULL`. Call @ref glfwJoystickPresent to - * check device presence. - * - * @param[in] joy The [joystick](@ref joysticks) to query. - * @param[out] count Where to store the number of axis values in the returned - * array. This is set to zero if an error occurred. - * @return An array of axis values, or `NULL` if the joystick is not present. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified joystick is - * disconnected, this function is called again for that joystick or the library - * is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref joystick_axis - * - * @since Added in version 3.0. Replaces `glfwGetJoystickPos`. - * - * @ingroup input - */ -GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count); - -/*! @brief Returns the state of all buttons of the specified joystick. - * - * This function returns the state of all buttons of the specified joystick. - * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. - * - * Querying a joystick slot with no device present is not an error, but will - * cause this function to return `NULL`. Call @ref glfwJoystickPresent to - * check device presence. - * - * @param[in] joy The [joystick](@ref joysticks) to query. - * @param[out] count Where to store the number of button states in the returned - * array. This is set to zero if an error occurred. - * @return An array of button states, or `NULL` if the joystick is not present. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified joystick is - * disconnected, this function is called again for that joystick or the library - * is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref joystick_button - * - * @since Added in version 2.2. - * @glfw3 Changed to return a dynamic array. - * - * @ingroup input - */ -GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count); - -/*! @brief Returns the name of the specified joystick. - * - * This function returns the name, encoded as UTF-8, of the specified joystick. - * The returned string is allocated and freed by GLFW. You should not free it - * yourself. - * - * Querying a joystick slot with no device present is not an error, but will - * cause this function to return `NULL`. Call @ref glfwJoystickPresent to - * check device presence. - * - * @param[in] joy The [joystick](@ref joysticks) to query. - * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick - * is not present. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned string is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified joystick is - * disconnected, this function is called again for that joystick or the library - * is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref joystick_name - * - * @since Added in version 3.0. - * - * @ingroup input - */ -GLFWAPI const char* glfwGetJoystickName(int joy); - -/*! @brief Sets the joystick configuration callback. - * - * This function sets the joystick configuration callback, or removes the - * currently set callback. This is called when a joystick is connected to or - * disconnected from the system. - * - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref joystick_event - * - * @since Added in version 3.2. - * - * @ingroup input - */ -GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun); - -/*! @brief Sets the clipboard to the specified string. - * - * This function sets the system clipboard to the specified, UTF-8 encoded - * string. - * - * @param[in] window The window that will own the clipboard contents. - * @param[in] string A UTF-8 encoded string. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The specified string is copied before this function - * returns. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref clipboard - * @sa glfwGetClipboardString - * - * @since Added in version 3.0. - * - * @ingroup input - */ -GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); - -/*! @brief Returns the contents of the clipboard as a string. - * - * This function returns the contents of the system clipboard, if it contains - * or is convertible to a UTF-8 encoded string. If the clipboard is empty or - * if its contents cannot be converted, `NULL` is returned and a @ref - * GLFW_FORMAT_UNAVAILABLE error is generated. - * - * @param[in] window The window that will request the clipboard contents. - * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` - * if an [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned string is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the next call to @ref - * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library - * is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref clipboard - * @sa glfwSetClipboardString - * - * @since Added in version 3.0. - * - * @ingroup input - */ -GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); - -/*! @brief Returns the value of the GLFW timer. - * - * This function returns the value of the GLFW timer. Unless the timer has - * been set using @ref glfwSetTime, the timer measures time elapsed since GLFW - * was initialized. - * - * The resolution of the timer is system dependent, but is usually on the order - * of a few micro- or nanoseconds. It uses the highest-resolution monotonic - * time source on each supported platform. - * - * @return The current value, in seconds, or zero if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. Reading and - * writing of the internal timer offset is not atomic, so it needs to be - * externally synchronized with calls to @ref glfwSetTime. - * - * @sa @ref time - * - * @since Added in version 1.0. - * - * @ingroup input - */ -GLFWAPI double glfwGetTime(void); - -/*! @brief Sets the GLFW timer. - * - * This function sets the value of the GLFW timer. It then continues to count - * up from that value. The value must be a positive finite number less than - * or equal to 18446744073.0, which is approximately 584.5 years. - * - * @param[in] time The new value, in seconds. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_VALUE. - * - * @remark The upper limit of the timer is calculated as - * floor((264 - 1) / 109) and is due to implementations - * storing nanoseconds in 64 bits. The limit may be increased in the future. - * - * @thread_safety This function may be called from any thread. Reading and - * writing of the internal timer offset is not atomic, so it needs to be - * externally synchronized with calls to @ref glfwGetTime. - * - * @sa @ref time - * - * @since Added in version 2.2. - * - * @ingroup input - */ -GLFWAPI void glfwSetTime(double time); - -/*! @brief Returns the current value of the raw timer. - * - * This function returns the current value of the raw timer, measured in - * 1 / frequency seconds. To get the frequency, call @ref - * glfwGetTimerFrequency. - * - * @return The value of the timer, or zero if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref time - * @sa glfwGetTimerFrequency - * - * @since Added in version 3.2. - * - * @ingroup input - */ -GLFWAPI uint64_t glfwGetTimerValue(void); - -/*! @brief Returns the frequency, in Hz, of the raw timer. - * - * This function returns the frequency, in Hz, of the raw timer. - * - * @return The frequency of the timer, in Hz, or zero if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref time - * @sa glfwGetTimerValue - * - * @since Added in version 3.2. - * - * @ingroup input - */ -GLFWAPI uint64_t glfwGetTimerFrequency(void); - -/*! @brief Makes the context of the specified window current for the calling - * thread. - * - * This function makes the OpenGL or OpenGL ES context of the specified window - * current on the calling thread. A context can only be made current on - * a single thread at a time and each thread can have only a single current - * context at a time. - * - * By default, making a context non-current implicitly forces a pipeline flush. - * On machines that support `GL_KHR_context_flush_control`, you can control - * whether a context performs this flush by setting the - * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint. - * - * The specified window must have an OpenGL or OpenGL ES context. Specifying - * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT - * error. - * - * @param[in] window The window whose context to make current, or `NULL` to - * detach the current context. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref context_current - * @sa glfwGetCurrentContext - * - * @since Added in version 3.0. - * - * @ingroup context - */ -GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); - -/*! @brief Returns the window whose context is current on the calling thread. - * - * This function returns the window whose OpenGL or OpenGL ES context is - * current on the calling thread. - * - * @return The window whose context is current, or `NULL` if no window's - * context is current. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref context_current - * @sa glfwMakeContextCurrent - * - * @since Added in version 3.0. - * - * @ingroup context - */ -GLFWAPI GLFWwindow* glfwGetCurrentContext(void); - -/*! @brief Swaps the front and back buffers of the specified window. - * - * This function swaps the front and back buffers of the specified window when - * rendering with OpenGL or OpenGL ES. If the swap interval is greater than - * zero, the GPU driver waits the specified number of screen updates before - * swapping the buffers. - * - * The specified window must have an OpenGL or OpenGL ES context. Specifying - * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT - * error. - * - * This function does not apply to Vulkan. If you are rendering with Vulkan, - * see `vkQueuePresentKHR` instead. - * - * @param[in] window The window whose buffers to swap. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. - * - * @remark __EGL:__ The context of the specified window must be current on the - * calling thread. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref buffer_swap - * @sa glfwSwapInterval - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwSwapBuffers(GLFWwindow* window); - -/*! @brief Sets the swap interval for the current context. - * - * This function sets the swap interval for the current OpenGL or OpenGL ES - * context, i.e. the number of screen updates to wait from the time @ref - * glfwSwapBuffers was called before swapping the buffers and returning. This - * is sometimes called _vertical synchronization_, _vertical retrace - * synchronization_ or just _vsync_. - * - * Contexts that support either of the `WGL_EXT_swap_control_tear` and - * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, - * which allow the driver to swap even if a frame arrives a little bit late. - * You can check for the presence of these extensions using @ref - * glfwExtensionSupported. For more information about swap tearing, see the - * extension specifications. - * - * A context must be current on the calling thread. Calling this function - * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. - * - * This function does not apply to Vulkan. If you are rendering with Vulkan, - * see the present mode of your swapchain instead. - * - * @param[in] interval The minimum number of screen updates to wait for - * until the buffers are swapped by @ref glfwSwapBuffers. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. - * - * @remark This function is not called during context creation, leaving the - * swap interval set to whatever is the default on that platform. This is done - * because some swap interval extensions used by GLFW do not allow the swap - * interval to be reset to zero once it has been set to a non-zero value. - * - * @remark Some GPU drivers do not honor the requested swap interval, either - * because of a user setting that overrides the application's request or due to - * bugs in the driver. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref buffer_swap - * @sa glfwSwapBuffers - * - * @since Added in version 1.0. - * - * @ingroup context - */ -GLFWAPI void glfwSwapInterval(int interval); - -/*! @brief Returns whether the specified extension is available. - * - * This function returns whether the specified - * [API extension](@ref context_glext) is supported by the current OpenGL or - * OpenGL ES context. It searches both for client API extension and context - * creation API extensions. - * - * A context must be current on the calling thread. Calling this function - * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. - * - * As this functions retrieves and searches one or more extension strings each - * call, it is recommended that you cache its results if it is going to be used - * frequently. The extension strings will not change during the lifetime of - * a context, so there is no danger in doing this. - * - * This function does not apply to Vulkan. If you are using Vulkan, see @ref - * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties` - * and `vkEnumerateDeviceExtensionProperties` instead. - * - * @param[in] extension The ASCII encoded name of the extension. - * @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE` - * otherwise. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref context_glext - * @sa glfwGetProcAddress - * - * @since Added in version 1.0. - * - * @ingroup context - */ -GLFWAPI int glfwExtensionSupported(const char* extension); - -/*! @brief Returns the address of the specified function for the current - * context. - * - * This function returns the address of the specified OpenGL or OpenGL ES - * [core or extension function](@ref context_glext), if it is supported - * by the current context. - * - * A context must be current on the calling thread. Calling this function - * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. - * - * This function does not apply to Vulkan. If you are rendering with Vulkan, - * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and - * `vkGetDeviceProcAddr` instead. - * - * @param[in] procname The ASCII encoded name of the function. - * @return The address of the function, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. - * - * @remark The address of a given function is not guaranteed to be the same - * between contexts. - * - * @remark This function may return a non-`NULL` address despite the - * associated version or extension not being available. Always check the - * context version or extension string first. - * - * @pointer_lifetime The returned function pointer is valid until the context - * is destroyed or the library is terminated. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref context_glext - * @sa glfwExtensionSupported - * - * @since Added in version 1.0. - * - * @ingroup context - */ -GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); - -/*! @brief Returns whether the Vulkan loader has been found. - * - * This function returns whether the Vulkan loader has been found. This check - * is performed by @ref glfwInit. - * - * The availability of a Vulkan loader does not by itself guarantee that window - * surface creation or even device creation is possible. Call @ref - * glfwGetRequiredInstanceExtensions to check whether the extensions necessary - * for Vulkan surface creation are available and @ref - * glfwGetPhysicalDevicePresentationSupport to check whether a queue family of - * a physical device supports image presentation. - * - * @return `GLFW_TRUE` if Vulkan is available, or `GLFW_FALSE` otherwise. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref vulkan_support - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -GLFWAPI int glfwVulkanSupported(void); - -/*! @brief Returns the Vulkan instance extensions required by GLFW. - * - * This function returns an array of names of Vulkan instance extensions required - * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the - * list will always contains `VK_KHR_surface`, so if you don't require any - * additional extensions you can pass this list directly to the - * `VkInstanceCreateInfo` struct. - * - * If Vulkan is not available on the machine, this function returns `NULL` and - * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported - * to check whether Vulkan is available. - * - * If Vulkan is available but no set of extensions allowing window surface - * creation was found, this function returns `NULL`. You may still use Vulkan - * for off-screen rendering and compute work. - * - * @param[out] count Where to store the number of extensions in the returned - * array. This is set to zero if an error occurred. - * @return An array of ASCII encoded extension names, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_API_UNAVAILABLE. - * - * @remarks Additional extensions may be required by future versions of GLFW. - * You should check if any extensions you wish to enable are already in the - * returned array, as it is an error to specify an extension more than once in - * the `VkInstanceCreateInfo` struct. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is guaranteed to be valid only until the - * library is terminated. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref vulkan_ext - * @sa glfwCreateWindowSurface - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count); - -#if defined(VK_VERSION_1_0) - -/*! @brief Returns the address of the specified Vulkan instance function. - * - * This function returns the address of the specified Vulkan core or extension - * function for the specified instance. If instance is set to `NULL` it can - * return any function exported from the Vulkan loader, including at least the - * following functions: - * - * - `vkEnumerateInstanceExtensionProperties` - * - `vkEnumerateInstanceLayerProperties` - * - `vkCreateInstance` - * - `vkGetInstanceProcAddr` - * - * If Vulkan is not available on the machine, this function returns `NULL` and - * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported - * to check whether Vulkan is available. - * - * This function is equivalent to calling `vkGetInstanceProcAddr` with - * a platform-specific query of the Vulkan loader as a fallback. - * - * @param[in] instance The Vulkan instance to query, or `NULL` to retrieve - * functions related to instance creation. - * @param[in] procname The ASCII encoded name of the function. - * @return The address of the function, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_API_UNAVAILABLE. - * - * @pointer_lifetime The returned function pointer is valid until the library - * is terminated. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref vulkan_proc - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname); - -/*! @brief Returns whether the specified queue family can present images. - * - * This function returns whether the specified queue family of the specified - * physical device supports presentation to the platform GLFW was built for. - * - * If Vulkan or the required window surface creation instance extensions are - * not available on the machine, or if the specified instance was not created - * with the required extensions, this function returns `GLFW_FALSE` and - * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported - * to check whether Vulkan is available and @ref - * glfwGetRequiredInstanceExtensions to check what instance extensions are - * required. - * - * @param[in] instance The instance that the physical device belongs to. - * @param[in] device The physical device that the queue family belongs to. - * @param[in] queuefamily The index of the queue family to query. - * @return `GLFW_TRUE` if the queue family supports presentation, or - * `GLFW_FALSE` otherwise. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. - * - * @thread_safety This function may be called from any thread. For - * synchronization details of Vulkan objects, see the Vulkan specification. - * - * @sa @ref vulkan_present - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); - -/*! @brief Creates a Vulkan surface for the specified window. - * - * This function creates a Vulkan surface for the specified window. - * - * If the Vulkan loader was not found at initialization, this function returns - * `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref GLFW_API_UNAVAILABLE - * error. Call @ref glfwVulkanSupported to check whether the Vulkan loader was - * found. - * - * If the required window surface creation instance extensions are not - * available or if the specified instance was not created with these extensions - * enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and - * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref - * glfwGetRequiredInstanceExtensions to check what instance extensions are - * required. - * - * The window surface must be destroyed before the specified Vulkan instance. - * It is the responsibility of the caller to destroy the window surface. GLFW - * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the - * surface. - * - * @param[in] instance The Vulkan instance to create the surface in. - * @param[in] window The window to create the surface for. - * @param[in] allocator The allocator to use, or `NULL` to use the default - * allocator. - * @param[out] surface Where to store the handle of the surface. This is set - * to `VK_NULL_HANDLE` if an error occurred. - * @return `VK_SUCCESS` if successful, or a Vulkan error code if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. - * - * @remarks If an error occurs before the creation call is made, GLFW returns - * the Vulkan error code most appropriate for the error. Appropriate use of - * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should - * eliminate almost all occurrences of these errors. - * - * @thread_safety This function may be called from any thread. For - * synchronization details of Vulkan objects, see the Vulkan specification. - * - * @sa @ref vulkan_surface - * @sa glfwGetRequiredInstanceExtensions - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); - -#endif /*VK_VERSION_1_0*/ - - -/************************************************************************* - * Global definition cleanup - *************************************************************************/ - -/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ - -#ifdef GLFW_WINGDIAPI_DEFINED - #undef WINGDIAPI - #undef GLFW_WINGDIAPI_DEFINED -#endif - -#ifdef GLFW_CALLBACK_DEFINED - #undef CALLBACK - #undef GLFW_CALLBACK_DEFINED -#endif - -/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ - - -#ifdef __cplusplus -} -#endif - -#endif /* _glfw3_h_ */ - diff --git a/src/external/include/GLFW/glfw3native.h b/src/external/include/GLFW/glfw3native.h deleted file mode 100644 index 30e1a570..00000000 --- a/src/external/include/GLFW/glfw3native.h +++ /dev/null @@ -1,456 +0,0 @@ -/************************************************************************* - * GLFW 3.2 - www.glfw.org - * A library for OpenGL, window and input - *------------------------------------------------------------------------ - * Copyright (c) 2002-2006 Marcus Geelnard - * Copyright (c) 2006-2016 Camilla Berglund - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would - * be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - * - *************************************************************************/ - -#ifndef _glfw3_native_h_ -#define _glfw3_native_h_ - -#ifdef __cplusplus -extern "C" { -#endif - - -/************************************************************************* - * Doxygen documentation - *************************************************************************/ - -/*! @file glfw3native.h - * @brief The header of the native access functions. - * - * This is the header file of the native access functions. See @ref native for - * more information. - */ -/*! @defgroup native Native access - * - * **By using the native access functions you assert that you know what you're - * doing and how to fix problems caused by using them. If you don't, you - * shouldn't be using them.** - * - * Before the inclusion of @ref glfw3native.h, you may define exactly one - * window system API macro and zero or more context creation API macros. - * - * The chosen backends must match those the library was compiled for. Failure - * to do this will cause a link-time error. - * - * The available window API macros are: - * * `GLFW_EXPOSE_NATIVE_WIN32` - * * `GLFW_EXPOSE_NATIVE_COCOA` - * * `GLFW_EXPOSE_NATIVE_X11` - * * `GLFW_EXPOSE_NATIVE_WAYLAND` - * * `GLFW_EXPOSE_NATIVE_MIR` - * - * The available context API macros are: - * * `GLFW_EXPOSE_NATIVE_WGL` - * * `GLFW_EXPOSE_NATIVE_NSGL` - * * `GLFW_EXPOSE_NATIVE_GLX` - * * `GLFW_EXPOSE_NATIVE_EGL` - * - * These macros select which of the native access functions that are declared - * and which platform-specific headers to include. It is then up your (by - * definition platform-specific) code to handle which of these should be - * defined. - */ - - -/************************************************************************* - * System headers and types - *************************************************************************/ - -#if defined(GLFW_EXPOSE_NATIVE_WIN32) - // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for - // example to allow applications to correctly declare a GL_ARB_debug_output - // callback) but windows.h assumes no one will define APIENTRY before it does - #undef APIENTRY - #include -#elif defined(GLFW_EXPOSE_NATIVE_COCOA) - #include - #if defined(__OBJC__) - #import - #else - typedef void* id; - #endif -#elif defined(GLFW_EXPOSE_NATIVE_X11) - #include - #include -#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) - #include -#elif defined(GLFW_EXPOSE_NATIVE_MIR) - #include -#endif - -#if defined(GLFW_EXPOSE_NATIVE_WGL) - /* WGL is declared by windows.h */ -#endif -#if defined(GLFW_EXPOSE_NATIVE_NSGL) - /* NSGL is declared by Cocoa.h */ -#endif -#if defined(GLFW_EXPOSE_NATIVE_GLX) - #include -#endif -#if defined(GLFW_EXPOSE_NATIVE_EGL) - #include -#endif - - -/************************************************************************* - * Functions - *************************************************************************/ - -#if defined(GLFW_EXPOSE_NATIVE_WIN32) -/*! @brief Returns the adapter device name of the specified monitor. - * - * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) - * of the specified monitor, or `NULL` if an [error](@ref error_handling) - * occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.1. - * - * @ingroup native - */ -GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); - -/*! @brief Returns the display device name of the specified monitor. - * - * @return The UTF-8 encoded display device name (for example - * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.1. - * - * @ingroup native - */ -GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); - -/*! @brief Returns the `HWND` of the specified window. - * - * @return The `HWND` of the specified window, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_WGL) -/*! @brief Returns the `HGLRC` of the specified window. - * - * @return The `HGLRC` of the specified window, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_COCOA) -/*! @brief Returns the `CGDirectDisplayID` of the specified monitor. - * - * @return The `CGDirectDisplayID` of the specified monitor, or - * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.1. - * - * @ingroup native - */ -GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); - -/*! @brief Returns the `NSWindow` of the specified window. - * - * @return The `NSWindow` of the specified window, or `nil` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_NSGL) -/*! @brief Returns the `NSOpenGLContext` of the specified window. - * - * @return The `NSOpenGLContext` of the specified window, or `nil` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_X11) -/*! @brief Returns the `Display` used by GLFW. - * - * @return The `Display` used by GLFW, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI Display* glfwGetX11Display(void); - -/*! @brief Returns the `RRCrtc` of the specified monitor. - * - * @return The `RRCrtc` of the specified monitor, or `None` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.1. - * - * @ingroup native - */ -GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); - -/*! @brief Returns the `RROutput` of the specified monitor. - * - * @return The `RROutput` of the specified monitor, or `None` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.1. - * - * @ingroup native - */ -GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); - -/*! @brief Returns the `Window` of the specified window. - * - * @return The `Window` of the specified window, or `None` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI Window glfwGetX11Window(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_GLX) -/*! @brief Returns the `GLXContext` of the specified window. - * - * @return The `GLXContext` of the specified window, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); - -/*! @brief Returns the `GLXWindow` of the specified window. - * - * @return The `GLXWindow` of the specified window, or `None` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_WAYLAND) -/*! @brief Returns the `struct wl_display*` used by GLFW. - * - * @return The `struct wl_display*` used by GLFW, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI struct wl_display* glfwGetWaylandDisplay(void); - -/*! @brief Returns the `struct wl_output*` of the specified monitor. - * - * @return The `struct wl_output*` of the specified monitor, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); - -/*! @brief Returns the main `struct wl_surface*` of the specified window. - * - * @return The main `struct wl_surface*` of the specified window, or `NULL` if - * an [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_MIR) -/*! @brief Returns the `MirConnection*` used by GLFW. - * - * @return The `MirConnection*` used by GLFW, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI MirConnection* glfwGetMirDisplay(void); - -/*! @brief Returns the Mir output ID of the specified monitor. - * - * @return The Mir output ID of the specified monitor, or zero if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); - -/*! @brief Returns the `MirSurface*` of the specified window. - * - * @return The `MirSurface*` of the specified window, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_EGL) -/*! @brief Returns the `EGLDisplay` used by GLFW. - * - * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI EGLDisplay glfwGetEGLDisplay(void); - -/*! @brief Returns the `EGLContext` of the specified window. - * - * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); - -/*! @brief Returns the `EGLSurface` of the specified window. - * - * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* _glfw3_native_h_ */ - diff --git a/src/external/include/GLFW_COPYING.txt b/src/external/include/GLFW_COPYING.txt deleted file mode 100644 index ad16462a..00000000 --- a/src/external/include/GLFW_COPYING.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2002-2006 Marcus Geelnard -Copyright (c) 2006-2016 Camilla Berglund - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would - be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source - distribution. - From 60d7215b2af12614e0dd99b30ac4330168100fe8 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 18 Nov 2017 08:42:14 +1000 Subject: [PATCH 021/139] mini_al: Unify the buffer system for Sounds and AudioStreams. --- src/audio.c | 836 +++++++++++++++++++++++---------------------------- src/raylib.h | 4 +- 2 files changed, 371 insertions(+), 469 deletions(-) diff --git a/src/audio.c b/src/audio.c index d20380d0..83538f06 100644 --- a/src/audio.c +++ b/src/audio.c @@ -213,126 +213,75 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo #define DEVICE_CHANNELS 2 #define DEVICE_SAMPLE_RATE 44100 -typedef struct SoundData SoundData; -struct SoundData -{ - mal_dsp dsp; // Necessary for pitch shift. This is an optimized passthrough when the pitch == 1. - float volume; - float pitch; - bool playing; - bool paused; - bool looping; - unsigned int frameCursorPos; // Keeps track of the next frame to read when mixing - unsigned int bufferSizeInFrames; - SoundData* next; - SoundData* prev; - unsigned char data[1]; // Raw audio data. -}; +typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioBufferUsage; -// AudioStreamData -typedef struct AudioStreamData AudioStreamData; -struct AudioStreamData +typedef struct AudioBuffer AudioBuffer; +struct AudioBuffer { - mal_dsp dsp; // AudioStream data needs to flow through a persistent conversion pipeline. Not doing this will result in glitches between buffer updates. + mal_dsp dsp; // For format conversion. float volume; float pitch; bool playing; bool paused; + bool looping; // Always true for AudioStreams. + AudioBufferUsage usage; // Slightly different logic is used when feeding data to the playback device depending on whether or not data is streamed. bool isSubBufferProcessed[2]; unsigned int frameCursorPos; unsigned int bufferSizeInFrames; - AudioStreamData* next; - AudioStreamData* prev; + AudioBuffer* next; + AudioBuffer* prev; unsigned char buffer[1]; }; +void StopAudioBuffer(AudioBuffer* audioBuffer); + + static mal_context context; static mal_device device; static mal_bool32 isAudioInitialized = MAL_FALSE; static float masterVolume = 1; static mal_mutex soundLock; -static SoundData* firstSound; // Sounds are tracked in a linked list. -static SoundData* lastSound; -static AudioStreamData* firstAudioStream; -static AudioStreamData* lastAudioStream; +static AudioBuffer* firstAudioBuffer = NULL; // Audio buffers are tracked in a linked list. +static AudioBuffer* lastAudioBuffer = NULL; -static void AppendSound(SoundData* internalSound) +static void TrackAudioBuffer(AudioBuffer* audioBuffer) { mal_mutex_lock(&soundLock); { - if (firstSound == NULL) { - firstSound = internalSound; + if (firstAudioBuffer == NULL) { + firstAudioBuffer = audioBuffer; } else { - lastSound->next = internalSound; - internalSound->prev = lastSound; + lastAudioBuffer->next = audioBuffer; + audioBuffer->prev = lastAudioBuffer; } - lastSound = internalSound; + lastAudioBuffer = audioBuffer; } mal_mutex_unlock(&soundLock); } -static void RemoveSound(SoundData* internalSound) +static void UntrackAudioBuffer(AudioBuffer* audioBuffer) { mal_mutex_lock(&soundLock); { - if (internalSound->prev == NULL) { - firstSound = internalSound->next; + if (audioBuffer->prev == NULL) { + firstAudioBuffer = audioBuffer->next; } else { - internalSound->prev->next = internalSound->next; + audioBuffer->prev->next = audioBuffer->next; } - if (internalSound->next == NULL) { - lastSound = internalSound->prev; + if (audioBuffer->next == NULL) { + lastAudioBuffer = audioBuffer->prev; } else { - internalSound->next->prev = internalSound->prev; + audioBuffer->next->prev = audioBuffer->prev; } - internalSound->prev = NULL; - internalSound->next = NULL; + audioBuffer->prev = NULL; + audioBuffer->next = NULL; } mal_mutex_unlock(&soundLock); } -static void AppendAudioStream(AudioStreamData* internalAudioStream) -{ - mal_mutex_lock(&soundLock); - { - if (firstAudioStream == NULL) { - firstAudioStream = internalAudioStream; - } else { - lastAudioStream->next = internalAudioStream; - internalAudioStream->prev = lastAudioStream; - } - - lastAudioStream = internalAudioStream; - } - mal_mutex_unlock(&soundLock); -} - -static void RemoveAudioStream(AudioStreamData* internalAudioStream) -{ - mal_mutex_lock(&soundLock); - { - if (internalAudioStream->prev == NULL) { - firstAudioStream = internalAudioStream->next; - } else { - internalAudioStream->prev->next = internalAudioStream->next; - } - - if (internalAudioStream->next == NULL) { - lastAudioStream = internalAudioStream->prev; - } else { - internalAudioStream->next->prev = internalAudioStream->prev; - } - - internalAudioStream->prev = NULL; - internalAudioStream->next = NULL; - } - mal_mutex_unlock(&soundLock); -} - - static void OnLog_MAL(mal_context* pContext, mal_device* pDevice, const char* message) { (void)pContext; @@ -347,8 +296,8 @@ static void MixFrames(float* framesOut, const float* framesIn, mal_uint32 frameC { for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel) { - float* frameOut = framesOut + (iFrame * device.channels); - float* frameIn = framesIn + (iFrame * device.channels); + float* frameOut = framesOut + (iFrame * device.channels); + const float* frameIn = framesIn + (iFrame * device.channels); frameOut[iChannel] += frameIn[iChannel] * masterVolume * localVolume; } @@ -367,27 +316,24 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC // want to consider how you might want to avoid this. mal_mutex_lock(&soundLock); { - float* framesOutF = (float*)pFramesOut; // <-- Just for convenience. - - // Sounds. - for (SoundData* internalSound = firstSound; internalSound != NULL; internalSound = internalSound->next) + for (AudioBuffer* audioBuffer = firstAudioBuffer; audioBuffer != NULL; audioBuffer = audioBuffer->next) { // Ignore stopped or paused sounds. - if (!internalSound->playing || internalSound->paused) { + if (!audioBuffer->playing || audioBuffer->paused) { continue; } mal_uint32 framesRead = 0; for (;;) { if (framesRead > frameCount) { - TraceLog(LOG_DEBUG, "Mixed too many frames from sound"); + TraceLog(LOG_DEBUG, "Mixed too many frames from audio buffer"); break; } if (framesRead == frameCount) { break; } - // Just read as much data we can from the stream. + // Just read as much data as we can from the stream. mal_uint32 framesToRead = (frameCount - framesRead); while (framesToRead > 0) { float tempBuffer[1024]; // 512 frames for stereo. @@ -399,13 +345,13 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC // If we're not looping, we need to make sure we flush the internal buffers of the DSP pipeline to ensure we get the // last few samples. - mal_bool32 flushDSP = !internalSound->looping; + mal_bool32 flushDSP = !audioBuffer->looping; - mal_uint32 framesJustRead = mal_dsp_read_frames_ex(&internalSound->dsp, framesToReadRightNow, tempBuffer, flushDSP); + mal_uint32 framesJustRead = mal_dsp_read_frames_ex(&audioBuffer->dsp, framesToReadRightNow, tempBuffer, flushDSP); if (framesJustRead > 0) { - float* framesOut = framesOutF + (framesRead * device.channels); + float* framesOut = (float*)pFramesOut + (framesRead * device.channels); float* framesIn = tempBuffer; - MixFrames(framesOut, framesIn, framesJustRead, internalSound->volume); + MixFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume); framesToRead -= framesJustRead; framesRead += framesJustRead; @@ -413,13 +359,12 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC // If we weren't able to read all the frames we requested, break. if (framesJustRead < framesToReadRightNow) { - if (!internalSound->looping) { - internalSound->playing = MAL_FALSE; - internalSound->frameCursorPos = 0; + if (!audioBuffer->looping) { + StopAudioBuffer(audioBuffer); break; } else { // Should never get here, but just for safety, move the cursor position back to the start and continue the loop. - internalSound->frameCursorPos = 0; + audioBuffer->frameCursorPos = 0; continue; } } @@ -432,56 +377,6 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC } } } - - // AudioStreams. These are handled slightly differently to sounds because we do data conversion at mixing time rather than - // load time. - for (AudioStreamData* internalData = firstAudioStream; internalData != NULL; internalData = internalData->next) - { - // Ignore stopped or paused streams. - if (!internalData->playing || internalData->paused) { - continue; - } - - mal_uint32 framesRead = 0; - for (;;) { - if (framesRead > frameCount) { - TraceLog(LOG_DEBUG, "Mixed too many frames from sound"); - break; - } - if (framesRead == frameCount) { - break; - } - - // Just read as much data we can from the stream. - mal_uint32 framesToRead = (frameCount - framesRead); - while (framesToRead > 0) { - float tempBuffer[1024]; // 512 frames for stereo. - - mal_uint32 framesToReadRightNow = framesToRead; - if (framesToReadRightNow > sizeof(tempBuffer)/DEVICE_CHANNELS) { - framesToReadRightNow = sizeof(tempBuffer)/DEVICE_CHANNELS; - } - - mal_uint32 framesJustRead = mal_dsp_read_frames(&internalData->dsp, framesToReadRightNow, tempBuffer); - if (framesJustRead > 0) { - float* framesOut = framesOutF + (framesRead * device.channels); - float* framesIn = tempBuffer; - MixFrames(framesOut, framesIn, framesJustRead, internalData->volume); - - framesToRead -= framesJustRead; - framesRead += framesJustRead; - } else { - break; // Avoid an infinite loop. - } - } - - // If for some reason we weren't able to read every frame we'll need to break from the loop. Not doing this could - // theoretically put us into an infinite loop. - if (framesToRead > 0) { - break; - } - } - } } mal_mutex_unlock(&soundLock); @@ -630,6 +525,262 @@ void SetMasterVolume(float volume) #endif } + +//---------------------------------------------------------------------------------- +// Audio Buffer +//---------------------------------------------------------------------------------- +#if USE_MINI_AL +static mal_uint32 AudioBuffer_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) +{ + AudioBuffer* audioBuffer = (AudioBuffer*)pUserData; + + mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames / 2; + mal_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos / subBufferSizeInFrames; + if (currentSubBufferIndex > 1) { + TraceLog(LOG_DEBUG, "Frame cursor position moved too far forward in audio stream"); + return 0; + } + + // Another thread can update the processed state of buffers so we just take a copy here to try and avoid potential synchronization problems. + bool isSubBufferProcessed[2]; + isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0]; + isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1]; + + mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn) * audioBuffer->dsp.config.channelsIn; + + // Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0. + mal_uint32 framesRead = 0; + for (;;) + { + // We break from this loop differently depending on the buffer's usage. For static buffers, we simply fill as much data as we can. For + // streaming buffers we only fill the halves of the buffer that are processed. Unprocessed halves must keep their audio data in-tact. + if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) { + if (framesRead >= frameCount) { + break; + } + } else { + if (isSubBufferProcessed[currentSubBufferIndex]) { + break; + } + } + + mal_uint32 totalFramesRemaining = (frameCount - framesRead); + if (totalFramesRemaining == 0) { + break; + } + + mal_uint32 framesRemainingInOutputBuffer; + if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) { + framesRemainingInOutputBuffer = audioBuffer->bufferSizeInFrames - audioBuffer->frameCursorPos; + } else { + mal_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames * currentSubBufferIndex; + framesRemainingInOutputBuffer = subBufferSizeInFrames - (audioBuffer->frameCursorPos - firstFrameIndexOfThisSubBuffer); + } + + + + mal_uint32 framesToRead = totalFramesRemaining; + if (framesToRead > framesRemainingInOutputBuffer) { + framesToRead = framesRemainingInOutputBuffer; + } + + memcpy((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), audioBuffer->buffer + (audioBuffer->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes); + audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead) % audioBuffer->bufferSizeInFrames; + framesRead += framesToRead; + + // If we've read to the end of the buffer, mark it as processed. + if (framesToRead == framesRemainingInOutputBuffer) { + audioBuffer->isSubBufferProcessed[currentSubBufferIndex] = true; + isSubBufferProcessed[currentSubBufferIndex] = true; + + currentSubBufferIndex = (currentSubBufferIndex + 1) % 2; + + // We need to break from this loop if we're not looping. + if (!audioBuffer->looping) { + StopAudioBuffer(audioBuffer); + break; + } + } + } + + // Zero-fill excess. + mal_uint32 totalFramesRemaining = (frameCount - framesRead); + if (totalFramesRemaining > 0) { + memset((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes); + + // For static buffers we can fill the remaining frames with silence for safety, but we don't want + // to report those frames as "read". The reason for this is that the caller uses the return value + // to know whether or not a non-looping sound has finished playback. + if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) { + framesRead += totalFramesRemaining; + } + } + + return framesRead; +} + +// Create a new audio buffer. Initially filled with silence. +AudioBuffer* CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage) +{ + AudioBuffer* audioBuffer = (AudioBuffer*)calloc(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*mal_get_sample_size_in_bytes(format)), 1); + if (audioBuffer == NULL) + { + TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to allocate memory for audio buffer"); + return NULL; + } + + // We run audio data through a format converter. + mal_dsp_config dspConfig; + memset(&dspConfig, 0, sizeof(dspConfig)); + dspConfig.formatIn = format; + dspConfig.formatOut = DEVICE_FORMAT; + dspConfig.channelsIn = channels; + dspConfig.channelsOut = DEVICE_CHANNELS; + dspConfig.sampleRateIn = sampleRate; + dspConfig.sampleRateOut = DEVICE_SAMPLE_RATE; + mal_result resultMAL = mal_dsp_init(&dspConfig, AudioBuffer_OnDSPRead, audioBuffer, &audioBuffer->dsp); + if (resultMAL != MAL_SUCCESS) { + TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create data conversion pipeline"); + free(audioBuffer); + return NULL; + } + + audioBuffer->volume = 1; + audioBuffer->pitch = 1; + audioBuffer->playing = 0; + audioBuffer->paused = 0; + audioBuffer->looping = 0; + audioBuffer->usage = usage; + audioBuffer->bufferSizeInFrames = bufferSizeInFrames; + audioBuffer->frameCursorPos = 0; + + // Buffers should be marked as processed by default so that a call to UpdateAudioStream() immediately after initialization works correctly. + audioBuffer->isSubBufferProcessed[0] = true; + audioBuffer->isSubBufferProcessed[1] = true; + + TrackAudioBuffer(audioBuffer); + + return audioBuffer; +} + +// Delete an audio buffer. +void DeleteAudioBuffer(AudioBuffer* audioBuffer) +{ + if (audioBuffer == NULL) + { + TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); + return; + } + + UntrackAudioBuffer(audioBuffer); + free(audioBuffer); +} + +// Check if an audio buffer is playing. +bool IsAudioBufferPlaying(AudioBuffer* audioBuffer) +{ + if (audioBuffer == NULL) + { + TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); + return false; + } + + return audioBuffer->playing && !audioBuffer->paused; +} + +// Play an audio buffer. +// +// This will restart the buffer from the start. Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position +// should be maintained. +void PlayAudioBuffer(AudioBuffer* audioBuffer) +{ + if (audioBuffer == NULL) + { + TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); + return; + } + + audioBuffer->playing = true; + audioBuffer->paused = false; + audioBuffer->frameCursorPos = 0; +} + +// Stop an audio buffer. +void StopAudioBuffer(AudioBuffer* audioBuffer) +{ + if (audioBuffer == NULL) + { + TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); + return; + } + + // Don't do anything if the audio buffer is already stopped. + if (!IsAudioBufferPlaying(audioBuffer)) + { + return; + } + + audioBuffer->playing = false; + audioBuffer->paused = false; + audioBuffer->frameCursorPos = 0; + audioBuffer->isSubBufferProcessed[0] = true; + audioBuffer->isSubBufferProcessed[1] = true; +} + +// Pause an audio buffer. +void PauseAudioBuffer(AudioBuffer* audioBuffer) +{ + if (audioBuffer == NULL) + { + TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); + return; + } + + audioBuffer->paused = true; +} + +// Resume an audio buffer. +void ResumeAudioBuffer(AudioBuffer* audioBuffer) +{ + if (audioBuffer == NULL) + { + TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); + return; + } + + audioBuffer->paused = false; +} + +// Set volume for an audio buffer. +void SetAudioBufferVolume(AudioBuffer* audioBuffer, float volume) +{ + if (audioBuffer == NULL) + { + TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); + return; + } + + audioBuffer->volume = volume; +} + +// Set pitch for an audio buffer. +void SetAudioBufferPitch(AudioBuffer* audioBuffer, float pitch) +{ + if (audioBuffer == NULL) + { + TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); + return; + } + + audioBuffer->pitch = pitch; + + // Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches + // will make the sound faster; lower pitches make it slower. + mal_uint32 newOutputSampleRate = (mal_uint32)((((float)audioBuffer->dsp.config.sampleRateOut / (float)audioBuffer->dsp.config.sampleRateIn) / pitch) * audioBuffer->dsp.config.sampleRateIn); + mal_dsp_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate); +} +#endif + //---------------------------------------------------------------------------------- // Module Functions Definition - Sounds loading and playing (.WAV) //---------------------------------------------------------------------------------- @@ -696,39 +847,6 @@ Sound LoadSound(const char *fileName) return sound; } -#if USE_MINI_AL -static mal_uint32 Sound_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) -{ - SoundData* internalData = (SoundData*)pUserData; - - mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(internalData->dsp.config.formatIn)*internalData->dsp.config.channelsIn; - - // Just keep reading as much as we can. Do not zero fill excess data in the output buffer. - mal_uint32 framesRead = 0; - while (framesRead < frameCount) - { - mal_uint32 framesRemaining = internalData->bufferSizeInFrames - internalData->frameCursorPos; - mal_uint32 framesToRead = (frameCount - framesRead); - if (framesToRead > framesRemaining) { - framesToRead = framesRemaining; - } - - memcpy((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), internalData->data + (internalData->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes); - internalData->frameCursorPos += framesToRead; - framesRead += framesToRead; - - // If we've reached the end of the buffer but we're not looping, return. - if (framesToRead == framesRemaining) { - if (!internalData->looping) { - break; - } - } - } - - return framesRead; -} -#endif - // Load sound from wave data // NOTE: Wave data must be unallocated manually Sound LoadSoundFromWave(Wave wave) @@ -751,44 +869,24 @@ Sound LoadSoundFromWave(Wave wave) mal_uint32 frameCount = mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn); if (frameCount == 0) { - TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to get frame count for format conversion."); + TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to get frame count for format conversion"); } - SoundData* internalSound = (SoundData*)calloc(sizeof(*internalSound) + (frameCount*DEVICE_CHANNELS*4), 1); // <-- Make sure this is initialized to zero for safety. - if (internalSound == NULL) { - TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to allocate memory for internal buffer"); + + AudioBuffer* audioBuffer = CreateAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, frameCount, AUDIO_BUFFER_USAGE_STATIC); + if (audioBuffer == NULL) + { + TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create audio buffer"); } - frameCount = mal_convert_frames(internalSound->data, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, wave.data, formatIn, wave.channels, wave.sampleRate, frameCountIn); - if (frameCount == 0) { - TraceLog(LOG_ERROR, "LoadSoundFromWave() : Format conversion failed."); + + frameCount = mal_convert_frames(audioBuffer->buffer, audioBuffer->dsp.config.formatIn, audioBuffer->dsp.config.channelsIn, audioBuffer->dsp.config.sampleRateIn, wave.data, formatIn, wave.channels, wave.sampleRate, frameCountIn); + if (frameCount == 0) + { + TraceLog(LOG_ERROR, "LoadSoundFromWave() : Format conversion failed"); } - // We run audio data through a sample rate converter in order to support pitch shift. By default this will use an optimized passthrough - // algorithm, but when the application changes the pitch it will change to a less optimal linear SRC. - mal_dsp_config dspConfig; - memset(&dspConfig, 0, sizeof(dspConfig)); - dspConfig.formatIn = DEVICE_FORMAT; - dspConfig.formatOut = DEVICE_FORMAT; - dspConfig.channelsIn = DEVICE_CHANNELS; - dspConfig.channelsOut = DEVICE_CHANNELS; - dspConfig.sampleRateIn = DEVICE_SAMPLE_RATE; - dspConfig.sampleRateOut = DEVICE_SAMPLE_RATE; - mal_result resultMAL = mal_dsp_init(&dspConfig, Sound_OnDSPRead, internalSound, &internalSound->dsp); - if (resultMAL != MAL_SUCCESS) { - TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create data conversion pipeline"); - } - - internalSound->volume = 1; - internalSound->pitch = 1; - internalSound->playing = 0; - internalSound->paused = 0; - internalSound->looping = 0; - internalSound->bufferSizeInFrames = frameCount; - internalSound->frameCursorPos = 0; - AppendSound(internalSound); - - sound.handle = (void*)internalSound; + sound.audioBuffer = audioBuffer; #else ALenum format = 0; @@ -861,9 +959,7 @@ void UnloadWave(Wave wave) void UnloadSound(Sound sound) { #if USE_MINI_AL - SoundData* internalSound = (SoundData*)sound.handle; - RemoveSound(internalSound); - free(internalSound); + DeleteAudioBuffer((AudioBuffer*)sound.audioBuffer); #else alSourceStop(sound.source); @@ -879,19 +975,17 @@ void UnloadSound(Sound sound) void UpdateSound(Sound sound, const void *data, int samplesCount) { #if USE_MINI_AL - SoundData* internalSound = (SoundData*)sound.handle; - if (internalSound == NULL) + AudioBuffer* audioBuffer = (AudioBuffer*)sound.audioBuffer; + if (audioBuffer == NULL) { - TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound"); + TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound - no audio buffer"); return; } - internalSound->playing = false; - internalSound->paused = false; - internalSound->frameCursorPos = 0; + StopAudioBuffer(audioBuffer); // TODO: May want to lock/unlock this since this data buffer is read at mixing time. - memcpy(internalSound->data, data, samplesCount*internalSound->dsp.config.channelsIn*mal_get_sample_size_in_bytes(internalSound->dsp.config.formatIn)); + memcpy(audioBuffer->buffer, data, samplesCount*audioBuffer->dsp.config.channelsIn*mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn)); #else ALint sampleRate, sampleSize, channels; alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); @@ -921,16 +1015,7 @@ void UpdateSound(Sound sound, const void *data, int samplesCount) void PlaySound(Sound sound) { #if USE_MINI_AL - SoundData* internalSound = (SoundData*)sound.handle; - if (internalSound == NULL) - { - TraceLog(LOG_ERROR, "PlaySound() : Invalid sound"); - return; - } - - internalSound->playing = 1; - internalSound->paused = 0; - internalSound->frameCursorPos = 0; + PlayAudioBuffer((AudioBuffer*)sound.audioBuffer); #else alSourcePlay(sound.source); // Play the sound #endif @@ -955,14 +1040,7 @@ void PlaySound(Sound sound) void PauseSound(Sound sound) { #if USE_MINI_AL - SoundData* internalSound = (SoundData*)sound.handle; - if (internalSound == NULL) - { - TraceLog(LOG_ERROR, "PauseSound() : Invalid sound"); - return; - } - - internalSound->paused = true; + PauseAudioBuffer((AudioBuffer*)sound.audioBuffer); #else alSourcePause(sound.source); #endif @@ -972,14 +1050,7 @@ void PauseSound(Sound sound) void ResumeSound(Sound sound) { #if USE_MINI_AL - SoundData* internalSound = (SoundData*)sound.handle; - if (internalSound == NULL) - { - TraceLog(LOG_ERROR, "ResumeSound() : Invalid sound"); - return; - } - - internalSound->paused = false; + ResumeAudioBuffer((AudioBuffer*)sound.audioBuffer); #else ALenum state; @@ -993,15 +1064,7 @@ void ResumeSound(Sound sound) void StopSound(Sound sound) { #if USE_MINI_AL - SoundData* internalSound = (SoundData*)sound.handle; - if (internalSound == NULL) - { - TraceLog(LOG_ERROR, "StopSound() : Invalid sound"); - return; - } - - internalSound->playing = false; - internalSound->paused = false; + StopAudioBuffer((AudioBuffer*)sound.audioBuffer); #else alSourceStop(sound.source); #endif @@ -1011,14 +1074,7 @@ void StopSound(Sound sound) bool IsSoundPlaying(Sound sound) { #if USE_MINI_AL - SoundData* internalSound = (SoundData*)sound.handle; - if (internalSound == NULL) - { - TraceLog(LOG_ERROR, "IsSoundPlaying() : Invalid sound"); - return false; - } - - return internalSound->playing && !internalSound->paused; + return IsAudioBufferPlaying((AudioBuffer*)sound.audioBuffer); #else bool playing = false; ALint state; @@ -1034,14 +1090,7 @@ bool IsSoundPlaying(Sound sound) void SetSoundVolume(Sound sound, float volume) { #if USE_MINI_AL - SoundData* internalSound = (SoundData*)sound.handle; - if (internalSound == NULL) - { - TraceLog(LOG_ERROR, "SetSoundVolume() : Invalid sound"); - return; - } - - internalSound->volume = volume; + SetAudioBufferVolume((AudioBuffer*)sound.audioBuffer, volume); #else alSourcef(sound.source, AL_GAIN, volume); #endif @@ -1051,19 +1100,7 @@ void SetSoundVolume(Sound sound, float volume) void SetSoundPitch(Sound sound, float pitch) { #if USE_MINI_AL - SoundData* internalSound = (SoundData*)sound.handle; - if (internalSound == NULL) - { - TraceLog(LOG_ERROR, "SetSoundPitch() : Invalid sound"); - return; - } - - internalSound->pitch = pitch; - - // Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches - // will make the sound faster; lower pitches make it slower. - mal_uint32 newOutputSampleRate = (mal_uint32)((((float)internalSound->dsp.config.sampleRateOut / (float)internalSound->dsp.config.sampleRateIn) / pitch) * internalSound->dsp.config.sampleRateIn); - mal_dsp_set_output_sample_rate(&internalSound->dsp, newOutputSampleRate); + SetAudioBufferPitch((AudioBuffer*)sound.audioBuffer, pitch); #else alSourcef(sound.source, AL_PITCH, pitch); #endif @@ -1361,7 +1398,22 @@ void UnloadMusicStream(Music music) void PlayMusicStream(Music music) { #if USE_MINI_AL - PlayAudioStream(music->stream); + AudioBuffer* audioBuffer = (AudioBuffer*)music->stream.audioBuffer; + if (audioBuffer == NULL) + { + TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer"); + return; + } + + // For music streams, we need to make sure we maintain the frame cursor position. This is hack for this section of code in UpdateMusicStream() + // // NOTE: In case window is minimized, music stream is stopped, + // // just make sure to play again on window restore + // if (IsMusicPlaying(music)) PlayMusicStream(music); + mal_uint32 frameCursorPos = audioBuffer->frameCursorPos; + { + PlayAudioStream(music->stream); // <-- This resets the cursor position. + } + audioBuffer->frameCursorPos = frameCursorPos; #else alSourcePlay(music->stream.source); #endif @@ -1672,65 +1724,6 @@ float GetMusicTimePlayed(Music music) return secondsPlayed; } -#if USE_MINI_AL -static mal_uint32 UpdateAudioStream_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) -{ - AudioStreamData* internalData = (AudioStreamData*)pUserData; - - mal_uint32 subBufferSizeInFrames = AUDIO_BUFFER_SIZE; - mal_uint32 currentSubBufferIndex = internalData->frameCursorPos / subBufferSizeInFrames; - if (currentSubBufferIndex > 1) { - TraceLog(LOG_DEBUG, "Frame cursor position moved too far forward in audio stream"); - return 0; - } - - // Another thread can update the processed state of buffers so we just take a copy here to try and avoid potential synchronization problems. - bool isSubBufferProcessed[2]; - isSubBufferProcessed[0] = internalData->isSubBufferProcessed[0]; - isSubBufferProcessed[1] = internalData->isSubBufferProcessed[1]; - - mal_uint32 channels = internalData->dsp.config.channelsIn; - mal_uint32 sampleSizeInBytes = mal_get_sample_size_in_bytes(internalData->dsp.config.formatIn); - mal_uint32 frameSizeInBytes = sampleSizeInBytes*channels; - - // Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0. - mal_uint32 framesRead = 0; - while (!isSubBufferProcessed[currentSubBufferIndex]) - { - mal_uint32 totalFramesRemaining = (frameCount - framesRead); - if (totalFramesRemaining == 0) { - break; - } - - mal_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames * currentSubBufferIndex; - mal_uint32 framesRemainingInThisSubBuffer = subBufferSizeInFrames - (internalData->frameCursorPos - firstFrameIndexOfThisSubBuffer); - - mal_uint32 framesToRead = totalFramesRemaining; - if (framesToRead > framesRemainingInThisSubBuffer) { - framesToRead = framesRemainingInThisSubBuffer; - } - - memcpy((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), internalData->buffer + (internalData->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes); - - framesRead += framesToRead; - internalData->frameCursorPos = (internalData->frameCursorPos + framesToRead) % internalData->bufferSizeInFrames; - - // If we've read to the end of the buffer, mark it as processed. - if (framesToRead == framesRemainingInThisSubBuffer) { - internalData->isSubBufferProcessed[currentSubBufferIndex] = true; - currentSubBufferIndex = (currentSubBufferIndex + 1) % 2; - } - } - - // Zero-fill excess. - mal_uint32 totalFramesRemaining = (frameCount - framesRead); - if (totalFramesRemaining > 0) { - memset((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes); - } - - return frameCount; -} -#endif // Init audio stream (to stream audio pcm data) AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) @@ -1750,38 +1743,17 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un #if USE_MINI_AL - AudioStreamData* internalData = (AudioStreamData*)calloc(1, sizeof(*internalData) + (AUDIO_BUFFER_SIZE*2 * stream.channels*(stream.sampleSize/8))); - if (internalData == NULL) + mal_format formatIn = ((stream.sampleSize == 8) ? mal_format_u8 : ((stream.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); + + AudioBuffer* audioBuffer = CreateAudioBuffer(formatIn, stream.channels, stream.sampleRate, AUDIO_BUFFER_SIZE*2, AUDIO_BUFFER_USAGE_STREAM); + if (audioBuffer == NULL) { - TraceLog(LOG_ERROR, "Failed to allocate buffer for audio stream"); + TraceLog(LOG_ERROR, "InitAudioStream() : Failed to create audio buffer"); return stream; } - mal_dsp_config config; - memset(&config, 0, sizeof(config)); - config.formatIn = ((stream.sampleSize == 8) ? mal_format_u8 : ((stream.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); - config.channelsIn = stream.channels; - config.sampleRateIn = stream.sampleRate; - config.formatOut = DEVICE_FORMAT; - config.channelsOut = DEVICE_CHANNELS; - config.sampleRateOut = DEVICE_SAMPLE_RATE; - mal_result result = mal_dsp_init(&config, UpdateAudioStream_OnDSPRead, internalData, &internalData->dsp); - if (result != MAL_SUCCESS) - { - TraceLog(LOG_ERROR, "InitAudioStream() : Failed to initialize data conversion pipeline"); - free(internalData); - return stream; - } - - // Buffers should be marked as processed by default so that a call to UpdateAudioStream() immediately after initialization works correctly. - internalData->isSubBufferProcessed[0] = true; - internalData->isSubBufferProcessed[1] = true; - internalData->bufferSizeInFrames = AUDIO_BUFFER_SIZE*2; - internalData->volume = 1; - internalData->pitch = 1; - AppendAudioStream(internalData); - - stream.handle = internalData; + audioBuffer->looping = true; // Always loop for streaming buffers. + stream.audioBuffer = audioBuffer; #else // Setup OpenAL format if (stream.channels == 1) @@ -1838,9 +1810,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un void CloseAudioStream(AudioStream stream) { #if USE_MINI_AL - AudioStreamData* internalData = (AudioStreamData*)stream.handle; - RemoveAudioStream(internalData); - free(internalData); + DeleteAudioBuffer((AudioBuffer*)stream.audioBuffer); #else // Stop playing channel alSourceStop(stream.source); @@ -1871,32 +1841,30 @@ void CloseAudioStream(AudioStream stream) void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) { #if USE_MINI_AL - AudioStreamData* internalData = (AudioStreamData*)stream.handle; - if (internalData == NULL) + AudioBuffer* audioBuffer = (AudioBuffer*)stream.audioBuffer; + if (audioBuffer == NULL) { - TraceLog(LOG_ERROR, "Invalid audio stream"); + TraceLog(LOG_ERROR, "UpdateAudioStream() : No audio buffer"); return; } - // We need to determine which half of the buffer needs updating. If the stream is not started and the cursor position is - // at the front of the buffer, update the first subbuffer. - if (internalData->isSubBufferProcessed[0] || internalData->isSubBufferProcessed[1]) + if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1]) { mal_uint32 subBufferToUpdate; - if (internalData->isSubBufferProcessed[0] && internalData->isSubBufferProcessed[1]) + if (audioBuffer->isSubBufferProcessed[0] && audioBuffer->isSubBufferProcessed[1]) { // Both buffers are available for updating. Update the first one and make sure the cursor is moved back to the front. subBufferToUpdate = 0; - internalData->frameCursorPos = 0; + audioBuffer->frameCursorPos = 0; } else { // Just update whichever sub-buffer is processed. - subBufferToUpdate = (internalData->isSubBufferProcessed[0]) ? 0 : 1; + subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0]) ? 0 : 1; } - mal_uint32 subBufferSizeInFrames = AUDIO_BUFFER_SIZE; - unsigned char *subBuffer = internalData->buffer + ((subBufferSizeInFrames * stream.channels * (stream.sampleSize/8)) * subBufferToUpdate); + mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2; + unsigned char *subBuffer = audioBuffer->buffer + ((subBufferSizeInFrames * stream.channels * (stream.sampleSize/8)) * subBufferToUpdate); // Does this API expect a whole buffer to be updated in one go? Assuming so, but if not will need to change this logic. if (subBufferSizeInFrames >= (mal_uint32)samplesCount) @@ -1915,21 +1883,19 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) memset(subBuffer + bytesToWrite, 0, leftoverFrameCount * stream.channels * (stream.sampleSize/8)); } - internalData->isSubBufferProcessed[subBufferToUpdate] = false; + audioBuffer->isSubBufferProcessed[subBufferToUpdate] = false; } else { - TraceLog(LOG_ERROR, "[AUD ID %i] UpdateAudioStream() : Attempting to write too many frames to buffer"); + TraceLog(LOG_ERROR, "UpdateAudioStream() : Attempting to write too many frames to buffer"); return; } } else { - TraceLog(LOG_ERROR, "[AUD ID %i] Audio buffer not available for updating"); + TraceLog(LOG_ERROR, "Audio buffer not available for updating"); return; } - - #else ALuint buffer = 0; alSourceUnqueueBuffers(stream.source, 1, &buffer); @@ -1948,14 +1914,14 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) bool IsAudioBufferProcessed(AudioStream stream) { #if USE_MINI_AL - AudioStreamData* internalData = (AudioStreamData*)stream.handle; - if (internalData == NULL) + AudioBuffer* audioBuffer = (AudioBuffer*)stream.audioBuffer; + if (audioBuffer == NULL) { - TraceLog(LOG_ERROR, "Invalid audio stream"); + TraceLog(LOG_ERROR, "IsAudioBufferProcessed() : No audio buffer"); return false; } - return internalData->isSubBufferProcessed[0] || internalData->isSubBufferProcessed[1]; + return audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1]; #else ALint processed = 0; @@ -1970,14 +1936,7 @@ bool IsAudioBufferProcessed(AudioStream stream) void PlayAudioStream(AudioStream stream) { #if USE_MINI_AL - AudioStreamData* internalData = (AudioStreamData*)stream.handle; - if (internalData == NULL) - { - TraceLog(LOG_ERROR, "Invalid audio stream"); - return; - } - - internalData->playing = true; + PlayAudioBuffer((AudioBuffer*)stream.audioBuffer); #else alSourcePlay(stream.source); #endif @@ -1987,14 +1946,7 @@ void PlayAudioStream(AudioStream stream) void PauseAudioStream(AudioStream stream) { #if USE_MINI_AL - AudioStreamData* internalData = (AudioStreamData*)stream.handle; - if (internalData == NULL) - { - TraceLog(LOG_ERROR, "Invalid audio stream"); - return; - } - - internalData->paused = true; + PauseAudioBuffer((AudioBuffer*)stream.audioBuffer); #else alSourcePause(stream.source); #endif @@ -2004,14 +1956,7 @@ void PauseAudioStream(AudioStream stream) void ResumeAudioStream(AudioStream stream) { #if USE_MINI_AL - AudioStreamData* internalData = (AudioStreamData*)stream.handle; - if (internalData == NULL) - { - TraceLog(LOG_ERROR, "Invalid audio stream"); - return; - } - - internalData->paused = false; + ResumeAudioBuffer((AudioBuffer*)stream.audioBuffer); #else ALenum state; alGetSourcei(stream.source, AL_SOURCE_STATE, &state); @@ -2024,14 +1969,7 @@ void ResumeAudioStream(AudioStream stream) bool IsAudioStreamPlaying(AudioStream stream) { #if USE_MINI_AL - AudioStreamData* internalData = (AudioStreamData*)stream.handle; - if (internalData == NULL) - { - TraceLog(LOG_ERROR, "Invalid audio stream"); - return false; - } - - return internalData->playing; + return IsAudioBufferPlaying((AudioBuffer*)stream.audioBuffer); #else bool playing = false; ALint state; @@ -2048,18 +1986,7 @@ bool IsAudioStreamPlaying(AudioStream stream) void StopAudioStream(AudioStream stream) { #if USE_MINI_AL - AudioStreamData* internalData = (AudioStreamData*)stream.handle; - if (internalData == NULL) - { - TraceLog(LOG_ERROR, "Invalid audio stream"); - return; - } - - internalData->playing = 0; - internalData->paused = 0; - internalData->frameCursorPos = 0; - internalData->isSubBufferProcessed[0] = true; - internalData->isSubBufferProcessed[1] = true; + StopAudioBuffer((AudioBuffer*)stream.audioBuffer); #else alSourceStop(stream.source); #endif @@ -2068,14 +1995,7 @@ void StopAudioStream(AudioStream stream) void SetAudioStreamVolume(AudioStream stream, float volume) { #if USE_MINI_AL - AudioStreamData* internalData = (AudioStreamData*)stream.handle; - if (internalData == NULL) - { - TraceLog(LOG_ERROR, "Invalid audio stream"); - return; - } - - internalData->volume = volume; + SetAudioBufferVolume((AudioBuffer*)stream.audioBuffer, volume); #else alSourcef(stream.source, AL_GAIN, volume); #endif @@ -2084,25 +2004,7 @@ void SetAudioStreamVolume(AudioStream stream, float volume) void SetAudioStreamPitch(AudioStream stream, float pitch) { #if USE_MINI_AL - AudioStreamData* internalData = (AudioStreamData*)stream.handle; - if (internalData == NULL) - { - TraceLog(LOG_ERROR, "Invalid audio stream"); - return; - } - - if (pitch == 0) - { - TraceLog(LOG_ERROR, "Attempting to set pitch to 0"); - return; - } - - internalData->pitch = pitch; - - // Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches - // will make the sound faster; lower pitches make it slower. - mal_uint32 newOutputSampleRate = (mal_uint32)((((float)internalData->dsp.config.sampleRateOut / (float)internalData->dsp.config.sampleRateIn) / pitch) * internalData->dsp.config.sampleRateIn); - mal_dsp_set_output_sample_rate(&internalData->dsp, newOutputSampleRate); + SetAudioBufferPitch((AudioBuffer*)stream.audioBuffer, pitch); #else alSourcef(stream.source, AL_PITCH, pitch); #endif diff --git a/src/raylib.h b/src/raylib.h index 1f138c2b..331817cf 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -486,7 +486,7 @@ typedef struct Wave { // Sound source type typedef struct Sound { - void* handle; // A pointer to internal data used by the audio system. + void* audioBuffer; // A pointer to internal data used by the audio system. unsigned int source; // OpenAL audio source id unsigned int buffer; // OpenAL audio buffer id @@ -504,7 +504,7 @@ typedef struct AudioStream { unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) unsigned int channels; // Number of channels (1-mono, 2-stereo) - void* handle; // A pointer to internal data used by the audio system. + void* audioBuffer; // A pointer to internal data used by the audio system. int format; // OpenAL audio format specifier unsigned int source; // OpenAL audio source id From b9bb80d004d93aac0fe71b56b0efa71416a2e97e Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 18 Nov 2017 10:27:44 +1000 Subject: [PATCH 022/139] Add some logging and update mini_al. --- src/audio.c | 5 +++++ src/external/mini_al.h | 44 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/audio.c b/src/audio.c index 83538f06..5bff9a0c 100644 --- a/src/audio.c +++ b/src/audio.c @@ -425,6 +425,11 @@ void InitAudioDevice(void) return; } + TraceLog(LOG_INFO, "Audio device initialized successfully"); + TraceLog(LOG_INFO, "Audio backend: %s", mal_get_backend_name(context.backend)); + TraceLog(LOG_INFO, "Audio format: %s", mal_get_format_name(device.format)); + TraceLog(LOG_INFO, "Audio channels: %d", device.channels); + TraceLog(LOG_INFO, "Audio sample rate: %d", device.sampleRate); isAudioInitialized = MAL_TRUE; #else diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 18dd3b40..2dcf3e71 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -195,6 +195,9 @@ extern "C" { #ifdef __ANDROID__ #define MAL_ANDROID #endif + #ifdef __EMSCRIPTEN__ + #define MAL_EMSCRIPTEN + #endif #endif // Some backends are only supported on certain platforms. @@ -226,7 +229,7 @@ extern "C" { #if defined(MAL_ANDROID) #define MAL_SUPPORT_OPENSL #endif - #if !defined(MAL_LINUX) && !defined(MAL_APPLE) && !defined(MAL_ANDROID) + #if !defined(MAL_LINUX) && !defined(MAL_APPLE) && !defined(MAL_ANDROID) && !defined(MAL_EMSCRIPTEN) #define MAL_SUPPORT_OSS #endif #endif @@ -1435,6 +1438,12 @@ void mal_mutex_unlock(mal_mutex* pMutex); // /////////////////////////////////////////////////////////////////////////////// +// Retrieves a friendly name for a backend. +const char* mal_get_backend_name(mal_backend backend); + +// Retrieves a friendly name for a format. +const char* mal_get_format_name(mal_format format); + // Blends two frames in floating point format. void mal_blend_f32(float* pOut, float* pInA, float* pInB, float factor, mal_uint32 channels); @@ -10287,6 +10296,39 @@ mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 chann ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +const char* mal_get_backend_name(mal_backend backend) +{ + switch (backend) + { + case mal_backend_null: return "Null"; + case mal_backend_wasapi: return "WASAPI"; + case mal_backend_dsound: return "DirectSound"; + case mal_backend_winmm: return "WinMM"; + case mal_backend_alsa: return "ALSA"; + //case mal_backend_pulse: return "PulseAudio"; + //case mal_backend_jack: return "JACK"; + //case mal_backend_coreaudio: return "Core Audio"; + case mal_backend_oss: return "OSS"; + case mal_backend_opensl: return "OpenSL|ES"; + case mal_backend_openal: return "OpenAL"; + default: return "Unknown"; + } +} + +const char* mal_get_format_name(mal_format format) +{ + switch (format) + { + case mal_format_unknown: return "Unknown"; + case mal_format_u8: return "8-bit Unsigned Integer"; + case mal_format_s16: return "16-bit Signed Integer"; + case mal_format_s24: return "24-bit Signed Integer (Tightly Packed)"; + case mal_format_s32: return "32-bit Signed Integer"; + case mal_format_f32: return "32-bit IEEE Floating Point"; + default: return "Invalid"; + } +} + void mal_blend_f32(float* pOut, float* pInA, float* pInB, float factor, mal_uint32 channels) { for (mal_uint32 i = 0; i < channels; ++i) { From 3be83dac7edebd58ab02814b634eb053377f954f Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 18 Nov 2017 11:51:51 +1000 Subject: [PATCH 023/139] Update mini_al. --- src/external/mini_al.h | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 2dcf3e71..98e68c1b 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -1579,6 +1579,11 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form #define MAL_HAS_NULL // Everything supports the null backend. #endif +// Disable run-time linking on certain backends. +#if defined(MAL_ANDROID) || defined(MAL_EMSCRIPTED) +#define MAL_NO_RUNTIME_LINKING +#endif + #ifdef MAL_WIN32 #define MAL_THREADCALL WINAPI @@ -6802,7 +6807,7 @@ static SLuint32 mal_channel_id_to_opensl(mal_uint8 id) } // Converts a channel mapping to an OpenSL-style channel mask. -static SLuint32 mal_channel_map_to_channel_mask__opensl(mal_uint8 channelMap[MAL_MAX_CHANNELS], mal_uint32 channels) +static SLuint32 mal_channel_map_to_channel_mask__opensl(const mal_uint8 channelMap[MAL_MAX_CHANNELS], mal_uint32 channels) { SLuint32 channelMask = 0; for (mal_uint32 iChannel = 0; iChannel < channels; ++iChannel) { @@ -8485,6 +8490,7 @@ mal_result mal_context_uninit_backend_apis__nix(mal_context* pContext) mal_result mal_context_init_backend_apis__nix(mal_context* pContext) { // pthread +#if !defined(MAL_NO_RUNTIME_LINKING) const char* libpthreadFileNames[] = { "libpthread.so", "libpthread.so.0", @@ -8512,6 +8518,18 @@ mal_result mal_context_init_backend_apis__nix(mal_context* pContext) pContext->posix.pthread_cond_destroy = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_destroy"); pContext->posix.pthread_cond_wait = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_wait"); pContext->posix.pthread_cond_signal = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_signal"); +#else + pContext->posix.pthread_create = (mal_proc)pthread_create; + pContext->posix.pthread_join = (mal_proc)pthread_join; + pContext->posix.pthread_mutex_init = (mal_proc)pthread_mutex_init; + pContext->posix.pthread_mutex_destroy = (mal_proc)pthread_mutex_destroy; + pContext->posix.pthread_mutex_lock = (mal_proc)pthread_mutex_lock; + pContext->posix.pthread_mutex_unlock = (mal_proc)pthread_mutex_unlock; + pContext->posix.pthread_cond_init = (mal_proc)pthread_cond_init; + pContext->posix.pthread_cond_destroy = (mal_proc)pthread_cond_destroy; + pContext->posix.pthread_cond_wait = (mal_proc)pthread_cond_wait; + pContext->posix.pthread_cond_signal = (mal_proc)pthread_cond_signal; +#endif return MAL_SUCCESS; } @@ -10528,7 +10546,7 @@ void mal_pcm_s32_to_f32(float* pOut, const int* pIn, unsigned int count) for (unsigned int i = 0; i < count; ++i) { int x = pIn[i]; double t; - t = (double)(x + 2147483648); + t = (double)(x + 2147483648LL); t = t * 0.0000000004656612873077392578125; r = (float)(t - 1); pOut[i] = (float)r; @@ -10586,7 +10604,7 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); c = c + 1; t = (mal_int64)(c * 2147483647.5); - r = (int)(t - 2147483648); + r = (int)(t - 2147483648LL); pOut[i] = (int)r; } } @@ -10605,6 +10623,7 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) // - Simplify the build system further for when development packages for various backends are not installed. // With this change, when the compiler supports __has_include, backends without the relevant development // packages installed will be ignored. This fixes the build for old versions of MinGW. +// - Fixes to the Android build. // - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of // audio data to a different format. // - Improvements to f32 -> u8/s16/s24/s32 conversion routines. From f9144ac5b0bc59e69d87ee8b67047888873418fc Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 18 Nov 2017 12:15:48 +1000 Subject: [PATCH 024/139] Rename a variable for consistency. --- src/audio.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/audio.c b/src/audio.c index 5bff9a0c..5209cc56 100644 --- a/src/audio.c +++ b/src/audio.c @@ -240,13 +240,13 @@ static mal_context context; static mal_device device; static mal_bool32 isAudioInitialized = MAL_FALSE; static float masterVolume = 1; -static mal_mutex soundLock; +static mal_mutex audioLock; static AudioBuffer* firstAudioBuffer = NULL; // Audio buffers are tracked in a linked list. static AudioBuffer* lastAudioBuffer = NULL; static void TrackAudioBuffer(AudioBuffer* audioBuffer) { - mal_mutex_lock(&soundLock); + mal_mutex_lock(&audioLock); { if (firstAudioBuffer == NULL) { firstAudioBuffer = audioBuffer; @@ -257,12 +257,12 @@ static void TrackAudioBuffer(AudioBuffer* audioBuffer) lastAudioBuffer = audioBuffer; } - mal_mutex_unlock(&soundLock); + mal_mutex_unlock(&audioLock); } static void UntrackAudioBuffer(AudioBuffer* audioBuffer) { - mal_mutex_lock(&soundLock); + mal_mutex_lock(&audioLock); { if (audioBuffer->prev == NULL) { firstAudioBuffer = audioBuffer->next; @@ -279,7 +279,7 @@ static void UntrackAudioBuffer(AudioBuffer* audioBuffer) audioBuffer->prev = NULL; audioBuffer->next = NULL; } - mal_mutex_unlock(&soundLock); + mal_mutex_unlock(&audioLock); } static void OnLog_MAL(mal_context* pContext, mal_device* pDevice, const char* message) @@ -314,7 +314,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC // Using a mutex here for thread-safety which makes things not real-time. This is unlikely to be necessary for this project, but may // want to consider how you might want to avoid this. - mal_mutex_lock(&soundLock); + mal_mutex_lock(&audioLock); { for (AudioBuffer* audioBuffer = firstAudioBuffer; audioBuffer != NULL; audioBuffer = audioBuffer->next) { @@ -378,7 +378,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC } } } - mal_mutex_unlock(&soundLock); + mal_mutex_unlock(&audioLock); return frameCount; // We always output the same number of frames that were originally requested. } @@ -417,7 +417,7 @@ void InitAudioDevice(void) // Mixing happens on a seperate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may // want to look at something a bit smarter later on to keep everything real-time, if that's necessary. - if (mal_mutex_init(&context, &soundLock) != MAL_SUCCESS) + if (mal_mutex_init(&context, &audioLock) != MAL_SUCCESS) { TraceLog(LOG_ERROR, "Failed to create mutex for audio mixing"); mal_device_uninit(&device); @@ -479,7 +479,7 @@ void CloseAudioDevice(void) return; } - mal_mutex_uninit(&soundLock); + mal_mutex_uninit(&audioLock); mal_device_uninit(&device); mal_context_uninit(&context); #else From 84ef8604435c95c2253037c6aacba513b4d0154c Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 18 Nov 2017 22:30:20 +1000 Subject: [PATCH 025/139] Update mini_al with experimental support for SDL/Emscripten. --- src/external/mini_al.h | 288 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 279 insertions(+), 9 deletions(-) diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 98e68c1b..22ec1ac5 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -233,8 +233,14 @@ extern "C" { #define MAL_SUPPORT_OSS #endif #endif -#define MAL_SUPPORT_OPENAL // All platforms support OpenAL (at least for now). -#define MAL_SUPPORT_NULL // All platforms support the null device. + +// Explicitly disable OpenAL for Emscripten - prefer SDL for this. +#if !defined(MAL_EMSCRIPTEN) +#define MAL_SUPPORT_OPENAL +#endif + +#define MAL_SUPPORT_SDL // All platforms support SDL. +#define MAL_SUPPORT_NULL // All platforms support the null backend. #if !defined(MAL_NO_WASAPI) && defined(MAL_SUPPORT_WASAPI) @@ -261,6 +267,9 @@ extern "C" { #if !defined(MAL_NO_OPENAL) && defined(MAL_SUPPORT_OPENAL) #define MAL_ENABLE_OPENAL #endif +#if !defined(MAL_NO_SDL) && defined(MAL_SUPPORT_SDL) + #define MAL_ENABLE_SDL +#endif #if !defined(MAL_NO_NULL) && defined(MAL_SUPPORT_NULL) #define MAL_ENABLE_NULL #endif @@ -469,7 +478,8 @@ typedef enum mal_backend_alsa, mal_backend_oss, mal_backend_opensl, - mal_backend_openal + mal_backend_openal, + mal_backend_sdl } mal_backend; typedef enum @@ -522,6 +532,9 @@ typedef union #ifdef MAL_SUPPORT_OPENAL char openal[256]; // OpenAL seems to use human-readable device names as the ID. #endif +#ifdef MAL_SUPPORT_SDL + int sdl; // +#endif #ifdef MAL_SUPPORT_NULL int nullbackend; // Always 0. #endif @@ -844,11 +857,17 @@ struct mal_context mal_uint32 isMCFormatsSupported : 1; } openal; #endif +#ifdef MAL_SUPPORT_SDL + struct + { + int _unused; + } sdl; +#endif #ifdef MAL_SUPPORT_NULL struct { int _unused; - } null_device; + } null_backend; #endif }; @@ -1017,6 +1036,12 @@ struct mal_device mal_bool32 breakFromMainLoop; } openal; #endif +#ifdef MAL_SUPPORT_SDL + struct + { + mal_uint32 deviceID; + } sdl; +#endif #ifdef MAL_SUPPORT_NULL struct { @@ -1575,12 +1600,26 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form #ifdef MAL_ENABLE_OPENAL #define MAL_HAS_OPENAL // mini_al inlines the necessary OpenAL stuff. #endif +#ifdef MAL_ENABLE_SDL + #define MAL_HAS_SDL + #ifdef __has_include + #ifdef MAL_EMSCRIPTEN + #if !__has_include() + #undef MAL_HAS_SDL + #endif + #else + #if !__has_include() + #undef MAL_HAS_SDL + #endif + #endif + #endif +#endif #ifdef MAL_ENABLE_NULL #define MAL_HAS_NULL // Everything supports the null backend. #endif // Disable run-time linking on certain backends. -#if defined(MAL_ANDROID) || defined(MAL_EMSCRIPTED) +#if defined(MAL_ANDROID) || defined(MAL_EMSCRIPTEN) #define MAL_NO_RUNTIME_LINKING #endif @@ -7768,7 +7807,7 @@ mal_result mal_enumerate_devices__openal(mal_context* pContext, mal_device_type return MAL_SUCCESS; } -static void mal_device_uninit__openal(mal_device* pDevice) +void mal_device_uninit__openal(mal_device* pDevice) { mal_assert(pDevice != NULL); @@ -7784,7 +7823,7 @@ static void mal_device_uninit__openal(mal_device* pDevice) mal_free(pDevice->openal.pIntermediaryBuffer); } -static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) +mal_result mal_device_init__openal(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) { if (pDevice->periods > MAL_MAX_PERIODS_OPENAL) { pDevice->periods = MAL_MAX_PERIODS_OPENAL; @@ -8167,6 +8206,196 @@ static mal_result mal_device__main_loop__openal(mal_device* pDevice) #endif // OpenAL + +/////////////////////////////////////////////////////////////////////////////// +// +// SDL Backend +// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MAL_HAS_SDL +#define SDL_MAIN_HANDLED +#ifdef MAL_EMSCRIPTEN +#include +#else +#include +#endif + +SDL_AudioFormat mal_format_to_sdl(mal_format format) +{ + switch (format) + { + case mal_format_unknown: return 0; + case mal_format_u8: return AUDIO_U8; + case mal_format_s16: return AUDIO_S16; + case mal_format_s24: return AUDIO_S32; // Closest match. + case mal_format_s32: return AUDIO_S32; + default: return 0; + } +} + +mal_format mal_format_from_sdl(SDL_AudioFormat format) +{ + switch (format) + { + case AUDIO_U8: return mal_format_u8; + case AUDIO_S16: return mal_format_s16; + case AUDIO_S32: return mal_format_s32; + case AUDIO_F32: return mal_format_f32; + default: return mal_format_unknown; + } +} + + +mal_result mal_context_init__sdl(mal_context* pContext) +{ + mal_assert(pContext != NULL); + + int resultSDL = SDL_InitSubSystem(SDL_INIT_AUDIO); + if (resultSDL != 0) { + return MAL_ERROR; + } + + return MAL_SUCCESS; +} + +mal_result mal_context_uninit__sdl(mal_context* pContext) +{ + mal_assert(pContext != NULL); + mal_assert(pContext->backend == mal_backend_sdl); + + SDL_QuitSubSystem(SDL_INIT_AUDIO); + return MAL_SUCCESS; +} + +mal_result mal_enumerate_devices__sdl(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) +{ + (void)pContext; + + + mal_uint32 infoSize = *pCount; + *pCount = 0; + + // For now I'm restricting the SDL backend to default devices. + if (pInfo != NULL) { + if (infoSize > 0) { + if (type == mal_device_type_playback) { + pInfo->id.sdl = 0; + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1); + } else { + pInfo->id.sdl = 0; + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1); + } + + pInfo += 1; + *pCount += 1; + } + } else { + *pCount += 1; + } + + return MAL_SUCCESS; +} + +void mal_device_uninit__sdl(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + +#if 1 + SDL_CloseAudioDevice(pDevice->sdl.deviceID); +#else + SDL_CloseAudio(); +#endif +} + + +static void mal_audio_callback__sdl(void *pUserData, Uint8 *pBuffer, int bufferSizeInBytes) +{ + mal_device* pDevice = (mal_device*)pUserData; + mal_assert(pDevice != NULL); + + mal_uint32 bufferSizeInFrames = (mal_uint32)bufferSizeInBytes / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; + + if (pDevice->type == mal_device_type_playback) { + mal_device__read_frames_from_client(pDevice, bufferSizeInFrames, pBuffer); + } else { + mal_device__send_frames_to_client(pDevice, bufferSizeInFrames, pBuffer); + } +} + +mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) +{ + mal_assert(pContext != NULL); + mal_assert(pConfig != NULL); + mal_assert(pDevice != NULL); + + SDL_AudioSpec desiredSpec, obtainedSpec; + mal_zero_memory(&desiredSpec, sizeof(desiredSpec)); + desiredSpec.freq = (int)pConfig->sampleRate; + desiredSpec.format = mal_format_to_sdl(pConfig->format); + desiredSpec.channels = (Uint8)pConfig->channels; + desiredSpec.samples = (Uint16)mal_next_power_of_2(pConfig->bufferSizeInFrames * pConfig->periods * pConfig->channels); + desiredSpec.callback = mal_audio_callback__sdl; + desiredSpec.userdata = pDevice; + + // Fall back to f32 if we don't have an appropriate mapping between mini_al and SDL. + if (desiredSpec.format == 0) { + desiredSpec.format = AUDIO_F32; + } + + // For now, only using the default device. + (void)pDeviceID; + +#if 1 + pDevice->sdl.deviceID = SDL_OpenAudioDevice(NULL, (type == mal_device_type_playback) ? 0 : 1, &desiredSpec, &obtainedSpec, 0); + if (pDevice->sdl.deviceID == 0) { + return mal_post_error(pDevice, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } +#else + pDevice->sdl.deviceID = SDL_OpenAudio(&desiredSpec, &obtainedSpec); + if (pDevice->sdl.deviceID != 0) { + return mal_post_error(pDevice, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } +#endif + + pDevice->internalFormat = mal_format_from_sdl(obtainedSpec.format); + pDevice->internalChannels = obtainedSpec.channels; + pDevice->internalSampleRate = (mal_uint32)obtainedSpec.freq; + pDevice->bufferSizeInFrames = obtainedSpec.samples / obtainedSpec.channels; + pDevice->periods = 1; // SDL doesn't seem to tell us what the period count is. Just set this 1. + + return MAL_SUCCESS; +} + +static mal_result mal_device__start_backend__sdl(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + +#if 1 + SDL_PauseAudioDevice(pDevice->sdl.deviceID, 0); +#else + SDL_PauseAudio(0); +#endif + + return MAL_SUCCESS; +} + +static mal_result mal_device__stop_backend__sdl(mal_device* pDevice) +{ + mal_assert(pDevice != NULL); + +#if 1 + SDL_PauseAudioDevice(pDevice->sdl.deviceID, 1); +#else + SDL_PauseAudio(1); +#endif + + return MAL_SUCCESS; +} +#endif // SDL + + + + mal_bool32 mal__is_channel_map_valid(const mal_channel* channelMap, mal_uint32 channels) { mal_assert(channels > 0); @@ -8585,6 +8814,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, con mal_backend_oss, mal_backend_opensl, mal_backend_openal, + mal_backend_sdl, mal_backend_null }; @@ -8642,6 +8872,12 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, con result = mal_context_init__openal(pContext); } break; #endif + #ifdef MAL_HAS_SDL + case mal_backend_sdl: + { + result = mal_context_init__sdl(pContext); + } break; + #endif #ifdef MAL_HAS_NULL case mal_backend_null: { @@ -8710,6 +8946,12 @@ mal_result mal_context_uninit(mal_context* pContext) return mal_context_uninit__openal(pContext); } break; #endif + #ifdef MAL_HAS_SDL + case mal_backend_sdl: + { + return mal_context_uninit__sdl(pContext); + } break; + #endif #ifdef MAL_HAS_NULL case mal_backend_null: { @@ -8775,6 +9017,12 @@ mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, ma return mal_enumerate_devices__openal(pContext, type, pCount, pInfo); } break; #endif + #ifdef MAL_HAS_SDL + case mal_backend_sdl: + { + return mal_enumerate_devices__sdl(pContext, type, pCount, pInfo); + } break; + #endif #ifdef MAL_HAS_NULL case mal_backend_null: { @@ -8934,6 +9182,12 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi result = mal_device_init__openal(pContext, type, pDeviceID, &config, pDevice); } break; #endif + #ifdef MAL_HAS_SDL + case mal_backend_sdl: + { + result = mal_device_init__sdl(pContext, type, pDeviceID, &config, pDevice); + } break; + #endif #ifdef MAL_HAS_NULL case mal_backend_null: { @@ -8979,7 +9233,7 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi // Some backends don't require the worker thread. - if (pContext->backend != mal_backend_opensl) { + if (pContext->backend != mal_backend_opensl && pContext->backend != mal_backend_sdl) { // The worker thread. if (mal_thread_create(pContext, &pDevice->thread, mal_worker_thread, pDevice) != MAL_SUCCESS) { mal_device_uninit(pDevice); @@ -9012,7 +9266,7 @@ void mal_device_uninit(mal_device* pDevice) mal_device__set_state(pDevice, MAL_STATE_UNINITIALIZED); // Wake up the worker thread and wait for it to properly terminate. - if (pDevice->pContext->backend != mal_backend_opensl) { + if (pDevice->pContext->backend != mal_backend_opensl && pDevice->pContext->backend != mal_backend_sdl) { mal_event_signal(&pDevice->wakeupEvent); mal_thread_wait(&pDevice->thread); } @@ -9057,6 +9311,11 @@ void mal_device_uninit(mal_device* pDevice) mal_device_uninit__openal(pDevice); } #endif +#ifdef MAL_HAS_SDL + if (pDevice->pContext->backend == mal_backend_sdl) { + mal_device_uninit__sdl(pDevice); + } +#endif #ifdef MAL_HAS_NULL if (pDevice->pContext->backend == mal_backend_null) { mal_device_uninit__null(pDevice); @@ -9117,6 +9376,12 @@ mal_result mal_device_start(mal_device* pDevice) mal_device__start_backend__opensl(pDevice); mal_device__set_state(pDevice, MAL_STATE_STARTED); } else +#endif +#ifdef MAL_HAS_SDL + if (pDevice->pContext->backend == mal_backend_sdl) { + mal_device__start_backend__sdl(pDevice); + mal_device__set_state(pDevice, MAL_STATE_STARTED); + } else #endif // Synchronous backends. { @@ -9167,6 +9432,11 @@ mal_result mal_device_stop(mal_device* pDevice) if (pDevice->pContext->backend == mal_backend_opensl) { mal_device__stop_backend__opensl(pDevice); } else +#endif +#ifdef MAL_HAS_SDL + if (pDevice->pContext->backend == mal_backend_sdl) { + mal_device__stop_backend__sdl(pDevice); + } else #endif // Synchronous backends. { From 49e945f958ac0370a270bd3b5f77660d4e3c84dd Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 19 Nov 2017 12:15:01 +1000 Subject: [PATCH 026/139] Update mini_al with fixes and improvements for Emscripten. --- src/external/mini_al.h | 367 ++++++++++++++++++++++++++++++++--------- 1 file changed, 288 insertions(+), 79 deletions(-) diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 22ec1ac5..0b324a2b 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -20,6 +20,7 @@ // - OSS // - OpenSL|ES / Android // - OpenAL +// - SDL // - Null (Silence) // - ... and more in the future. // - Core Audio (OSX, iOS) @@ -60,6 +61,12 @@ // -------------- // The BSD build uses OSS and should Just Work without any linking nor include path configuration. // +// Building (Emscripten) +// --------------------- +// The Emscripten build currently uses SDL 1.2 for it's backend which means specifying "-s USE_SDL=2" is unecessary +// as of this version. However, if in the future there is legitimate benefit or enough demand for SDL 2 to be used +// instead, you will need to specify this when compiling. +// // // Playback Example // ---------------- @@ -152,6 +159,9 @@ // #define MAL_NO_OPENAL // Disables the OpenAL backend. // +// #define MAL_NO_SDL +// Disables the SDL backend. +// // #define MAL_NO_NULL // Disables the null backend. // @@ -234,13 +244,12 @@ extern "C" { #endif #endif -// Explicitly disable OpenAL for Emscripten - prefer SDL for this. +// Explicitly disable OpenAL and Null backends for Emscripten because they both use a background thread which is not properly supported right now. #if !defined(MAL_EMSCRIPTEN) #define MAL_SUPPORT_OPENAL +#define MAL_SUPPORT_NULL // All platforms support the null backend. #endif - #define MAL_SUPPORT_SDL // All platforms support SDL. -#define MAL_SUPPORT_NULL // All platforms support the null backend. #if !defined(MAL_NO_WASAPI) && defined(MAL_SUPPORT_WASAPI) @@ -533,7 +542,7 @@ typedef union char openal[256]; // OpenAL seems to use human-readable device names as the ID. #endif #ifdef MAL_SUPPORT_SDL - int sdl; // + int sdl; // SDL devices are identified with an index. #endif #ifdef MAL_SUPPORT_NULL int nullbackend; // Always 0. @@ -860,7 +869,19 @@ struct mal_context #ifdef MAL_SUPPORT_SDL struct { - int _unused; + mal_handle hSDL; // SDL + mal_proc SDL_InitSubSystem; + mal_proc SDL_QuitSubSystem; + mal_proc SDL_GetNumAudioDevices; + mal_proc SDL_GetAudioDeviceName; + mal_proc SDL_CloseAudio; + mal_proc SDL_CloseAudioDevice; + mal_proc SDL_OpenAudio; + mal_proc SDL_OpenAudioDevice; + mal_proc SDL_PauseAudio; + mal_proc SDL_PauseAudioDevice; + + mal_bool32 usingSDL1; } sdl; #endif #ifdef MAL_SUPPORT_NULL @@ -1559,6 +1580,13 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form #endif +// Disable run-time linking on certain backends. +#ifndef MAL_NO_RUNTIME_LINLING + #if defined(MAL_ANDROID) || defined(MAL_EMSCRIPTEN) + #define MAL_NO_RUNTIME_LINKING + #endif +#endif + // Check if we have the necessary development packages for each backend at the top so we can use this to determine whether or not // certain unused functions and variables can be excluded from the build to avoid warnings. #ifdef MAL_ENABLE_WASAPI @@ -1602,14 +1630,16 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form #endif #ifdef MAL_ENABLE_SDL #define MAL_HAS_SDL - #ifdef __has_include - #ifdef MAL_EMSCRIPTEN - #if !__has_include() - #undef MAL_HAS_SDL - #endif - #else - #if !__has_include() - #undef MAL_HAS_SDL + #ifdef MAL_NO_RUNTIME_LINKING + #ifdef __has_include + #ifdef MAL_EMSCRIPTEN + #if !__has_include() + #undef MAL_HAS_SDL + #endif + #else + #if !__has_include() + #undef MAL_HAS_SDL + #endif #endif #endif #endif @@ -1618,11 +1648,6 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form #define MAL_HAS_NULL // Everything supports the null backend. #endif -// Disable run-time linking on certain backends. -#if defined(MAL_ANDROID) || defined(MAL_EMSCRIPTEN) -#define MAL_NO_RUNTIME_LINKING -#endif - #ifdef MAL_WIN32 #define MAL_THREADCALL WINAPI @@ -8213,35 +8238,90 @@ static mal_result mal_device__main_loop__openal(mal_device* pDevice) // /////////////////////////////////////////////////////////////////////////////// #ifdef MAL_HAS_SDL -#define SDL_MAIN_HANDLED -#ifdef MAL_EMSCRIPTEN -#include + +//#define MAL_USE_SDL_1 + +#define MAL_SDL_INIT_AUDIO 0x00000010 +#define MAL_AUDIO_U8 0x0008 +#define MAL_AUDIO_S16 0x8010 +#define MAL_AUDIO_S32 0x8020 +#define MAL_AUDIO_F32 0x8120 +#define MAL_SDL_AUDIO_ALLOW_FREQUENCY_CHANGE 0x00000001 +#define MAL_SDL_AUDIO_ALLOW_FORMAT_CHANGE 0x00000002 +#define MAL_SDL_AUDIO_ALLOW_CHANNELS_CHANGE 0x00000004 +#define MAL_SDL_AUDIO_ALLOW_ANY_CHANGE (MAL_SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | MAL_SDL_AUDIO_ALLOW_FORMAT_CHANGE | MAL_SDL_AUDIO_ALLOW_CHANNELS_CHANGE) + +// If we are linking at compile time we'll just #include SDL.h. Otherwise we can just redeclare some stuff to avoid the +// need for development packages to be installed. +#ifdef MAL_NO_RUNTIME_LINKING + #define SDL_MAIN_HANDLED + #ifdef MAL_EMSCRIPTEN + #include + + // For now just use SDL 1.2 with Emscripten. This avoids the need for "-s USE_SDL=2" at compile time. + #ifndef MAL_USE_SDL_1 + #define MAL_USE_SDL_1 + #endif + #else + #include + #endif + + typedef SDL_AudioCallback MAL_SDL_AudioCallback; + typedef SDL_AudioSpec MAL_SDL_AudioSpec; + typedef SDL_AudioFormat MAL_SDL_AudioFormat; + typedef SDL_AudioDeviceID MAL_SDL_AudioDeviceID; #else -#include + typedef void (* MAL_SDL_AudioCallback)(void* userdata, mal_uint8* stream, int len); + typedef mal_uint16 MAL_SDL_AudioFormat; + typedef mal_uint32 MAL_SDL_AudioDeviceID; + + typedef struct MAL_SDL_AudioSpec + { + int freq; + MAL_SDL_AudioFormat format; + mal_uint8 channels; + mal_uint8 silence; + mal_uint16 samples; + mal_uint16 padding; + mal_uint32 size; + MAL_SDL_AudioCallback callback; + void* userdata; + } MAL_SDL_AudioSpec; #endif -SDL_AudioFormat mal_format_to_sdl(mal_format format) +typedef int (* MAL_PFN_SDL_InitSubSystem)(mal_uint32 flags); +typedef void (* MAL_PFN_SDL_QuitSubSystem)(mal_uint32 flags); +typedef int (* MAL_PFN_SDL_GetNumAudioDevices)(int iscapture); +typedef const char* (* MAL_PFN_SDL_GetAudioDeviceName)(int index, int iscapture); +typedef void (* MAL_PFN_SDL_CloseAudio)(void); +typedef void (* MAL_PFN_SDL_CloseAudioDevice)(MAL_SDL_AudioDeviceID dev); +typedef int (* MAL_PFN_SDL_OpenAudio)(MAL_SDL_AudioSpec* desired, MAL_SDL_AudioSpec* obtained); +typedef MAL_SDL_AudioDeviceID (* MAL_PFN_SDL_OpenAudioDevice)(const char* device, int iscapture, const MAL_SDL_AudioSpec* desired, MAL_SDL_AudioSpec* obtained, int allowed_changes); +typedef void (* MAL_PFN_SDL_PauseAudio)(int pause_on); +typedef void (* MAL_PFN_SDL_PauseAudioDevice)(MAL_SDL_AudioDeviceID dev, int pause_on); + +MAL_SDL_AudioFormat mal_format_to_sdl(mal_format format) { switch (format) { case mal_format_unknown: return 0; - case mal_format_u8: return AUDIO_U8; - case mal_format_s16: return AUDIO_S16; - case mal_format_s24: return AUDIO_S32; // Closest match. - case mal_format_s32: return AUDIO_S32; + case mal_format_u8: return MAL_AUDIO_U8; + case mal_format_s16: return MAL_AUDIO_S16; + case mal_format_s24: return MAL_AUDIO_S32; // Closest match. + case mal_format_s32: return MAL_AUDIO_S32; default: return 0; } } -mal_format mal_format_from_sdl(SDL_AudioFormat format) +mal_format mal_format_from_sdl(MAL_SDL_AudioFormat format) { switch (format) { - case AUDIO_U8: return mal_format_u8; - case AUDIO_S16: return mal_format_s16; - case AUDIO_S32: return mal_format_s32; - case AUDIO_F32: return mal_format_f32; - default: return mal_format_unknown; + case MAL_AUDIO_U8: return mal_format_u8; + case MAL_AUDIO_S16: return mal_format_s16; + case MAL_AUDIO_S32: return mal_format_s32; + case MAL_AUDIO_F32: return mal_format_f32; + default: return mal_format_unknown; } } @@ -8250,7 +8330,71 @@ mal_result mal_context_init__sdl(mal_context* pContext) { mal_assert(pContext != NULL); - int resultSDL = SDL_InitSubSystem(SDL_INIT_AUDIO); +#ifndef MAL_NO_RUNTIME_LINKING + // Run-time linking. + const char* libNames[] = { +#if defined(MAL_WIN32) + "SDL2.dll", + "SDL.dll" +#elif defined(MAL_APPLE) + "libSDL2-2.0.0.dylib", // Can any Mac users out there comfirm these library names? + "libSDL-1.2.0.dylib" +#else + "libSDL2-2.0.so.0", + "libSDL-1.2.so.0" +#endif + }; + + for (size_t i = 0; i < mal_countof(libNames); ++i) { + pContext->sdl.hSDL = mal_dlopen(libNames[i]); + if (pContext->sdl.hSDL != NULL) { + break; + } + } + + if (pContext->sdl.hSDL == NULL) { + return MAL_NO_BACKEND; // Couldn't find SDL2.dll, etc. Most likely it's not installed. + } + + pContext->sdl.SDL_InitSubSystem = mal_dlsym(pContext->sdl.hSDL, "SDL_InitSubSystem"); + pContext->sdl.SDL_QuitSubSystem = mal_dlsym(pContext->sdl.hSDL, "SDL_QuitSubSystem"); + pContext->sdl.SDL_CloseAudio = mal_dlsym(pContext->sdl.hSDL, "SDL_CloseAudio"); + pContext->sdl.SDL_OpenAudio = mal_dlsym(pContext->sdl.hSDL, "SDL_OpenAudio"); + pContext->sdl.SDL_PauseAudio = mal_dlsym(pContext->sdl.hSDL, "SDL_PauseAudio"); +#ifndef MAL_USE_SDL_1 + pContext->sdl.SDL_GetNumAudioDevices = mal_dlsym(pContext->sdl.hSDL, "SDL_GetNumAudioDevices"); + pContext->sdl.SDL_GetAudioDeviceName = mal_dlsym(pContext->sdl.hSDL, "SDL_GetAudioDeviceName"); + pContext->sdl.SDL_CloseAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_CloseAudioDevice"); + pContext->sdl.SDL_OpenAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_OpenAudioDevice"); + pContext->sdl.SDL_PauseAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_PauseAudioDevice"); +#endif +#else + // Compile-time linking. + pContext->sdl.SDL_InitSubSystem = (mal_proc)SDL_InitSubSystem; + pContext->sdl.SDL_QuitSubSystem = (mal_proc)SDL_QuitSubSystem; + pContext->sdl.SDL_CloseAudio = (mal_proc)SDL_CloseAudio; + pContext->sdl.SDL_OpenAudio = (mal_proc)SDL_OpenAudio; + pContext->sdl.SDL_PauseAudio = (mal_proc)SDL_PauseAudio; +#ifndef MAL_USE_SDL_1 + pContext->sdl.SDL_GetNumAudioDevices = (mal_proc)SDL_GetNumAudioDevices; + pContext->sdl.SDL_GetAudioDeviceName = (mal_proc)SDL_GetAudioDeviceName; + pContext->sdl.SDL_CloseAudioDevice = (mal_proc)SDL_CloseAudioDevice; + pContext->sdl.SDL_OpenAudioDevice = (mal_proc)SDL_OpenAudioDevice; + pContext->sdl.SDL_PauseAudioDevice = (mal_proc)SDL_PauseAudioDevice; +#endif +#endif + + // We need to determine whether or not we are using SDL2 or SDL1. We can know this by looking at whether or not certain + // function pointers are NULL. + if (pContext->sdl.SDL_GetNumAudioDevices == NULL || + pContext->sdl.SDL_GetAudioDeviceName == NULL || + pContext->sdl.SDL_CloseAudioDevice == NULL || + pContext->sdl.SDL_OpenAudioDevice == NULL || + pContext->sdl.SDL_PauseAudioDevice == NULL) { + pContext->sdl.usingSDL1 = MAL_TRUE; + } + + int resultSDL = ((MAL_PFN_SDL_InitSubSystem)pContext->sdl.SDL_InitSubSystem)(MAL_SDL_INIT_AUDIO); if (resultSDL != 0) { return MAL_ERROR; } @@ -8263,7 +8407,7 @@ mal_result mal_context_uninit__sdl(mal_context* pContext) mal_assert(pContext != NULL); mal_assert(pContext->backend == mal_backend_sdl); - SDL_QuitSubSystem(SDL_INIT_AUDIO); + ((MAL_PFN_SDL_QuitSubSystem)pContext->sdl.SDL_QuitSubSystem)(MAL_SDL_INIT_AUDIO); return MAL_SUCCESS; } @@ -8271,26 +8415,45 @@ mal_result mal_enumerate_devices__sdl(mal_context* pContext, mal_device_type typ { (void)pContext; - mal_uint32 infoSize = *pCount; *pCount = 0; - // For now I'm restricting the SDL backend to default devices. - if (pInfo != NULL) { - if (infoSize > 0) { - if (type == mal_device_type_playback) { - pInfo->id.sdl = 0; - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1); - } else { - pInfo->id.sdl = 0; - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1); - } +#ifndef MAL_USE_SDL_1 + if (!pContext->sdl.usingSDL1) { + int deviceCount = ((MAL_PFN_SDL_GetNumAudioDevices)pContext->sdl.SDL_GetNumAudioDevices)((type == mal_device_type_playback) ? 0 : 1); + for (int i = 0; i < deviceCount; ++i) { + if (pInfo != NULL) { + if (infoSize > 0) { + pInfo->id.sdl = i; + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), ((MAL_PFN_SDL_GetAudioDeviceName)pContext->sdl.SDL_GetAudioDeviceName)(i, (type == mal_device_type_playback) ? 0 : 1), (size_t)-1); - pInfo += 1; + pInfo += 1; + *pCount += 1; + } + } else { + *pCount += 1; + } + } + } else +#endif + { + if (pInfo != NULL) { + if (infoSize > 0) { + // SDL1 uses default devices. + if (type == mal_device_type_playback) { + pInfo->id.sdl = 0; + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1); + } else { + pInfo->id.sdl = 0; + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1); + } + + pInfo += 1; + *pCount += 1; + } + } else { *pCount += 1; } - } else { - *pCount += 1; } return MAL_SUCCESS; @@ -8300,20 +8463,23 @@ void mal_device_uninit__sdl(mal_device* pDevice) { mal_assert(pDevice != NULL); -#if 1 - SDL_CloseAudioDevice(pDevice->sdl.deviceID); -#else - SDL_CloseAudio(); +#ifndef MAL_USE_SDL_1 + if (!pDevice->pContext->sdl.usingSDL1) { + ((MAL_PFN_SDL_CloseAudioDevice)pDevice->pContext->sdl.SDL_CloseAudioDevice)(pDevice->sdl.deviceID); + } else #endif + { + ((MAL_PFN_SDL_CloseAudio)pDevice->pContext->sdl.SDL_CloseAudio)(); + } } -static void mal_audio_callback__sdl(void *pUserData, Uint8 *pBuffer, int bufferSizeInBytes) +static void mal_audio_callback__sdl(void* pUserData, mal_uint8* pBuffer, int bufferSizeInBytes) { mal_device* pDevice = (mal_device*)pUserData; mal_assert(pDevice != NULL); - mal_uint32 bufferSizeInFrames = (mal_uint32)bufferSizeInBytes / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; + mal_uint32 bufferSizeInFrames = (mal_uint32)bufferSizeInBytes / mal_get_sample_size_in_bytes(pDevice->internalFormat) / pDevice->internalChannels; if (pDevice->type == mal_device_type_playback) { mal_device__read_frames_from_client(pDevice, bufferSizeInFrames, pBuffer); @@ -8328,34 +8494,61 @@ mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, mal mal_assert(pConfig != NULL); mal_assert(pDevice != NULL); - SDL_AudioSpec desiredSpec, obtainedSpec; + // SDL wants the buffer size to be a power of 2. The SDL_AudioSpec property for this is only a Uint16, so we need + // to explicitly clamp this because it will be easy to overflow. + mal_uint32 bufferSize = pConfig->bufferSizeInFrames * pConfig->periods * pConfig->channels; + if (bufferSize > 32768) { + bufferSize = 32768; + } else { + bufferSize = mal_next_power_of_2(bufferSize); + } + + mal_assert(bufferSize <= 32768); + + + MAL_SDL_AudioSpec desiredSpec, obtainedSpec; mal_zero_memory(&desiredSpec, sizeof(desiredSpec)); desiredSpec.freq = (int)pConfig->sampleRate; desiredSpec.format = mal_format_to_sdl(pConfig->format); - desiredSpec.channels = (Uint8)pConfig->channels; - desiredSpec.samples = (Uint16)mal_next_power_of_2(pConfig->bufferSizeInFrames * pConfig->periods * pConfig->channels); + desiredSpec.channels = (mal_uint8)pConfig->channels; + desiredSpec.samples = (mal_uint16)bufferSize; desiredSpec.callback = mal_audio_callback__sdl; desiredSpec.userdata = pDevice; // Fall back to f32 if we don't have an appropriate mapping between mini_al and SDL. if (desiredSpec.format == 0) { - desiredSpec.format = AUDIO_F32; + desiredSpec.format = MAL_AUDIO_F32; } - // For now, only using the default device. - (void)pDeviceID; +#ifndef MAL_USE_SDL_1 + if (!pDevice->pContext->sdl.usingSDL1) { + int isCapture = (type == mal_device_type_playback) ? 0 : 1; -#if 1 - pDevice->sdl.deviceID = SDL_OpenAudioDevice(NULL, (type == mal_device_type_playback) ? 0 : 1, &desiredSpec, &obtainedSpec, 0); - if (pDevice->sdl.deviceID == 0) { - return mal_post_error(pDevice, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } -#else - pDevice->sdl.deviceID = SDL_OpenAudio(&desiredSpec, &obtainedSpec); - if (pDevice->sdl.deviceID != 0) { - return mal_post_error(pDevice, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } + const char* pDeviceName = NULL; + if (pDeviceID != NULL) { + pDeviceName = ((MAL_PFN_SDL_GetAudioDeviceName)pDevice->pContext->sdl.SDL_GetAudioDeviceName)(pDeviceID->sdl, isCapture); + } + + pDevice->sdl.deviceID = ((MAL_PFN_SDL_OpenAudioDevice)pDevice->pContext->sdl.SDL_OpenAudioDevice)(pDeviceName, isCapture, &desiredSpec, &obtainedSpec, MAL_SDL_AUDIO_ALLOW_ANY_CHANGE); + if (pDevice->sdl.deviceID == 0) { + return mal_post_error(pDevice, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + } else #endif + { + // SDL1 uses default devices. + (void)pDeviceID; + + // SDL1 only supports playback as far as I can tell. + if (type != mal_device_type_playback) { + return MAL_NO_DEVICE; + } + + pDevice->sdl.deviceID = ((MAL_PFN_SDL_OpenAudio)pDevice->pContext->sdl.SDL_OpenAudio)(&desiredSpec, &obtainedSpec); + if (pDevice->sdl.deviceID != 0) { + return mal_post_error(pDevice, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); + } + } pDevice->internalFormat = mal_format_from_sdl(obtainedSpec.format); pDevice->internalChannels = obtainedSpec.channels; @@ -8363,6 +8556,15 @@ mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, mal pDevice->bufferSizeInFrames = obtainedSpec.samples / obtainedSpec.channels; pDevice->periods = 1; // SDL doesn't seem to tell us what the period count is. Just set this 1. +#if 0 + printf("=== SDL CONFIG ===\n"); + printf("REQUESTED -> RECEIVED\n"); + printf(" FORMAT: %s -> %s\n", mal_get_format_name(pConfig->format), mal_get_format_name(pDevice->internalFormat)); + printf(" CHANNELS: %d -> %d\n", desiredSpec.channels, obtainedSpec.channels); + printf(" SAMPLE RATE: %d -> %d\n", desiredSpec.freq, obtainedSpec.freq); + printf(" BUFFER SIZE IN SAMPLES: %d -> %d\n", desiredSpec.samples, obtainedSpec.samples); +#endif + return MAL_SUCCESS; } @@ -8370,11 +8572,14 @@ static mal_result mal_device__start_backend__sdl(mal_device* pDevice) { mal_assert(pDevice != NULL); -#if 1 - SDL_PauseAudioDevice(pDevice->sdl.deviceID, 0); -#else - SDL_PauseAudio(0); +#ifndef MAL_USE_SDL_1 + if (!pDevice->pContext->sdl.usingSDL1) { + ((MAL_PFN_SDL_PauseAudioDevice)pDevice->pContext->sdl.SDL_PauseAudioDevice)(pDevice->sdl.deviceID, 0); + } else #endif + { + ((MAL_PFN_SDL_PauseAudio)pDevice->pContext->sdl.SDL_PauseAudio)(0); + } return MAL_SUCCESS; } @@ -8383,11 +8588,14 @@ static mal_result mal_device__stop_backend__sdl(mal_device* pDevice) { mal_assert(pDevice != NULL); -#if 1 - SDL_PauseAudioDevice(pDevice->sdl.deviceID, 1); -#else - SDL_PauseAudio(1); +#ifndef MAL_USE_SDL_1 + if (!pDevice->pContext->sdl.usingSDL1) { + ((MAL_PFN_SDL_PauseAudioDevice)pDevice->pContext->sdl.SDL_PauseAudioDevice)(pDevice->sdl.deviceID, 1); + } else #endif + { + ((MAL_PFN_SDL_PauseAudio)pDevice->pContext->sdl.SDL_PauseAudio)(1); + } return MAL_SUCCESS; } @@ -10890,6 +11098,7 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) // need to update. // - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively. // - API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent. +// - Add support for SDL and Emscripten. // - Simplify the build system further for when development packages for various backends are not installed. // With this change, when the compiler supports __has_include, backends without the relevant development // packages installed will be ignored. This fixes the build for old versions of MinGW. From 3238cba47c698dd7bbeba35d5b2ec81e9ce0b974 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 19 Nov 2017 16:36:24 +1000 Subject: [PATCH 027/139] Log the name of the playback device. --- src/audio.c | 2 +- src/external/mini_al.h | 176 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 171 insertions(+), 7 deletions(-) diff --git a/src/audio.c b/src/audio.c index 5209cc56..2c2aedac 100644 --- a/src/audio.c +++ b/src/audio.c @@ -425,7 +425,7 @@ void InitAudioDevice(void) return; } - TraceLog(LOG_INFO, "Audio device initialized successfully"); + TraceLog(LOG_INFO, "Audio device initialized successfully: %s", device.name); TraceLog(LOG_INFO, "Audio backend: %s", mal_get_backend_name(context.backend)); TraceLog(LOG_INFO, "Audio format: %s", mal_get_format_name(device.format)); TraceLog(LOG_INFO, "Audio channels: %d", device.channels); diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 0b324a2b..f1d7ffdc 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -1,4 +1,4 @@ -// Mini audio library. Public domain. See "unlicense" statement at the end of this file. +// Audio playback and capture library. Public domain. See "unlicense" statement at the end of this file. // mini_al - v0.x - 2017-xx-xx // // David Reid - davidreidsoftware@gmail.com @@ -872,13 +872,13 @@ struct mal_context mal_handle hSDL; // SDL mal_proc SDL_InitSubSystem; mal_proc SDL_QuitSubSystem; + mal_proc SDL_CloseAudio; + mal_proc SDL_OpenAudio; + mal_proc SDL_PauseAudio; mal_proc SDL_GetNumAudioDevices; mal_proc SDL_GetAudioDeviceName; - mal_proc SDL_CloseAudio; mal_proc SDL_CloseAudioDevice; - mal_proc SDL_OpenAudio; mal_proc SDL_OpenAudioDevice; - mal_proc SDL_PauseAudio; mal_proc SDL_PauseAudioDevice; mal_bool32 usingSDL1; @@ -944,6 +944,7 @@ struct mal_device mal_send_proc onSend; mal_stop_proc onStop; void* pUserData; // Application defined data. + char name[256]; mal_mutex lock; mal_event wakeupEvent; mal_event startEvent; @@ -1095,6 +1096,7 @@ struct mal_device // - OSS // - OpenSL|ES // - OpenAL +// - SDL // - Null // // The onLog callback is used for posting log messages back to the client for diagnostics, debugging, @@ -1156,8 +1158,8 @@ mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, ma // data. It's tied to the buffer size, so as an example, if your buffer size is equivalent to 10 // milliseconds and you have 2 periods, the CPU will wake up approximately every 5 milliseconds. // -// Consider using mal_device_config_init(), mal_device_config_init_playback(), etc. to make it easier -// to initialize a mal_device_config object. +// Use mal_device_config_init(), mal_device_config_init_playback(), etc. to initialize a +// mal_device_config object. // // When compiling for UWP you must ensure you call this function on the main UI thread because the // operating system may need to present the user with a message asking for permissions. Please refer @@ -1630,6 +1632,8 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form #endif #ifdef MAL_ENABLE_SDL #define MAL_HAS_SDL + + // SDL headers are necessary if using compile-time linking. #ifdef MAL_NO_RUNTIME_LINKING #ifdef __has_include #ifdef MAL_EMSCRIPTEN @@ -2667,6 +2671,140 @@ static inline mal_uint32 mal_device__get_state(mal_device* pDevice) #endif +// Generic function for retrieving the name of a device by it's ID. +// +// This function simply enumerates every device and then retrieves the name of the first device that has the same ID. +static mal_result mal_context__try_get_device_name_by_id(mal_context* pContext, mal_device_type type, const mal_device_id* pDeviceID, char* pName, size_t nameBufferSize) +{ + mal_assert(pContext != NULL); + mal_assert(pName != NULL); + + if (pDeviceID == NULL) { + return MAL_NO_DEVICE; + } + + mal_uint32 deviceCount; + mal_result result = mal_enumerate_devices(pContext, type, &deviceCount, NULL); + if (result != MAL_SUCCESS) { + return result; + } + + mal_device_info* pInfos = (mal_device_info*)mal_malloc(sizeof(*pInfos) * deviceCount); + if (pInfos == NULL) { + return MAL_OUT_OF_MEMORY; + } + + result = mal_enumerate_devices(pContext, type, &deviceCount, pInfos); + if (result != MAL_SUCCESS) { + mal_free(pInfos); + return result; + } + + mal_bool32 found = MAL_FALSE; + for (mal_uint32 iDevice = 0; iDevice < deviceCount; ++iDevice) { + // Prefer backend specific comparisons for efficiency and accuracy, but fall back to a generic method if a backend-specific comparison + // is not implemented. + switch (pContext->backend) + { + #ifdef MAL_HAS_WASAPI + case mal_backend_wasapi: + { + if (memcmp(pDeviceID->wasapi, &pInfos[iDevice].id.wasapi, sizeof(pDeviceID->wasapi)) == 0) { + found = MAL_TRUE; + } + } break; + #endif + #ifdef MAL_HAS_DSOUND + case mal_backend_dsound: + { + if (memcmp(pDeviceID->dsound, &pInfos[iDevice].id.dsound, sizeof(pDeviceID->dsound)) == 0) { + found = MAL_TRUE; + } + } break; + #endif + #ifdef MAL_HAS_WINMM + case mal_backend_winmm: + { + if (pInfos[iDevice].id.winmm == pDeviceID->winmm) { + found = MAL_TRUE; + } + } break; + #endif + #ifdef MAL_HAS_ALSA + case mal_backend_alsa: + { + if (mal_strcmp(pInfos[iDevice].id.alsa, pDeviceID->alsa) == 0) { + found = MAL_TRUE; + } + } break; + #endif + #ifdef MAL_HAS_COREAUDIO + case mal_backend_coreaudio + { + // TODO: Implement me. + } break; + #endif + #ifdef MAL_HAS_OSS + case mal_backend_oss: + { + if (mal_strcmp(pInfos[iDevice].id.oss, pDeviceID->oss) == 0) { + found = MAL_TRUE; + } + } break; + #endif + #ifdef MAL_HAS_OPENSL + case mal_backend_opensl: + { + if (pInfos[iDevice].id.opensl == pDeviceID->opensl) { + found = MAL_TRUE; + } + } break; + #endif + #ifdef MAL_HAS_OPENAL + case mal_backend_openal: + { + if (mal_strcmp(pInfos[iDevice].id.openal, pDeviceID->openal) == 0) { + found = MAL_TRUE; + } + } break; + #endif + #ifdef MAL_HAS_SDL + case mal_backend_sdl: + { + if (pInfos[iDevice].id.sdl == pDeviceID->sdl) { + found = MAL_TRUE; + } + } break; + #endif + #ifdef MAL_HAS_NULL + case mal_backend_null: + { + if (pInfos[iDevice].id.nullbackend == pDeviceID->nullbackend) { + found = MAL_TRUE; + } + } break; + #endif + + // Fall back to a generic memory comparison. + default: + { + if (memcmp(pDeviceID, &pInfos[iDevice].id, sizeof(*pDeviceID)) == 0) { + found = MAL_TRUE; + } + } break; + } + + if (found) { + mal_strncpy_s(pName, nameBufferSize, pInfos[iDevice].name, (size_t)-1); + result = MAL_SUCCESS; + break; + } + } + + mal_free(pInfos); + return result; +} + /////////////////////////////////////////////////////////////////////////////// // @@ -9181,6 +9319,11 @@ mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, ma { if (pCount == NULL) return mal_post_error(NULL, "mal_enumerate_devices() called with invalid arguments (pCount == 0).", MAL_INVALID_ARGS); + // The output buffer needs to be initialized to zero. + if (pInfo != NULL) { + mal_zero_memory(pInfo, (*pCount) * sizeof(*pInfo)); + } + switch (pContext->backend) { #ifdef MAL_HAS_WASAPI @@ -9409,6 +9552,27 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi if (result != MAL_SUCCESS) { return MAL_NO_BACKEND; // The error message will have been posted with mal_post_error() by the source of the error so don't bother calling it here. } + + + // If the backend did not fill out a name for the device, try a generic method. + if (pDevice->name[0] == '\0') { + if (mal_context__try_get_device_name_by_id(pContext, type, pDeviceID, pDevice->name, sizeof(pDevice->name)) != MAL_SUCCESS) { + // We failed to get the device name, so fall back to some generic names. + if (pDeviceID == NULL) { + if (type == mal_device_type_playback) { + mal_strncpy_s(pDevice->name, sizeof(pDevice->name), "Default Playback Device", (size_t)-1); + } else { + mal_strncpy_s(pDevice->name, sizeof(pDevice->name), "Default Capture Device", (size_t)-1); + } + } else { + if (type == mal_device_type_playback) { + mal_strncpy_s(pDevice->name, sizeof(pDevice->name), "Playback Device", (size_t)-1); + } else { + mal_strncpy_s(pDevice->name, sizeof(pDevice->name), "Capture Device", (size_t)-1); + } + } + } + } // We need a DSP object which is where samples are moved through in order to convert them to the From 14b889be4127f5ce96ad9c74bc90cbb0dad771c2 Mon Sep 17 00:00:00 2001 From: David Reid Date: Mon, 20 Nov 2017 21:47:07 +1000 Subject: [PATCH 028/139] Update mini_al with a potential fix for HTML5. --- src/external/mini_al.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/external/mini_al.h b/src/external/mini_al.h index f1d7ffdc..df0f560e 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -8682,6 +8682,11 @@ mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, mal return MAL_NO_DEVICE; } + // SDL1 does not support floating point formats. + if (desiredSpec.format == MAL_AUDIO_F32) { + desiredSpec.format = MAL_AUDIO_S16; + } + pDevice->sdl.deviceID = ((MAL_PFN_SDL_OpenAudio)pDevice->pContext->sdl.SDL_OpenAudio)(&desiredSpec, &obtainedSpec); if (pDevice->sdl.deviceID != 0) { return mal_post_error(pDevice, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); From c71b01c8ac824f3c519ce181fc029d8d62102073 Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 21 Nov 2017 06:35:38 +1000 Subject: [PATCH 029/139] Update mini_al with fixes for OpenSL and SDL backends. --- src/external/mini_al.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/external/mini_al.h b/src/external/mini_al.h index df0f560e..164709d9 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -9750,14 +9750,18 @@ mal_result mal_device_start(mal_device* pDevice) // Asynchronous backends need to be handled differently. #ifdef MAL_HAS_OPENSL if (pDevice->pContext->backend == mal_backend_opensl) { - mal_device__start_backend__opensl(pDevice); - mal_device__set_state(pDevice, MAL_STATE_STARTED); + result = mal_device__start_backend__opensl(pDevice); + if (result == MAL_SUCCESS) { + mal_device__set_state(pDevice, MAL_STATE_STARTED); + } } else #endif #ifdef MAL_HAS_SDL if (pDevice->pContext->backend == mal_backend_sdl) { - mal_device__start_backend__sdl(pDevice); - mal_device__set_state(pDevice, MAL_STATE_STARTED); + result = mal_device__start_backend__sdl(pDevice); + if (result == MAL_SUCCESS) { + mal_device__set_state(pDevice, MAL_STATE_STARTED); + } } else #endif // Synchronous backends. @@ -11275,6 +11279,7 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) // - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of // audio data to a different format. // - Improvements to f32 -> u8/s16/s24/s32 conversion routines. +// - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL and SDL backends. // - Warning fixes. // // v0.5 - 2017-11-11 From 398d793dbbc1ad5723f80706d9d091427be095c4 Mon Sep 17 00:00:00 2001 From: Martinfx Date: Tue, 21 Nov 2017 19:30:52 +0100 Subject: [PATCH 030/139] Added FreeBSD clean for Makefile --- examples/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/Makefile b/examples/Makefile index 1557da92..a2411c3f 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -359,6 +359,10 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) find . -type f -perm +ugo+x -delete rm -f *.o endif + ifeq ($(PLATFORM_OS),FREEBSD) + find . -type f -perm +ugo+x -delete + rm -f *.o + endif endif ifeq ($(PLATFORM),PLATFORM_RPI) find . -type f -executable -delete From 8b3694a34d91682e05fb74f625bbd0f2dbb01645 Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 22 Nov 2017 18:36:48 +1000 Subject: [PATCH 031/139] Fix a crash in audio mixing code. --- src/audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/audio.c b/src/audio.c index 2c2aedac..6065bf00 100644 --- a/src/audio.c +++ b/src/audio.c @@ -339,8 +339,8 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC float tempBuffer[1024]; // 512 frames for stereo. mal_uint32 framesToReadRightNow = framesToRead; - if (framesToReadRightNow > sizeof(tempBuffer)/DEVICE_CHANNELS) { - framesToReadRightNow = sizeof(tempBuffer)/DEVICE_CHANNELS; + if (framesToReadRightNow > sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS) { + framesToReadRightNow = sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS; } // If we're not looping, we need to make sure we flush the internal buffers of the DSP pipeline to ensure we get the From 25ceec9b8f8f414b995469a24ade69725ead4fdb Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 22 Nov 2017 14:56:45 +0100 Subject: [PATCH 032/139] Corrected default textures locations By default, we look for texture1 for LOC_MAP_SPECULAR and texture2 for LOC_MAP_NORMAL --- src/rlgl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rlgl.c b/src/rlgl.c index f273e55d..6ae7df4c 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -3362,8 +3362,8 @@ static void SetShaderDefaultLocations(Shader *shader) // Get handles to GLSL uniform locations (fragment shader) shader->locs[LOC_COLOR_DIFFUSE] = glGetUniformLocation(shader->id, "colDiffuse"); shader->locs[LOC_MAP_DIFFUSE] = glGetUniformLocation(shader->id, "texture0"); - shader->locs[LOC_MAP_NORMAL] = glGetUniformLocation(shader->id, "texture1"); - shader->locs[LOC_MAP_SPECULAR] = glGetUniformLocation(shader->id, "texture2"); + shader->locs[LOC_MAP_SPECULAR] = glGetUniformLocation(shader->id, "texture1"); + shader->locs[LOC_MAP_NORMAL] = glGetUniformLocation(shader->id, "texture2"); } // Unload default shader From 1be826fb165f4f627eddeedacf77c0eed88cb464 Mon Sep 17 00:00:00 2001 From: Ray San Date: Wed, 22 Nov 2017 17:21:38 +0100 Subject: [PATCH 033/139] Removed useless file --- src/external/glfw/src/CMakeLists.txt | 152 --------------------------- 1 file changed, 152 deletions(-) delete mode 100644 src/external/glfw/src/CMakeLists.txt diff --git a/src/external/glfw/src/CMakeLists.txt b/src/external/glfw/src/CMakeLists.txt deleted file mode 100644 index b14512cc..00000000 --- a/src/external/glfw/src/CMakeLists.txt +++ /dev/null @@ -1,152 +0,0 @@ - -set(common_HEADERS internal.h mappings.h - "${GLFW_BINARY_DIR}/src/glfw_config.h" - "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" - "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h") -set(common_SOURCES context.c init.c input.c monitor.c vulkan.c window.c) - -if (_GLFW_COCOA) - set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h - posix_thread.h nsgl_context.h egl_context.h osmesa_context.h) - set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m - cocoa_monitor.m cocoa_window.m cocoa_time.c posix_thread.c - nsgl_context.m egl_context.c osmesa_context.c) -elseif (_GLFW_WIN32) - set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h - wgl_context.h egl_context.h osmesa_context.h) - set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_joystick.c - win32_monitor.c win32_time.c win32_thread.c win32_window.c - wgl_context.c egl_context.c osmesa_context.c) -elseif (_GLFW_X11) - set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h posix_time.h - posix_thread.h glx_context.h egl_context.h osmesa_context.h) - set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c - xkb_unicode.c posix_time.c posix_thread.c glx_context.c - egl_context.c osmesa_context.c) - - if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - set(glfw_HEADERS ${glfw_HEADERS} linux_joystick.h) - set(glfw_SOURCES ${glfw_SOURCES} linux_joystick.c) - else() - set(glfw_HEADERS ${glfw_HEADERS} null_joystick.h) - set(glfw_SOURCES ${glfw_SOURCES} null_joystick.c) - endif() -elseif (_GLFW_WAYLAND) - set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h - posix_time.h posix_thread.h xkb_unicode.h egl_context.h - osmesa_context.h) - set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c - linux_joystick.c posix_time.c posix_thread.c xkb_unicode.c - egl_context.c osmesa_context.c) - - ecm_add_wayland_client_protocol(glfw_SOURCES - PROTOCOL - "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" - BASENAME relative-pointer-unstable-v1) - ecm_add_wayland_client_protocol(glfw_SOURCES - PROTOCOL - "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" - BASENAME pointer-constraints-unstable-v1) -elseif (_GLFW_MIR) - set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h - posix_time.h posix_thread.h xkb_unicode.h egl_context.h - osmesa_context.h) - set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c - linux_joystick.c posix_time.c posix_thread.c xkb_unicode.c - egl_context.c osmesa_context.c) -elseif (_GLFW_OSMESA) - set(glfw_HEADERS ${common_HEADERS} null_platform.h null_joystick.h - posix_time.h posix_thread.h osmesa_context.h) - set(glfw_SOURCES ${common_SOURCES} null_init.c null_monitor.c null_window.c - null_joystick.c posix_time.c posix_thread.c osmesa_context.c) -endif() - -if (APPLE) - # For some reason, CMake doesn't know about .m - set_source_files_properties(${glfw_SOURCES} PROPERTIES LANGUAGE C) -endif() - -# Make GCC and Clang warn about declarations that VS 2010 and 2012 won't accept -# for all source files that VS will build -if (${CMAKE_C_COMPILER_ID} STREQUAL GNU OR ${CMAKE_C_COMPILER_ID} STREQUAL Clang) - if (WIN32) - set(windows_SOURCES ${glfw_SOURCES}) - else() - set(windows_SOURCES ${common_SOURCES}) - endif() - set_source_files_properties(${windows_SOURCES} PROPERTIES - COMPILE_FLAGS -Wdeclaration-after-statement) -endif() - -add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS}) -set_target_properties(glfw PROPERTIES - OUTPUT_NAME ${GLFW_LIB_NAME} - VERSION ${GLFW_VERSION} - SOVERSION ${GLFW_VERSION_MAJOR} - POSITION_INDEPENDENT_CODE ON - FOLDER "GLFW3") - -target_compile_definitions(glfw PRIVATE - _GLFW_USE_CONFIG_H - $<$:_XOPEN_SOURCE=600>) -target_include_directories(glfw PUBLIC - "$" - "$/include>") -target_include_directories(glfw PRIVATE - "${GLFW_SOURCE_DIR}/src" - "${GLFW_BINARY_DIR}/src" - ${glfw_INCLUDE_DIRS}) - -# HACK: When building on MinGW, WINVER and UNICODE need to be defined before -# the inclusion of stddef.h (by glfw3.h), which is itself included before -# win32_platform.h. We define them here until a saner solution can be found -# NOTE: MinGW-w64 and Visual C++ do /not/ need this hack. -target_compile_definitions(glfw PRIVATE - "$<$:UNICODE;WINVER=0x0501>") - -# Enable a reasonable set of warnings (no, -Wextra is not reasonable) -target_compile_options(glfw PRIVATE - "$<$:-Wall>" - "$<$:-Wall>") - -if (BUILD_SHARED_LIBS) - if (WIN32) - if (MINGW) - # Remove the lib prefix on the DLL (but not the import library - set_target_properties(glfw PROPERTIES PREFIX "") - - # Add a suffix to the import library to avoid naming conflicts - set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.a") - else() - # Add a suffix to the import library to avoid naming conflicts - set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.lib") - endif() - elseif (APPLE) - # Add -fno-common to work around a bug in Apple's GCC - target_compile_options(glfw PRIVATE "-fno-common") - - set_target_properties(glfw PROPERTIES - INSTALL_NAME_DIR "lib${LIB_SUFFIX}") - elseif (UNIX) - # Hide symbols not explicitly tagged for export from the shared library - target_compile_options(glfw PRIVATE "-fvisibility=hidden") - endif() - - target_compile_definitions(glfw INTERFACE GLFW_DLL) - target_link_libraries(glfw PRIVATE ${glfw_LIBRARIES}) -else() - target_link_libraries(glfw INTERFACE ${glfw_LIBRARIES}) -endif() - -if (MSVC) - target_compile_definitions(glfw PRIVATE _CRT_SECURE_NO_WARNINGS) -endif() - -if (GLFW_INSTALL) - install(TARGETS glfw - EXPORT glfwTargets - RUNTIME DESTINATION "bin" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" - LIBRARY DESTINATION "lib${LIB_SUFFIX}") -endif() - From 9ec8c0f1d6d7b4cace71930cfefcc17f68a6d424 Mon Sep 17 00:00:00 2001 From: Ray San Date: Wed, 22 Nov 2017 17:29:46 +0100 Subject: [PATCH 034/139] Updated OSX compilation with clang --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 703206e2..a621217d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ before_install: mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev libglew-dev; wget 'https://github.com/a3f/GLFW-3.2.1-Debian-binary-package/releases/download/v3.2.1/GLFW-3.2.1-Linux.deb' && sudo dpkg -i GLFW-3.2.1-Linux.deb; fi - - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; brew install glfw; fi + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; brew install glfw; export CC=clang fi - "$CC --version" script: From f70a0a996cc7a9a3cd1f5e3c7e3466b1d2528fd3 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 22 Nov 2017 19:51:38 +0100 Subject: [PATCH 035/139] Review file issue --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a621217d..7a5148ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ before_install: mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev libglew-dev; wget 'https://github.com/a3f/GLFW-3.2.1-Debian-binary-package/releases/download/v3.2.1/GLFW-3.2.1-Linux.deb' && sudo dpkg -i GLFW-3.2.1-Linux.deb; fi - - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; brew install glfw; export CC=clang fi + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; brew install glfw; export CC=clang; fi - "$CC --version" script: From 899e1fbd94f697d95b9684e272de5410b08edc06 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 22 Nov 2017 22:47:57 +0100 Subject: [PATCH 036/139] Avoid duplicate definition of feature macro Feature macros need to be defined before #including any headers, preferably through the build system, but this is good enough. Fixes a compile error on my fork's Travis CI. --- src/core.c | 9 +++++---- src/gestures.h | 5 ++++- src/physac.h | 28 ++++++++++++++++------------ 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/core.c b/src/core.c index 97d8a74c..c11c69ce 100644 --- a/src/core.c +++ b/src/core.c @@ -88,6 +88,11 @@ #include "raylib.h" +#if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_S_SOURCE < 199309L + #undef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. +#endif + #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 #include "utils.h" // Required for: fopen() Android mapping @@ -110,10 +115,6 @@ #include "external/rgif.h" // Support GIF recording #endif -#if defined(__linux__) || defined(PLATFORM_WEB) - #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. -#endif - #include // Standard input / output lib #include // Required for: malloc(), free(), rand(), atexit() #include // Required for: typedef unsigned long long int uint64_t, used by hi-res timer diff --git a/src/gestures.h b/src/gestures.h index f4d38dfb..2e343154 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -148,7 +148,10 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); #elif defined(__linux__) - #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. + #if _POSIX_C_SOURCE < 199309L + #undef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. + #endif #include // Required for: timespec #include // Required for: clock_gettime() #endif diff --git a/src/physac.h b/src/physac.h index 5ecd2815..ef78aab8 100644 --- a/src/physac.h +++ b/src/physac.h @@ -235,6 +235,22 @@ PHYSACDEF void ClosePhysics(void); #if defined(PHYSAC_IMPLEMENTATION) +#if defined(_WIN32) + // Functions required to query time on Windows + int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); + int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); +#elif (defined(__linux__) || defined(__APPLE__) || defined(PLATFORM_WEB)) + #if _POSIX_C_SOURCE < 199309L + #undef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. + #endif + //#define _DEFAULT_SOURCE // Enables BSD function definitions and C99 POSIX compliance + #include // Required for: timespec + #include // Required for: clock_gettime() + #include +#endif + + #if !defined(PHYSAC_NO_THREADS) #include // Required for: pthread_t, pthread_create() #endif @@ -248,18 +264,6 @@ PHYSACDEF void ClosePhysics(void); #include "raymath.h" // Required for: Vector2Add(), Vector2Subtract() -#if defined(_WIN32) - // Functions required to query time on Windows - int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); - int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); -#elif defined(__linux__) || defined(__APPLE__) || defined(PLATFORM_WEB) - #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. - //#define _DEFAULT_SOURCE // Enables BSD function definitions and C99 POSIX compliance - #include // Required for: timespec - #include // Required for: clock_gettime() - #include -#endif - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- From b2acff66dec7bce30e9704aa9b13070f7c3ffac1 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 22 Nov 2017 22:33:47 +0100 Subject: [PATCH 037/139] Fix macOS build of new rglfw.c approach There have been two problems: * GLFW itself was compiled with the definitions for compiling _against_ GLFW (fixed by removing requirement for external glfw) * rglfw.c was being compiled as C code, although it includes Objective C files. This _might_ break the Windows build, needs to be checked. Fixes #391, but as noted I'd prefer though a separate source directory and build script for GLFW. --- .travis.yml | 3 +-- src/CMakeLists.txt | 6 +++--- src/gestures.h | 6 +++--- src/rglfw.c | 2 +- utils.cmake | 7 ------- 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7a5148ad..8b122c47 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,9 +25,8 @@ before_install: libopenal-dev libxcursor-dev libxinerama-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev libglew-dev; - wget 'https://github.com/a3f/GLFW-3.2.1-Debian-binary-package/releases/download/v3.2.1/GLFW-3.2.1-Linux.deb' && sudo dpkg -i GLFW-3.2.1-Linux.deb; fi - - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; brew install glfw; export CC=clang; fi + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; brew install glfw; fi - "$CC --version" script: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a398d665..f362b52f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,6 +20,7 @@ set(OPENGL_VERSION "3.3" CACHE STRING "OpenGL Version to build raylib with") set_property(CACHE OPENGL_VERSION PROPERTY STRINGS "3.3" "2.1" "1.1" "ES 2.0") ### Config options ### +include_directories(external/glfw/include) # Translate the config options to what raylib wants if(${PLATFORM} MATCHES "Desktop") @@ -40,6 +41,8 @@ if(${PLATFORM} MATCHES "Desktop") # See: https://github.com/raysan5/raylib/issues/341 if(APPLE) set(GRAPHICS "GRAPHICS_API_OPENGL_33") + set_source_files_properties(rglfw.c PROPERTIES COMPILE_FLAGS "-x objective-c") + link_libraries("-framework CoreFoundation -framework Cocoa -framework IOKit -framework CoreVideo") endif() elseif(${PLATFORM} MATCHES "Web") set(PLATFORM "PLATFORM_WEB") @@ -93,9 +96,6 @@ if(${PLATFORM} MATCHES "PLATFORM_DESKTOP") target_link_libraries(${RAYLIB} GL) endif() - # Add in GLFW as a linking target - target_link_libraries(${RAYLIB} glfw) - # Library file & Header set_target_properties(${RAYLIB} PROPERTIES PUBLIC_HEADER "raylib.h") install( diff --git a/src/gestures.h b/src/gestures.h index 2e343154..e2f004e2 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -140,9 +140,6 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang #if defined(GESTURES_IMPLEMENTATION) -#include // Required for: atan2(), sqrt() -#include // Required for: uint64_t - #if defined(_WIN32) // Functions required to query time on Windows int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); @@ -154,6 +151,9 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang #endif #include // Required for: timespec #include // Required for: clock_gettime() + + #include // Required for: atan2(), sqrt() + #include // Required for: uint64_t #endif //---------------------------------------------------------------------------------- diff --git a/src/rglfw.c b/src/rglfw.c index b1b4eed7..83e0021b 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -86,5 +86,5 @@ #include "external/glfw/src/posix_thread.c" #include "external/glfw/src/nsgl_context.m" #include "external/glfw/src/egl_context.c" - #include "external/glfw/src/osmesa_context.c.m" + #include "external/glfw/src/osmesa_context.c" #endif diff --git a/utils.cmake b/utils.cmake index c902f60e..f260fa5e 100644 --- a/utils.cmake +++ b/utils.cmake @@ -6,10 +6,6 @@ if(UNIX AND NOT APPLE) set(LINUX TRUE) endif() -# Need GLFW 3.2.1 -find_package(glfw3 3.2.1 REQUIRED) - - # Linking for OS X -framework options # Will do nothing on other OSes function(link_os_x_frameworks binary) @@ -40,9 +36,6 @@ function(link_libraries_to_executable executable) # TODO windows endif() - # Add in GLFW as a linking target - target_link_libraries(${executable} glfw) - # And raylib target_link_libraries(${executable} raylib) endfunction() From 1e1b20c889a53d24cfc37880bf6e6bba46f2ae78 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 22 Nov 2017 23:32:08 +0100 Subject: [PATCH 038/139] Add AppVeyor CI for automatic Windows Builds We already have automatic Linux and macOS build via Travis CI. This adds the same for Windows x86 and x86_64 with both Microsoft Visual Studio 2015 as well as MinGW-w64. --- README.md | 1 + appveyor.yml | 65 ++++++++++++++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 1 + 3 files changed, 67 insertions(+) create mode 100644 appveyor.yml diff --git a/README.md b/README.md index 5b5171aa..febd8972 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ no fancy interface, no visual helpers, no auto-debugging... just coding in the m pure spartan-programmers way. Are you ready to learn? Jump to [code examples!](http://www.raylib.com/examples.html) [![Build Status](https://travis-ci.org/raysan5/raylib.svg?branch=develop)](https://travis-ci.org/raysan5/raylib) + features -------- diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..36f161c3 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,65 @@ +#os: Visual Studio 2015 + +clone_depth: 5 + +cache: + - C:\ProgramData\chocolatey\bin -> appveyor.yml + - C:\ProgramData\chocolatey\lib -> appveyor.yml + +init: + - cmake -E remove c:\programdata\chocolatey\bin\cpack.exe + - set PATH=%PATH:C:\Program Files (x86)\Git\usr\bin;=% + - set PATH=%PATH:C:\Program Files\Git\usr\bin;=% + - set PATH=%prefix_dir%\bin;%PATH% + +environment: + matrix: + - compiler: MinGW-w64 + bits: 32 + prefix_dir: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32 + - compiler: MinGW-w64 + bits: 64 + prefix_dir: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64 + - compiler: MSVC15 + bits: 32 + - compiler: MSVC15 + bits: 64 + +before_build: + - appveyor DownloadFile http://openal-soft.org/openal-binaries/openal-soft-1.17.2-bin.zip + - 7z x openal-soft-1.17.2-bin.zip + - move openal-soft-1.17.2-bin src\external\openal + - if [%COMPILER%]==[MinGW-w64] set CFLAGS=-m%BITS% & set LDFLAGS=-m%BITS% & set GENERATOR="MinGW Makefiles" + - if [%COMPILER%]==[MSVC15] if [%BITS%]==[32] set GENERATOR="Visual Studio 14 2015" + - if [%COMPILER%]==[MSVC15] if [%BITS%]==[64] set GENERATOR="Visual Studio 14 2015 Win64" + - set VERBOSE=1 + - mkdir build + - cd build + +build_script: + - cmake -G %GENERATOR% -DBUILD_EXAMPLES=OFF -DBUILD_GAMES=OFF .. + - cmake --build . --target install + +after_build: +# - cmake --build . --target package + +before_test: + +test_script: + +#artifacts: +# - path: 'build\*.zip' +# +#deploy: +# description: 'Automatic build by CI' +# provider: GitHub +# auth_token: +# secure: XXX +# artifact: /.*\.zip/ +# draft: false +# prerelease: false +# force_update: true +# on: +# branch: master +# appveyor_repo_tag: true # deploy on tag push only +# diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f362b52f..fc1e4ca8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,6 +21,7 @@ set_property(CACHE OPENGL_VERSION PROPERTY STRINGS "3.3" "2.1" "1.1" "ES 2.0") ### Config options ### include_directories(external/glfw/include) +include_directories(external/openal/include) # For use with AppVeyor on Windows # Translate the config options to what raylib wants if(${PLATFORM} MATCHES "Desktop") From 17c91bad6f4c44c93933190eba5f08b69b257a67 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 23 Nov 2017 07:44:55 +0100 Subject: [PATCH 039/139] Disable CRT "secure" warnings Suppresses 88 of the 213 warnings reported when compiling with MSVC 2015 on AppVeyor. --- src/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fc1e4ca8..6ab8e606 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,6 +44,8 @@ if(${PLATFORM} MATCHES "Desktop") set(GRAPHICS "GRAPHICS_API_OPENGL_33") set_source_files_properties(rglfw.c PROPERTIES COMPILE_FLAGS "-x objective-c") link_libraries("-framework CoreFoundation -framework Cocoa -framework IOKit -framework CoreVideo") + elseif(WIN32) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif() elseif(${PLATFORM} MATCHES "Web") set(PLATFORM "PLATFORM_WEB") From 83029225d60044a3c194d6168cb7e6ca950fb963 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 23 Nov 2017 10:13:40 +0100 Subject: [PATCH 040/139] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index febd8972..00955d3e 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ no fancy interface, no visual helpers, no auto-debugging... just coding in the m pure spartan-programmers way. Are you ready to learn? Jump to [code examples!](http://www.raylib.com/examples.html) [![Build Status](https://travis-ci.org/raysan5/raylib.svg?branch=develop)](https://travis-ci.org/raysan5/raylib) - +![https://ci.appveyor.com/api/projects/status/github/raysan5/raylib?svg=true](https://ci.appveyor.com/api/projects/status/github/raysan5/raylib?svg=true) features -------- From f9d9ff7e483e1758a8b3d53d27b2b6f56bca0744 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 23 Nov 2017 10:14:53 +0100 Subject: [PATCH 041/139] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 00955d3e..7e47384f 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ no fancy interface, no visual helpers, no auto-debugging... just coding in the m pure spartan-programmers way. Are you ready to learn? Jump to [code examples!](http://www.raylib.com/examples.html) [![Build Status](https://travis-ci.org/raysan5/raylib.svg?branch=develop)](https://travis-ci.org/raysan5/raylib) -![https://ci.appveyor.com/api/projects/status/github/raysan5/raylib?svg=true](https://ci.appveyor.com/api/projects/status/github/raysan5/raylib?svg=true) +[![https://ci.appveyor.com/api/projects/status/github/raysan5/raylib?svg=true](https://ci.appveyor.com/api/projects/status/github/raysan5/raylib?svg=true)](https://ci.appveyor.com/project/raysan5/raylib) features -------- From 589cec0dd585bae24bd872e70a3bcf64a95e5b1a Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 24 Nov 2017 12:40:08 +0100 Subject: [PATCH 042/139] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 7e47384f..0be62fda 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,9 @@ pure spartan-programmers way. Are you ready to learn? Jump to [code examples!](h [![Build Status](https://travis-ci.org/raysan5/raylib.svg?branch=develop)](https://travis-ci.org/raysan5/raylib) [![https://ci.appveyor.com/api/projects/status/github/raysan5/raylib?svg=true](https://ci.appveyor.com/api/projects/status/github/raysan5/raylib?svg=true)](https://ci.appveyor.com/project/raysan5/raylib) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/raylib/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![License](https://img.shields.io/badge/license-zlib%2Flibpng-blue.svg)](LICENSE.md) +[![Twitter URL](https://img.shields.io/twitter/url/http/shields.io.svg?style=social&label=Follow)](https://twitter.com/raysan5) features -------- From 5463e14886456e362594250d9d5aa548a462eb20 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 24 Nov 2017 21:54:00 +1000 Subject: [PATCH 043/139] Audio: Fix a bug with AudioStreams. This bug is a result of the buffer of an AudioStream being smaller than that of a period of the backend playback device. In this situation, AudioStream's would have pauses between buffer updates because the backend is not able to re-fill the AudioStream buffer's quick enough due to it's periods being longer than the AudioStream buffer. --- src/audio.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/audio.c b/src/audio.c index 6065bf00..1e8d09e7 100644 --- a/src/audio.c +++ b/src/audio.c @@ -426,10 +426,11 @@ void InitAudioDevice(void) } TraceLog(LOG_INFO, "Audio device initialized successfully: %s", device.name); - TraceLog(LOG_INFO, "Audio backend: %s", mal_get_backend_name(context.backend)); - TraceLog(LOG_INFO, "Audio format: %s", mal_get_format_name(device.format)); - TraceLog(LOG_INFO, "Audio channels: %d", device.channels); - TraceLog(LOG_INFO, "Audio sample rate: %d", device.sampleRate); + TraceLog(LOG_INFO, "Audio backend: mini_al / %s", mal_get_backend_name(context.backend)); + TraceLog(LOG_INFO, "Audio format: %s -> %s", mal_get_format_name(device.format), mal_get_format_name(device.internalFormat)); + TraceLog(LOG_INFO, "Audio channels: %d -> %d", device.channels, device.internalChannels); + TraceLog(LOG_INFO, "Audio sample rate: %d -> %d", device.sampleRate, device.internalSampleRate); + TraceLog(LOG_INFO, "Audio buffer size: %d", device.bufferSizeInFrames); isAudioInitialized = MAL_TRUE; #else @@ -1501,14 +1502,16 @@ void UpdateMusicStream(Music music) #if USE_MINI_AL bool streamEnding = false; + unsigned int subBufferSizeInFrames = ((AudioBuffer*)music->stream.audioBuffer)->bufferSizeInFrames / 2; + // NOTE: Using dynamic allocation because it could require more than 16KB - void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, 1); + void *pcm = calloc(subBufferSizeInFrames*music->stream.sampleSize/8*music->stream.channels, 1); int samplesCount = 0; // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts while (IsAudioBufferProcessed(music->stream)) { - if (music->samplesLeft >= AUDIO_BUFFER_SIZE) samplesCount = AUDIO_BUFFER_SIZE; + if (music->samplesLeft >= subBufferSizeInFrames) samplesCount = subBufferSizeInFrames; else samplesCount = music->samplesLeft; // TODO: Really don't like ctxType thingy... @@ -1750,7 +1753,14 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un #if USE_MINI_AL mal_format formatIn = ((stream.sampleSize == 8) ? mal_format_u8 : ((stream.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); - AudioBuffer* audioBuffer = CreateAudioBuffer(formatIn, stream.channels, stream.sampleRate, AUDIO_BUFFER_SIZE*2, AUDIO_BUFFER_USAGE_STREAM); + // The size of a streaming buffer must be at least double the size of a period. + unsigned int periodSize = device.bufferSizeInFrames / device.periods; + unsigned int subBufferSize = AUDIO_BUFFER_SIZE; + if (subBufferSize < periodSize) { + subBufferSize = periodSize; + } + + AudioBuffer* audioBuffer = CreateAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM); if (audioBuffer == NULL) { TraceLog(LOG_ERROR, "InitAudioStream() : Failed to create audio buffer"); From a0d9913c7cf2dce11f8d45e38923c69eae5d6f5e Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 24 Nov 2017 22:13:33 +1000 Subject: [PATCH 044/139] Potential fixes for audio on RPI and Emscripten builds. --- src/audio.c | 10 ++++++++++ src/external/mini_al.h | 11 +++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/audio.c b/src/audio.c index 1e8d09e7..497deaf8 100644 --- a/src/audio.c +++ b/src/audio.c @@ -393,14 +393,23 @@ void InitAudioDevice(void) mal_result result = mal_context_init(NULL, 0, &contextConfig, &context); if (result != MAL_SUCCESS) { + TraceLog(LOG_ERROR, "Failed to initialize audio context"); return; } // Device. Using the default device. Format is floating point because it simplifies mixing. mal_device_config deviceConfig = mal_device_config_init(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, OnSendAudioDataToDevice); + + // Special case for PLATFORM_RPI. +#if defined(PLATFORM_RPI) + deviceConfig.alsa.noMMap = MAL_TRUE; + deviceConfig.bufferSizeInFrames = 2048; +#endif + result = mal_device_init(&context, mal_device_type_playback, NULL, &deviceConfig, NULL, &device); if (result != MAL_SUCCESS) { + TraceLog(LOG_ERROR, "Failed to initialize audio playback device"); mal_context_uninit(&context); return; } @@ -410,6 +419,7 @@ void InitAudioDevice(void) result = mal_device_start(&device); if (result != MAL_SUCCESS) { + TraceLog(LOG_ERROR, "Failed to start audio playback device"); mal_device_uninit(&device); mal_context_uninit(&context); return; diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 164709d9..1779e707 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -8634,7 +8634,7 @@ mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, mal // SDL wants the buffer size to be a power of 2. The SDL_AudioSpec property for this is only a Uint16, so we need // to explicitly clamp this because it will be easy to overflow. - mal_uint32 bufferSize = pConfig->bufferSizeInFrames * pConfig->periods * pConfig->channels; + mal_uint32 bufferSize = pConfig->bufferSizeInFrames; if (bufferSize > 32768) { bufferSize = 32768; } else { @@ -8696,7 +8696,7 @@ mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, mal pDevice->internalFormat = mal_format_from_sdl(obtainedSpec.format); pDevice->internalChannels = obtainedSpec.channels; pDevice->internalSampleRate = (mal_uint32)obtainedSpec.freq; - pDevice->bufferSizeInFrames = obtainedSpec.samples / obtainedSpec.channels; + pDevice->bufferSizeInFrames = obtainedSpec.samples; pDevice->periods = 1; // SDL doesn't seem to tell us what the period count is. Just set this 1. #if 0 @@ -10980,6 +10980,7 @@ const char* mal_get_backend_name(mal_backend backend) case mal_backend_oss: return "OSS"; case mal_backend_opensl: return "OpenSL|ES"; case mal_backend_openal: return "OpenAL"; + case mal_backend_sdl: return "SDL"; default: return "Unknown"; } } @@ -11197,7 +11198,8 @@ void mal_pcm_s32_to_f32(float* pOut, const int* pIn, unsigned int count) for (unsigned int i = 0; i < count; ++i) { int x = pIn[i]; double t; - t = (double)(x + 2147483648LL); + t = (double)(x + 2147483647); + t = t + 1; t = t * 0.0000000004656612873077392578125; r = (float)(t - 1); pOut[i] = (float)r; @@ -11255,7 +11257,8 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); c = c + 1; t = (mal_int64)(c * 2147483647.5); - r = (int)(t - 2147483648LL); + t = t - 2147483647; + r = (int)(t - 1); pOut[i] = (int)r; } } From 44376c04fa8ed5bc9ca48598afa1d177d169fa32 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 11 Oct 2017 22:33:09 +0200 Subject: [PATCH 045/139] Generate and install pkg-config pc file After installation, compiling new programs is possible with $ cc game.c `pkg-config --static --libs --cflags raylib` or $ cc game.c `pkg-config --libs --cflags raylib` depending on configuration Also adds following configuration options: - WITH_PIC "Compile static library as position-independent code" - STATIC_RAYLIB "Build raylib as a static library" - MACOS_FATLIB "Build fat library for both i386 and x86_64 on macOS" --- .travis.yml | 8 +-- appveyor.yml | 2 +- raylib.pc.in | 13 +++++ src/CMakeLists.txt | 124 ++++++++++++++++++++++++++++++--------------- utils.cmake | 40 +++++++-------- 5 files changed, 117 insertions(+), 70 deletions(-) create mode 100644 raylib.pc.in diff --git a/.travis.yml b/.travis.yml index 8b122c47..ce4998c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,9 @@ env: global: - VERBOSE=1 matrix: - - CFLAGS=-m64 - - CFLAGS=-m32 - + - CFLAGS=-m64 SHARED=ON + - CFLAGS=-m32 SHARED=OFF +# We don't install x11 32-bit libraries, so skip shared libraries on -m32 before_script: - export CFLAGS="-std=gnu99 $CFLAGS" @@ -32,7 +32,7 @@ before_install: script: - mkdir build - cd build - - cmake -DBUILD_EXAMPLES=OFF -DBUILD_GAMES=OFF .. + - cmake -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=$SHARED -DBUILD_EXAMPLES=OFF -DBUILD_GAMES=OFF .. - make # - make package # - sudo make install diff --git a/appveyor.yml b/appveyor.yml index 36f161c3..864d0c68 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -37,7 +37,7 @@ before_build: - cd build build_script: - - cmake -G %GENERATOR% -DBUILD_EXAMPLES=OFF -DBUILD_GAMES=OFF .. + - cmake -G %GENERATOR% -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=OFF -DBUILD_EXAMPLES=OFF -DBUILD_GAMES=OFF .. - cmake --build . --target install after_build: diff --git a/raylib.pc.in b/raylib.pc.in new file mode 100644 index 00000000..0472c283 --- /dev/null +++ b/raylib.pc.in @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: raylib +Description: Simple and easy-to-use library to learn videogames programming +URL: https://github.com/raysan5/raylib +Version: @PROJECT_VERSION@ +Libs: -L${libdir} -lraylib +Libs.private:@PKG_CONFIG_LIBS_PRIVATE@ +Requires.private: +Cflags: -I${includedir} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6ab8e606..b29c29fc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,8 +8,17 @@ set(RAYLIB raylib) # Name of the generated library ### Config options ### -# Build a static or shared raylib? +# Shared library is always PIC. Static library should be PIC too if linked into a shared library +set(WITH_PIC OFF CACHE BOOL "Compile static library as position-independent code" OFF) +# Build a static and/or shared raylib? set(SHARED_RAYLIB OFF CACHE BOOL "Build raylib as a dynamic library") +set(STATIC_RAYLIB ON CACHE BOOL "Build raylib as a static library") +set(MACOS_FATLIB ON CACHE BOOL "Build fat library for both i386 and x86_64 on macOS") + +if(NOT (STATIC_RAYLIB OR SHARED_RAYLIB)) + message(FATAL_ERROR "Nothing to do if both -DSHARED_RAYLIB=OFF and -DSTATIC_RAYLIB=OFF...") +endif() + # Platform set(PLATFORM "Desktop" CACHE STRING "Platform to build for.") @@ -66,6 +75,14 @@ elseif(${PLATFORM} MATCHES "Raspberry Pi") set(GRAPHICS "GRAPHICS_API_OPENGL_ES2") endif() +if(BUILD_MACOS_FATLIB) + if (CMAKE_OSX_ARCHITECTURES) + message(FATAL_ERROR "User supplied -DCMAKE_OSX_ARCHITECTURES overrides BUILD_MACOS_FATLIB=ON") + else() + SET(CMAKE_OSX_ARCHITECTURES "x86_64;i386") + endif() +endif() + # Get the sources together file(GLOB raylib_sources *.c) file(GLOB stb_vorbis external/stb_vorbis.c) @@ -73,40 +90,72 @@ set(sources ${raylib_sources} ${stb_vorbis}) # Which platform? if(${PLATFORM} MATCHES "PLATFORM_DESKTOP") - # Build a static or shared raylib? - # TODO clean this up a bit? - if(${SHARED_RAYLIB}) - # Shared library - add_library(${RAYLIB} SHARED ${sources}) - - # Will link -framework (if on OS X) - link_os_x_frameworks(raylib) - else() - # Static library - add_library(${RAYLIB} STATIC ${sources}) - - if(LINUX) - # On Linux, need to link a few extra things for static - target_link_libraries(${RAYLIB} m pthread dl) - target_link_libraries(${RAYLIB} X11 Xrandr Xinerama Xi Xxf86vm Xcursor) # X11 stuff - endif() - endif() - - # Always need to link OpenAL and OpenGL + if(LINUX) - # Elsewhere (such as Linux), need `-lopenal -lGL` - target_link_libraries(${RAYLIB} openal) - target_link_libraries(${RAYLIB} GL) + foreach(L ${LIBS_PRIVATE}) + set(PKG_CONFIG_LIBS_PRIVATE "${PKG_CONFIG_LIBS_PRIVATE} -l${L}") + endforeach(L) + + elseif(APPLE) + # TODO extract framework location and name from ${LIBS_PRIVATE} + # and specify them as -F and -framework instead of hardcoding + foreach(F OpenGL OpenAL Cocoa) + set(PKG_CONFIG_LIBS_PRIVATE "${PKG_CONFIG_LIBS_PRIVATE} -framework ${F}") + endforeach(F) + endif() - - # Library file & Header - set_target_properties(${RAYLIB} PROPERTIES PUBLIC_HEADER "raylib.h") - install( - TARGETS ${RAYLIB} - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - PUBLIC_HEADER DESTINATION include - ) + + if(${SHARED_RAYLIB}) + add_library(${RAYLIB}_shared SHARED ${sources}) + + target_compile_definitions(${RAYLIB}_shared + PUBLIC ${PLATFORM} + PUBLIC ${GRAPHICS} + ) + + set_property(TARGET ${RAYLIB}_shared PROPERTY POSITION_INDEPENDENT_CODE ON) + set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + set(CMAKE_MACOSX_RPATH ON) + + target_link_libraries(${RAYLIB}_shared ${LIBS_PRIVATE}) + set_target_properties(${RAYLIB}_shared PROPERTIES PUBLIC_HEADER "raylib.h") + if(WIN32) + install( + TARGETS ${RAYLIB}_shared + RUNTIME DESTINATION lib + PUBLIC_HEADER DESTINATION include + ) + else() # Keep lib*.(a|dll) name, but avoid *.lib files overwriting each other on Windows + set_target_properties(${RAYLIB}_shared PROPERTIES OUTPUT_NAME ${RAYLIB}) + install( + TARGETS ${RAYLIB}_shared + LIBRARY DESTINATION lib + PUBLIC_HEADER DESTINATION include + ) + endif() + endif(${SHARED_RAYLIB}) + + if(${STATIC_RAYLIB}) + add_library(${RAYLIB} STATIC ${sources}) + + target_compile_definitions(${RAYLIB} + PUBLIC ${PLATFORM} + PUBLIC ${GRAPHICS} + ) + + if (WITH_PIC) + set_property(TARGET ${RAYLIB} PROPERTY POSITION_INDEPENDENT_CODE ON) + endif() + set_target_properties(${RAYLIB} PROPERTIES PUBLIC_HEADER "raylib.h") + install(TARGETS ${RAYLIB} + ARCHIVE DESTINATION lib + PUBLIC_HEADER DESTINATION include + ) + endif(${STATIC_RAYLIB}) + + configure_file(../raylib.pc.in raylib.pc @ONLY) + install(FILES ${CMAKE_BINARY_DIR}/release/raylib.pc DESTINATION lib/pkgconfig) # Copy the header files to the build directory file(COPY "raylib.h" DESTINATION ".") @@ -119,15 +168,6 @@ elseif(${PLATFORM} MATCHES "PLATFORM_WEB") add_executable(${RAYLIB} ${sources}) endif() - -# Set the compile flags to raylib -target_compile_definitions(${RAYLIB} - PUBLIC ${PLATFORM} - PUBLIC ${GRAPHICS} -) - - - # Print the flags for the user message(STATUS "Compiling with the flags:") message(STATUS " PLATFORM=" ${PLATFORM}) diff --git a/utils.cmake b/utils.cmake index f260fa5e..54221b9c 100644 --- a/utils.cmake +++ b/utils.cmake @@ -1,5 +1,5 @@ # All sorts of things that we need cross project -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 2.8.0) # Detect linux if(UNIX AND NOT APPLE) @@ -8,33 +8,27 @@ endif() # Linking for OS X -framework options # Will do nothing on other OSes -function(link_os_x_frameworks binary) - if(APPLE) - find_library(OPENGL_LIBRARY OpenGL) - find_library(OPENAL_LIBRARY OpenAL) - find_library(COCOA_LIBRARY Cocoa) - - set(OSX_FRAMEWORKS ${OPENGL_LIBRARY} ${OPENAL_LIBRARY} ${COCOA_LIBRARY}) - target_link_libraries(${binary} ${OSX_FRAMEWORKS}) - endif() -endfunction() +if(APPLE) + find_library(OPENGL_LIBRARY OpenGL) + find_library(OPENAL_LIBRARY OpenAL) + find_library(COCOA_LIBRARY Cocoa) + set(LIBS_PRIVATE ${OPENGL_LIBRARY} ${OPENAL_LIBRARY} ${COCOA_LIBRARY}) +elseif(LINUX) + # Elsewhere (such as Linux), need `-lopenal -lGL`, etc... + set(LIBS_PRIVATE + m pthread dl + openal + GL + X11 Xrandr Xinerama Xi Xxf86vm Xcursor) # X11 stuff +else() + # TODO Windows +endif() # Do the linking for executables that are meant to link raylib function(link_libraries_to_executable executable) # Link the libraries - if(APPLE) - # OS X, we use frameworks - link_os_x_frameworks(${executable}) - elseif(LINUX) - # Elsewhere (such as Linux), need `-lopenal -lGL`, etc... - target_link_libraries(${executable} m pthread dl) - target_link_libraries(${executable} openal) - target_link_libraries(${executable} GL) - target_link_libraries(${executable} X11 Xrandr Xinerama Xi Xxf86vm Xcursor) # X11 stuff - else() - # TODO windows - endif() + target_link_libraries(${executable} ${LIBS_PRIVATE}) # And raylib target_link_libraries(${executable} raylib) From 49c5a433df48c1b9efafb70e51724c2fc3a5e608 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Fri, 24 Nov 2017 19:57:44 +0100 Subject: [PATCH 046/139] Setup CMake package target and CI auto-deploy tags cmake --build . --target package # or make package if make is used can now be used to create binary packages for raylib. AppVeyor and Travis CI are configured to push the artifacts that result from building git tags to the related Github releases page. --- .travis.yml | 52 ++++++++++++++++++++++++----------------- README.md | 10 ++++---- appveyor.yml | 58 ++++++++++++++++++++++++---------------------- raylib.pc.in | 2 +- src/CMakeLists.txt | 16 +++++++++++-- 5 files changed, 82 insertions(+), 56 deletions(-) diff --git a/.travis.yml b/.travis.yml index ce4998c7..40817fba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,38 +12,48 @@ os: env: global: - VERBOSE=1 - matrix: - - CFLAGS=-m64 SHARED=ON - - CFLAGS=-m32 SHARED=OFF -# We don't install x11 32-bit libraries, so skip shared libraries on -m32 + matrix: # We don't install x11 32-bit libraries, so skip shared libraries on -m32 + - ARCH=i386 SHARED=OFF + - ARCH=amd64 SHARED=ON + +matrix: + exclude: # This is already covered by building universal (fat) libraries by default + - os: osx + env: ARCH=i386 SHARED=OFF + before_script: - - export CFLAGS="-std=gnu99 $CFLAGS" + - export CFLAGS="-std=gnu99" before_install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -y gcc-multilib libopenal-dev libxcursor-dev libxinerama-dev - mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev libglew-dev; + mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev + libgl1-mesa-dev libglu1-mesa-dev libglew-dev; + export RAYLIB_PACKAGE_SUFFIX="-Linux-$ARCH"; + if [ "$ARCH" == "i386" ]; then export CFLAGS="$CFLAGS -m32"; fi; + if [ "$ARCH" == "amd64" ]; then export CFLAGS="$CFLAGS -m64"; fi; fi - - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; brew install glfw; fi + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then export RAYLIB_PACKAGE_SUFFIX="-macOS"; fi - "$CC --version" script: - mkdir build - cd build - - cmake -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=$SHARED -DBUILD_EXAMPLES=OFF -DBUILD_GAMES=OFF .. + - cmake -DMACOS_FATLIB=ON -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=$SHARED -DBUILD_EXAMPLES=OFF -DBUILD_GAMES=OFF .. - make -# - make package -# - sudo make install -# -#deploy: -# provider: releases -# api_key: -# secure: XXX -# file_glob: true -# file: raylib-*.tar.gz -# skip_cleanup: true -# on: -# branch: master -# tags: true + - make package + +deploy: + provider: releases + api_key: + secure: LvqUIAN/3dJul+Ra2iK3tSaNG5IwsNMmGIwVMy0DK5IBCxiQPBc9pWGiE30RTBPt6Z+N4BhMEE8DtUl+vnISlMoHWNIIhF2zwC66hs/F7zY7qEITMRSmfiLcqxQysknFOnJB06CATgXcFqlEo9j+t4abrG/f3qcb92J4O2uNz336Au2myTx93Q5MxbyA7KiUuEutFnb2dWiPCY4d+sGeXEfsiD2R7aj/8MaWOkoGdZVrTkI9juMgvpImkjQBArvqdjUMeT3MsRrwgOIq5v2GFV9dOl8k1WzPeT8B2JHh00ed/o1/wuFq/cLLOxtYo2+Pv3+xatOrlexoX0WkDm7C9/L1W5U4rLexU3CQ9mMBmHPnp6k/WXZ5QXEE4uUF0+LpN3XlIXzFpdZmZiVV8VLxg2WvyncMmivYiu7/MTkyfZxyKkzwl7sZZslzHA9kOGedGaN7b7/2B77OFHoQK8lKfdFml7jJnarh+89nenNZYMab0E8qkOJOyb2bYlDTa0/2nyxGiyymYgq6YHLNrDbhqB/1LzdgzjMliQ8ri5q9Ux2vjfcqOzhfAmcwFwnY/D6yXJWYi0DWpHZdpKl3du6dYDrypW91/yDWbwiJ/YhrE7ZunzrcB6GH/QkbuzWxdCth39rQAHih8DG01co/K3Gvi4yGjvIH5tFUpyEolMnpMiA= + file_glob: true + file: raylib-*.tar.gz + skip_cleanup: true + on: + repo: raysan5/raylib + branch: + - develop + - master diff --git a/README.md b/README.md index 0be62fda..1c078f52 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ features * Audio loading and playing with streaming support (WAV, OGG, FLAC, XM, MOD) * Multiple platforms support: Windows, Linux, Mac, **Android**, **Raspberry Pi** and **HTML5** * VR stereo rendering support with configurable HMD device parameters - * Minimal external dependencies (GLFW3, OpenGL, OpenAL) + * Minimal external dependencies (OpenGL, OpenAL) * Complete bindings to LUA ([raylib-lua](https://github.com/raysan5/raylib-lua)) and Go ([raylib-go](https://github.com/gen2brain/raylib-go)) raylib uses on its core module the outstanding [GLFW3](http://www.glfw.org/) library. The best option I found for @@ -44,10 +44,12 @@ to accomodate to Android, Raspberry Pi and HTML5. *On Raspberry Pi, Videocore API and EGL libraries are used for window/context management and raw inputs reading.* -building --------- +build and installation +---------------------- -For detailed building instructions, check [raylib Wiki](https://github.com/raysan5/raylib/wiki). +Binary releases for Windows, Linux and macOS are available at the [Github Releases](https://github.com/raysan5/raylib/releases) page. + +To build raylib yourself, check out the [raylib Wiki](https://github.com/raysan5/raylib/wiki) for detailed instructions. raylib has been developed using exclusively two tools: diff --git a/appveyor.yml b/appveyor.yml index 864d0c68..2363bd3f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,29 +10,30 @@ init: - cmake -E remove c:\programdata\chocolatey\bin\cpack.exe - set PATH=%PATH:C:\Program Files (x86)\Git\usr\bin;=% - set PATH=%PATH:C:\Program Files\Git\usr\bin;=% - - set PATH=%prefix_dir%\bin;%PATH% + - if [%BITS%]==[32] set MINGW=C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32 + - if [%BITS%]==[64] set MINGW=C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64 + - if [%COMPILER%]==[mingw] set PATH=%MINGW%\bin;%PATH% + - set RAYLIB_PACKAGE_SUFFIX=-Win%BITS%-%COMPILER% + - set VERBOSE=1 environment: matrix: - - compiler: MinGW-w64 + - compiler: mingw bits: 32 - prefix_dir: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32 - - compiler: MinGW-w64 + - compiler: mingw bits: 64 - prefix_dir: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64 - - compiler: MSVC15 + - compiler: msvc15 bits: 32 - - compiler: MSVC15 + - compiler: msvc15 bits: 64 before_build: - appveyor DownloadFile http://openal-soft.org/openal-binaries/openal-soft-1.17.2-bin.zip - 7z x openal-soft-1.17.2-bin.zip - move openal-soft-1.17.2-bin src\external\openal - - if [%COMPILER%]==[MinGW-w64] set CFLAGS=-m%BITS% & set LDFLAGS=-m%BITS% & set GENERATOR="MinGW Makefiles" - - if [%COMPILER%]==[MSVC15] if [%BITS%]==[32] set GENERATOR="Visual Studio 14 2015" - - if [%COMPILER%]==[MSVC15] if [%BITS%]==[64] set GENERATOR="Visual Studio 14 2015 Win64" - - set VERBOSE=1 + - if [%compiler%]==[mingw] set CFLAGS=-m%BITS% & set LDFLAGS=-m%BITS% & set GENERATOR="MinGW Makefiles" + - if [%COMPILER%]==[msvc15] if [%BITS%]==[32] set GENERATOR="Visual Studio 14 2015" + - if [%COMPILER%]==[msvc15] if [%BITS%]==[64] set GENERATOR="Visual Studio 14 2015 Win64" - mkdir build - cd build @@ -41,25 +42,26 @@ build_script: - cmake --build . --target install after_build: -# - cmake --build . --target package + - cmake --build . --target package before_test: test_script: -#artifacts: -# - path: 'build\*.zip' -# -#deploy: -# description: 'Automatic build by CI' -# provider: GitHub -# auth_token: -# secure: XXX -# artifact: /.*\.zip/ -# draft: false -# prerelease: false -# force_update: true -# on: -# branch: master -# appveyor_repo_tag: true # deploy on tag push only -# +artifacts: + - path: 'build\*.zip' + +deploy: + description: 'Automatic build by CI' + provider: GitHub + auth_token: + secure: lqkfPGZPK828Mmopbicrng08QaaQXAshp0a9E3bMXt8+hpA8vCfDAT3jgU8kaSsW + artifact: /.*\.zip/ + draft: false + prerelease: false + force_update: true + on: + branch: + - master + - develop + appveyor_repo_tag: true # deploy on tag push only diff --git a/raylib.pc.in b/raylib.pc.in index 0472c283..93984363 100644 --- a/raylib.pc.in +++ b/raylib.pc.in @@ -5,7 +5,7 @@ includedir=${prefix}/include Name: raylib Description: Simple and easy-to-use library to learn videogames programming -URL: https://github.com/raysan5/raylib +URL: http://github.com/raysan5/raylib Version: @PROJECT_VERSION@ Libs: -L${libdir} -lraylib Libs.private:@PKG_CONFIG_LIBS_PRIVATE@ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b29c29fc..1fec104f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,8 +2,7 @@ project(raylib) include("../utils.cmake") -set(raylib_VERSION_MAJOR 1) -set(raylib_VERSION_MINOR 8) +set(PROJECT_VERSION 1.9.0dev) set(RAYLIB raylib) # Name of the generated library @@ -173,3 +172,16 @@ message(STATUS "Compiling with the flags:") message(STATUS " PLATFORM=" ${PLATFORM}) message(STATUS " GRAPHICS=" ${GRAPHICS}) +# Packaging +SET(CPACK_PACKAGE_NAME "raylib") +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Simple and easy-to-use library to learn videogames programming") +SET(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") +SET(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") +SET(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") +SET(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") +SET(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/../README.md") +SET(CPACK_RESOURCE_FILE_WELCOME "${PROJECT_SOURCE_DIR}/../README.md") +SET(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/../LICENSE.md") +SET(CPACK_PACKAGE_FILE_NAME "raylib-${PROJECT_VERSION}$ENV{RAYLIB_PACKAGE_SUFFIX}") +SET(CPACK_GENERATOR "ZIP;TGZ") # Remove this, if you want the NSIS installer on Windows +include(CPack) From 13fa61f7d9a4be326812a77a4148472961415776 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Fri, 24 Nov 2017 22:46:23 +0100 Subject: [PATCH 047/139] CI: Only push binaries for develop branch builds ... for now. Syntax was confusing Travis CI, AppVeyor is reporting 401, so lets see if this change at least fixes Travis. If this doesn't work, it might be that @raysan5's token is required. --- .travis.yml | 4 +--- appveyor.yml | 23 ++++++++++------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 40817fba..d7124970 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,6 +54,4 @@ deploy: skip_cleanup: true on: repo: raysan5/raylib - branch: - - develop - - master + branch: develop diff --git a/appveyor.yml b/appveyor.yml index 2363bd3f..bfda4ec3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,16 +52,13 @@ artifacts: - path: 'build\*.zip' deploy: - description: 'Automatic build by CI' - provider: GitHub - auth_token: - secure: lqkfPGZPK828Mmopbicrng08QaaQXAshp0a9E3bMXt8+hpA8vCfDAT3jgU8kaSsW - artifact: /.*\.zip/ - draft: false - prerelease: false - force_update: true - on: - branch: - - master - - develop - appveyor_repo_tag: true # deploy on tag push only + - provider: GitHub + auth_token: + secure: lqkfPGZPK828Mmopbicrng08QaaQXAshp0a9E3bMXt8+hpA8vCfDAT3jgU8kaSsW + artifact: /.*\.zip/ + draft: false + prerelease: false + force_update: true + on: + branch: develop + appveyor_repo_tag: true # deploy on tag push only From d54ea107f7c1bf7c006f4782a435ba9c33e33f73 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Fri, 24 Nov 2017 23:03:02 +0100 Subject: [PATCH 048/139] [CI] Push Github artifacts only on tag Forgot that one the first time round, which created some unnecssary releases. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d7124970..af381d5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,3 +55,4 @@ deploy: on: repo: raysan5/raylib branch: develop + tags: true From 853cc6f4c96f4de94a11aa8317e98fd0e42c64fd Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 25 Nov 2017 19:40:05 +0100 Subject: [PATCH 049/139] Added authorization token --- appveyor.yml | 2 +- src/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index bfda4ec3..bee59fa5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -54,7 +54,7 @@ artifacts: deploy: - provider: GitHub auth_token: - secure: lqkfPGZPK828Mmopbicrng08QaaQXAshp0a9E3bMXt8+hpA8vCfDAT3jgU8kaSsW + secure: OxKnnT3tlkPl9365cOO84rDWU4UkHIYJc0D3r3Tv7rB3HaR2BBhlhCnl7g3nuOJy artifact: /.*\.zip/ draft: false prerelease: false diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1fec104f..47938030 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,7 +2,7 @@ project(raylib) include("../utils.cmake") -set(PROJECT_VERSION 1.9.0dev) +set(PROJECT_VERSION 1.9.1-dev) set(RAYLIB raylib) # Name of the generated library From f991a075e18df5e58bd6f6f90c1b02b5b353cbe3 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sat, 25 Nov 2017 20:27:53 +0100 Subject: [PATCH 050/139] Build examples and games on Travis CI They were disabled because they failed to build, but this patch set fixes the build on Linux and macOS. This doesn't apply to the AppVeyor build on Windows yet; it currently fails at linking with OpenAL. --- .gitignore | 5 +++++ .travis.yml | 2 +- examples/CMakeLists.txt | 21 ++++++++++++++++++++- examples/others/audio_standalone.c | 7 ++----- games/wave_collector/wave_collector.c | 4 ++-- src/CMakeLists.txt | 2 +- utils.cmake | 12 ++++++++---- 7 files changed, 39 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 331d062d..65b3020c 100644 --- a/.gitignore +++ b/.gitignore @@ -132,3 +132,8 @@ build # Ignore Android generated files and folders templates/android_project/output + +# Ignore GNU global tags +GPATH +GRTAGS +GTAGS diff --git a/.travis.yml b/.travis.yml index af381d5b..ea51039e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ before_install: script: - mkdir build - cd build - - cmake -DMACOS_FATLIB=ON -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=$SHARED -DBUILD_EXAMPLES=OFF -DBUILD_GAMES=OFF .. + - cmake -DMACOS_FATLIB=ON -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=$SHARED .. - make - make package diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 354a1373..96ce37e0 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -7,9 +7,20 @@ include("../utils.cmake") # TODO `build` directory should maybe be something else... # TODO place somewhere else? include_directories("../build/release") +include_directories("../src/external") +include_directories("../src/external/glfw/include") # Get the sources together -set(example_dirs audio core models others physac shaders text texutures) +set(example_dirs audio core models others shaders text texutures) +set(CMAKE_REQUIRED_DEFINITIONS -D_POSIX_C_SOURCE=199309L) + include(CheckSymbolExists) + check_symbol_exists(CLOCK_MONOTONIC time.h HAVE_CLOCK_MONOTONIC) + check_symbol_exists(QueryPerformanceCounter windows.h HAVE_QPC) +set(CMAKE_REQUIRED_DEFINITIONS) +if(HAVE_QPC OR HAVE_CLOCK_MONOTONIC) + set(example_dirs ${example_dirs} physac) +endif() + set(example_sources) set(example_resources) foreach(example_dir ${example_dirs}) @@ -22,6 +33,14 @@ foreach(example_dir ${example_dirs}) list(APPEND example_resources ${resources}) endforeach() +include(CheckIncludeFiles) +check_include_files(OVR_CAPI_GL.h HAVE_OCULUS_CAPI) +if(NOT HAVE_OCULUS_CAPI) + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/oculus_rift.c) +endif() +list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/standard_lighting.c) + + # Do each example foreach(example_source ${example_sources}) # Create the basename for the example diff --git a/examples/others/audio_standalone.c b/examples/others/audio_standalone.c index 0a09c988..97c3fd0d 100644 --- a/examples/others/audio_standalone.c +++ b/examples/others/audio_standalone.c @@ -26,14 +26,11 @@ ********************************************************************************************/ #include +#include "audio.h" #if defined(_WIN32) #include // Windows only, no stardard library -#endif - -#include "audio.h" - -#if defined(__linux__) +#else #include #include #include diff --git a/games/wave_collector/wave_collector.c b/games/wave_collector/wave_collector.c index d4ce33d9..e28c0b84 100644 --- a/games/wave_collector/wave_collector.c +++ b/games/wave_collector/wave_collector.c @@ -63,7 +63,7 @@ static void UpdateDrawFrame(void); // Update and Draw one frame #if defined(PLATFORM_ANDROID) void android_main(struct android_app *app) #else -int main(void) +int main(int argc, char *argv[]) #endif { // Initialization @@ -315,4 +315,4 @@ static void UpdateDrawFrame(void) EndDrawing(); //---------------------------------------------------------------------------------- -} \ No newline at end of file +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 47938030..47bee1ce 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,7 +51,7 @@ if(${PLATFORM} MATCHES "Desktop") if(APPLE) set(GRAPHICS "GRAPHICS_API_OPENGL_33") set_source_files_properties(rglfw.c PROPERTIES COMPILE_FLAGS "-x objective-c") - link_libraries("-framework CoreFoundation -framework Cocoa -framework IOKit -framework CoreVideo") + link_libraries("${LIBS_PRIVATE}") elseif(WIN32) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif() diff --git a/utils.cmake b/utils.cmake index 54221b9c..84c73fe2 100644 --- a/utils.cmake +++ b/utils.cmake @@ -12,8 +12,12 @@ if(APPLE) find_library(OPENGL_LIBRARY OpenGL) find_library(OPENAL_LIBRARY OpenAL) find_library(COCOA_LIBRARY Cocoa) + find_library(IOKIT_LIBRARY IOKit) + find_library(COREFOUNDATION_LIBRARY CoreFoundation) + find_library(COREVIDEO_LIBRARY CoreVideo) - set(LIBS_PRIVATE ${OPENGL_LIBRARY} ${OPENAL_LIBRARY} ${COCOA_LIBRARY}) + set(LIBS_PRIVATE ${OPENGL_LIBRARY} ${OPENAL_LIBRARY} ${COCOA_LIBRARY} + ${IOKIT_LIBRARY} ${COREFOUNDATION_LIBRARY} ${COREVIDEO_LIBRARY}) elseif(LINUX) # Elsewhere (such as Linux), need `-lopenal -lGL`, etc... set(LIBS_PRIVATE @@ -27,10 +31,10 @@ endif() # Do the linking for executables that are meant to link raylib function(link_libraries_to_executable executable) - # Link the libraries - target_link_libraries(${executable} ${LIBS_PRIVATE}) - # And raylib target_link_libraries(${executable} raylib) + + # Link the libraries + target_link_libraries(${executable} ${LIBS_PRIVATE}) endfunction() From a78a1504a8f98cceb2a3b44c6e7f7a285df07b24 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sun, 26 Nov 2017 10:42:19 +0100 Subject: [PATCH 051/139] Note that raylib can be installed via Homebrew [ci skip] --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c078f52..db8e9698 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,9 @@ to accomodate to Android, Raspberry Pi and HTML5. build and installation ---------------------- -Binary releases for Windows, Linux and macOS are available at the [Github Releases](https://github.com/raysan5/raylib/releases) page. +Binary releases for Windows, Linux and macOS are available at the [Github Releases](https://github.com/raysan5/raylib/releases) page. Raylib is also available via following package managers: + + * Homebrew: `brew install raylib` To build raylib yourself, check out the [raylib Wiki](https://github.com/raysan5/raylib/wiki) for detailed instructions. From ca921e5a53fdd3412f5f81e3a739f54d68cb63a7 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 27 Nov 2017 01:24:08 +0100 Subject: [PATCH 052/139] CMake: Explicitly ask for C99 support Otherwise using a compiler that defaults to -std=c89 or -std=gnu89 will fail. Example: http://www.cpantesters.org/cpan/report/abb85066-d283-11e7-9926-b2f4efb9c382 Apparently, -m32 Travis CI build was broken: -m32 was overridden by -std=gnu99. This fixes that. --- .travis.yml | 36 ++++++++++++++++-------------------- CMakeLists.txt | 8 ++++++++ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index ea51039e..28641b38 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,28 +1,24 @@ language: c -sudo: required dist: trusty git: depth: 3 -os: - - osx - - linux +# TODO we could use a 32 bit Docker container for running true 32-bit tests +# services: - docker -env: - global: - - VERBOSE=1 - matrix: # We don't install x11 32-bit libraries, so skip shared libraries on -m32 - - ARCH=i386 SHARED=OFF - - ARCH=amd64 SHARED=ON - -matrix: - exclude: # This is already covered by building universal (fat) libraries by default - - os: osx - env: ARCH=i386 SHARED=OFF +matrix: # We don't install x11 32-bit libraries, so skip shared libraries on -m32 + include: + - os: linux + env: ARCH=i386 SHARED=OFF EXAMPLES=OFF + sudo: required + - os: linux + env: ARCH=amd64 SHARED=ON EXAMPLES=ON + sudo: required + - os: osx + env: ARCH=amd64 SHARED=ON EXAMPLES=ON before_script: - - export CFLAGS="-std=gnu99" before_install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then @@ -32,8 +28,8 @@ before_install: mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev libglew-dev; export RAYLIB_PACKAGE_SUFFIX="-Linux-$ARCH"; - if [ "$ARCH" == "i386" ]; then export CFLAGS="$CFLAGS -m32"; fi; - if [ "$ARCH" == "amd64" ]; then export CFLAGS="$CFLAGS -m64"; fi; + if [ "$ARCH" == "i386" ]; then export CFLAGS="-m32"; fi; + if [ "$ARCH" == "amd64" ]; then export CFLAGS="-m64"; fi; fi - if [ "$TRAVIS_OS_NAME" == "osx" ]; then export RAYLIB_PACKAGE_SUFFIX="-macOS"; fi - "$CC --version" @@ -41,8 +37,8 @@ before_install: script: - mkdir build - cd build - - cmake -DMACOS_FATLIB=ON -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=$SHARED .. - - make + - cmake -DMACOS_FATLIB=ON -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=$SHARED -DBUILD_EXAMPLES=$EXAMPLES -DBUILD_GAMES=$EXAMPLES .. + - make VERBOSE=1 - make package deploy: diff --git a/CMakeLists.txt b/CMakeLists.txt index 0dfa0857..057481bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,14 @@ cmake_minimum_required(VERSION 3.0) set(BUILD_EXAMPLES ON CACHE BOOL "Build the examples.") set(BUILD_GAMES ON CACHE BOOL "Build the example games.") +if(CMAKE_VERSION VERSION_LESS "3.1") + if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + set(CMAKE_C_FLAGS "-std=gnu99 ${CMAKE_C_FLAGS}") + endif() +else() + set (CMAKE_C_STANDARD 99) +endif() + add_subdirectory(src release) if (${BUILD_EXAMPLES}) From c9722161d11b250006f17de62dd9ff17e46aeed4 Mon Sep 17 00:00:00 2001 From: Ray San Date: Mon, 27 Nov 2017 12:46:40 +0100 Subject: [PATCH 053/139] Support GetCurrentTime() on macOS --- src/gestures.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/gestures.h b/src/gestures.h index e2f004e2..68bdc11b 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -156,6 +156,11 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang #include // Required for: uint64_t #endif +#if defined(__APPLE__) // macOS also defines __MACH__ + #include // Required for: clock_get_time() + #include // Required for: mach_timespec_t +#endif + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -532,6 +537,22 @@ static double GetCurrentTime(void) time = ((double)nowTime/1000000.0); // Time in miliseconds #endif +#if defined(__APPLE__) + //#define CLOCK_REALTIME CALENDAR_CLOCK + //#define CLOCK_MONOTONIC SYSTEM_CLOCK + + clock_serv_t cclock; + mach_timespec_t now; + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); + + // NOTE: OS X does not have clock_gettime(), using clock_get_time() + clock_get_time(cclock, &now); + mach_port_deallocate(mach_task_self(), cclock); + uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds + + time = ((double)nowTime/1000000.0); // Time in miliseconds +#endif + return time; } From 2cf37708c024cb18267c41db3d604d570f6fe670 Mon Sep 17 00:00:00 2001 From: Martinfx Date: Wed, 29 Nov 2017 00:04:29 +0100 Subject: [PATCH 054/139] Added glfw support for FreeBSD --- src/rglfw.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/rglfw.c b/src/rglfw.c index 83e0021b..5cd2c937 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -36,6 +36,9 @@ #ifdef __linux__ #define _GLFW_X11 #endif +#ifdef __FreeBSD__ + #define _GLFW_X11 +#endif #ifdef __APPLE__ #define _GLFW_COCOA #define _GLFW_USE_CHDIR // To chdir to the Resources subdirectory of the application bundle during glfwInit @@ -77,6 +80,20 @@ #include "external/glfw/src/osmesa_context.c" #endif +#ifdef __FreeBSD__ + #include "external/glfw/src/x11_init.c" + #include "external/glfw/src/x11_monitor.c" + #include "external/glfw/src/x11_window.c" + #include "external/glfw/src/xkb_unicode.c" + // TODO: Joistick implementation + #include "external/glfw/src/null_joystick.c" + #include "external/glfw/src/posix_time.c" + #include "external/glfw/src/posix_thread.c" + #include "external/glfw/src/glx_context.c" + #include "external/glfw/src/egl_context.c" + #include "external/glfw/src/osmesa_context.c" +#endif + #ifdef __APPLE__ #include "external/glfw/src/cocoa_init.m" #include "external/glfw/src/cocoa_joystick.m" From 2f471414c2f830e61a200ecd956f37e45ce94e96 Mon Sep 17 00:00:00 2001 From: Martinfx Date: Wed, 29 Nov 2017 00:05:39 +0100 Subject: [PATCH 055/139] Added compile with cmake for FreeBSD --- src/CMakeLists.txt | 19 +++++++++++++++---- utils.cmake | 30 ++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 47bee1ce..e4f5e8fc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,7 +5,6 @@ include("../utils.cmake") set(PROJECT_VERSION 1.9.1-dev) set(RAYLIB raylib) # Name of the generated library - ### Config options ### # Shared library is always PIC. Static library should be PIC too if linked into a shared library set(WITH_PIC OFF CACHE BOOL "Compile static library as position-independent code" OFF) @@ -18,7 +17,6 @@ if(NOT (STATIC_RAYLIB OR SHARED_RAYLIB)) message(FATAL_ERROR "Nothing to do if both -DSHARED_RAYLIB=OFF and -DSTATIC_RAYLIB=OFF...") endif() - # Platform set(PLATFORM "Desktop" CACHE STRING "Platform to build for.") set_property(CACHE PLATFORM PROPERTY STRINGS "Desktop" "Web" "Android" "Raspberry Pi") @@ -28,8 +26,14 @@ set(OPENGL_VERSION "3.3" CACHE STRING "OpenGL Version to build raylib with") set_property(CACHE OPENGL_VERSION PROPERTY STRINGS "3.3" "2.1" "1.1" "ES 2.0") ### Config options ### +if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD) + find_package(OpenGL REQUIRED) + find_package(OpenAL REQUIRED) + include_directories(${OPENGL_INCLUDE_DIR} ${OPENAL_INCLUDE_DIR}) +endif() + include_directories(external/glfw/include) -include_directories(external/openal/include) # For use with AppVeyor on Windows +include_directories(external/include) # For use with AppVeyor on Windows # Translate the config options to what raylib wants if(${PLATFORM} MATCHES "Desktop") @@ -55,6 +59,7 @@ if(${PLATFORM} MATCHES "Desktop") elseif(WIN32) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif() + elseif(${PLATFORM} MATCHES "Web") set(PLATFORM "PLATFORM_WEB") set(GRAPHICS "GRAPHICS_API_OPENGL_ES2") @@ -94,14 +99,20 @@ if(${PLATFORM} MATCHES "PLATFORM_DESKTOP") foreach(L ${LIBS_PRIVATE}) set(PKG_CONFIG_LIBS_PRIVATE "${PKG_CONFIG_LIBS_PRIVATE} -l${L}") endforeach(L) + endif() - elseif(APPLE) + if(APPLE) # TODO extract framework location and name from ${LIBS_PRIVATE} # and specify them as -F and -framework instead of hardcoding foreach(F OpenGL OpenAL Cocoa) set(PKG_CONFIG_LIBS_PRIVATE "${PKG_CONFIG_LIBS_PRIVATE} -framework ${F}") endforeach(F) + endif() + if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD) + foreach(L OpenGL OpenAL) + set(PKG_CONFIG_LIBS_PRIVATE "${PKG_CONFIG_LIBS_PRIVATE} -l${L}") + endforeach(L) endif() if(${SHARED_RAYLIB}) diff --git a/utils.cmake b/utils.cmake index 84c73fe2..43b479da 100644 --- a/utils.cmake +++ b/utils.cmake @@ -1,9 +1,8 @@ # All sorts of things that we need cross project cmake_minimum_required(VERSION 2.8.0) -# Detect linux -if(UNIX AND NOT APPLE) - set(LINUX TRUE) +if(CMAKE_SYSTEM_NAME STREQUAL Linux) + set(LINUX TRUE) endif() # Linking for OS X -framework options @@ -18,17 +17,36 @@ if(APPLE) set(LIBS_PRIVATE ${OPENGL_LIBRARY} ${OPENAL_LIBRARY} ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREFOUNDATION_LIBRARY} ${COREVIDEO_LIBRARY}) -elseif(LINUX) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL Linux) # Elsewhere (such as Linux), need `-lopenal -lGL`, etc... set(LIBS_PRIVATE m pthread dl openal GL X11 Xrandr Xinerama Xi Xxf86vm Xcursor) # X11 stuff -else() - # TODO Windows endif() +if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD) + find_package(OpenGL REQUIRED) + find_package(OpenAL REQUIRED) + include_directories(${OPENGL_INCLUDE_DIR} ${OPENAL_INCLUDE_DIR}) + + find_package(X11 REQUIRED) + find_library(OpenAL REQUIRED) + find_library(pthread NAMES pthread) + find_library(Xrandr NAMES Xrandr) + find_library(Xi NAMES Xi) + find_library(Xinerama NAMES Xinerama) + find_library(Xxf86vm NAMES Xxf86vm) + find_library(Xcursor NAMES Xcursor) + + set(LIBS_PRIVATE m ${pthread} ${OPENAL_LIBRARY} ${X11_LIBRARIES} ${Xrandr} ${Xinerama} ${Xi} ${Xxf86vm} ${Xcursor}) +endif() + +# TODO Support Windows + # Do the linking for executables that are meant to link raylib function(link_libraries_to_executable executable) # And raylib From 69a1c19735bd808c7fe5f6d546c1d238a21ccc24 Mon Sep 17 00:00:00 2001 From: Martinfx Date: Wed, 29 Nov 2017 13:17:02 +0100 Subject: [PATCH 056/139] Fixed use ${LIBS_PRIVATE} for FreeBSD --- src/CMakeLists.txt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e4f5e8fc..33f0fec5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,14 +24,8 @@ set_property(CACHE PLATFORM PROPERTY STRINGS "Desktop" "Web" "Android" "Raspberr # OpenGL version set(OPENGL_VERSION "3.3" CACHE STRING "OpenGL Version to build raylib with") set_property(CACHE OPENGL_VERSION PROPERTY STRINGS "3.3" "2.1" "1.1" "ES 2.0") + ### Config options ### - -if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD) - find_package(OpenGL REQUIRED) - find_package(OpenAL REQUIRED) - include_directories(${OPENGL_INCLUDE_DIR} ${OPENAL_INCLUDE_DIR}) -endif() - include_directories(external/glfw/include) include_directories(external/include) # For use with AppVeyor on Windows @@ -110,7 +104,7 @@ if(${PLATFORM} MATCHES "PLATFORM_DESKTOP") endif() if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD) - foreach(L OpenGL OpenAL) + foreach(L ${LIBS_PRIVATE}) set(PKG_CONFIG_LIBS_PRIVATE "${PKG_CONFIG_LIBS_PRIVATE} -l${L}") endforeach(L) endif() From 825d15b06976ef2f9a05255ecc86c04d5f73953f Mon Sep 17 00:00:00 2001 From: Martinfx Date: Wed, 29 Nov 2017 16:54:25 +0100 Subject: [PATCH 057/139] Fixed broken include for AppVeyor --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 33f0fec5..cb8af48d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,7 +27,7 @@ set_property(CACHE OPENGL_VERSION PROPERTY STRINGS "3.3" "2.1" "1.1" "ES 2.0") ### Config options ### include_directories(external/glfw/include) -include_directories(external/include) # For use with AppVeyor on Windows +include_directories(external/openal/include) # For use with AppVeyor on Windows # Translate the config options to what raylib wants if(${PLATFORM} MATCHES "Desktop") From 9a7524661fd31aef254abc1266132775aa4f0d07 Mon Sep 17 00:00:00 2001 From: Ray San Date: Thu, 30 Nov 2017 16:59:09 +0100 Subject: [PATCH 058/139] Removed GLFW3 linking and added rglfw --- src/Makefile | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/Makefile b/src/Makefile index 29b3fb75..2408f0f1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -89,6 +89,12 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif endif endif +ifeq ($(PLATFORM),PLATFORM_RPI) + UNAMEOS=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX + endif +endif ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables @@ -224,7 +230,7 @@ endif # Define compiler flags: # -O1 defines optimization level -# -Og enable debugging +# -g enable debugging # -s strip unnecessary data from build # -Wall turns on most, but not all, compiler warnings # -std=c99 defines C language mode (standard C from 1999 revision) @@ -270,7 +276,7 @@ endif # Define include paths for required headers # NOTE: Several external required libraries (stb and others) -INCLUDE_PATHS = -I. -Iexternal -Iexternal/include +INCLUDE_PATHS = -I. -Iexternal -Iexternal/include -Iexternal/glfw/include ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),FREEBSD) @@ -310,8 +316,23 @@ endif # Define all object files required with a wildcard # The wildcard takes all files that finish with ".c", # and replaces extentions with ".o", that are the object files -OBJS = $(patsubst %.c, %.o, $(wildcard *.c)) -OBJS += stb_vorbis.o +# NOTE: Some objects depend on the PLATFORM to be added or not! +# OBJS = $(patsubst %.c, %.o, $(wildcard *.c)) + +# Define object required on compilation +OBJS = core.o \ + rlgl.o \ + shapes.o \ + textures.o \ + text.o \ + models.o \ + audio.o \ + stb_vorbis.o \ + utils.o + +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + OBJS += rglfw.o +endif # Default target entry all: raylib @@ -338,24 +359,24 @@ else ifeq ($(RAYLIB_LIBTYPE),SHARED) # NOTE: If using OpenAL Soft as static library, all its dependencies must be also linked in the shared library ifeq ($(PLATFORM_OS),WINDOWS) - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/raylib.dll $(OBJS) -L$(RAYLIB_RELEASE_PATH) -lglfw3 -lgdi32 -lopenal32 -lwinmm -Wl,--out-implib,$(RAYLIB_RELEASE_PATH)/libraylibdll.a + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/raylib.dll $(OBJS) -L$(RAYLIB_RELEASE_PATH) -lgdi32 -lopenal32 -lwinmm -Wl,--out-implib,$(RAYLIB_RELEASE_PATH)/libraylibdll.a @echo "raylib dynamic library (raylib.dll) and import library (libraylibdll.a) generated!" @echo "expected OpenAL Soft static library linking" endif ifeq ($(PLATFORM_OS),LINUX) # Compile raylib to shared library version for GNU/Linux. # WARNING: you should type "make clean" before doing this target - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lglfw -lGL -lopenal -lm -lpthread -ldl + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lGL -lopenal -lm -lpthread -ldl @echo "raylib shared library generated (libraylib.so)!" endif ifeq ($(PLATFORM_OS),OSX) - $(CC) -dynamiclib -o $(RAYLIB_RELEASE_PATH)/libraylib.dylib $(OBJS) -L/usr/local/Cellar/glfw/3.2.1/lib -lglfw -framework OpenGL -framework OpenAL -framework Cocoa + $(CC) -dynamiclib -o $(RAYLIB_RELEASE_PATH)/libraylib.dylib $(OBJS) -L/usr/local/Cellar/glfw/3.2.1/lib -framework OpenGL -framework OpenAL -framework Cocoa install_name_tool -id "libraylib.dylib" $(RAYLIB_RELEASE_PATH)/libraylib.dylib @echo "raylib shared library generated (libraylib.dylib)!" endif ifeq ($(PLATFORM_OS),FREEBSD) # WARNING: you should type "gmake clean" before doing this target - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lglfw -lGL -lopenal -lpthread + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lGL -lopenal -lpthread @echo "raylib shared library generated (libraylib.so)!" endif ifeq ($(PLATFORM),PLATFORM_ANDROID) @@ -380,6 +401,10 @@ endif # Compile core module core.o : core.c raylib.h rlgl.h utils.h raymath.h gestures.h $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS) + +# Compile rglfw module +rglfw.o : rglfw.c + $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS) # Compile rlgl module rlgl.o : rlgl.c rlgl.h raymath.h From 82f88e5df9ec7384b1f6a97a144371c37f6768eb Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 3 Dec 2017 11:20:02 +1000 Subject: [PATCH 059/139] Potential fixes for Raspberry Pi. --- src/audio.c | 8 +- src/external/mini_al.h | 273 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 248 insertions(+), 33 deletions(-) diff --git a/src/audio.c b/src/audio.c index 497deaf8..d397b064 100644 --- a/src/audio.c +++ b/src/audio.c @@ -401,10 +401,10 @@ void InitAudioDevice(void) mal_device_config deviceConfig = mal_device_config_init(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, OnSendAudioDataToDevice); // Special case for PLATFORM_RPI. -#if defined(PLATFORM_RPI) - deviceConfig.alsa.noMMap = MAL_TRUE; - deviceConfig.bufferSizeInFrames = 2048; -#endif +//#if defined(PLATFORM_RPI) +// deviceConfig.alsa.noMMap = MAL_TRUE; +// deviceConfig.bufferSizeInFrames = 2048; +//#endif result = mal_device_init(&context, mal_device_type_playback, NULL, &deviceConfig, NULL, &device); if (result != MAL_SUCCESS) diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 1779e707..fd395832 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -244,12 +244,13 @@ extern "C" { #endif #endif +#define MAL_SUPPORT_SDL // All platforms support SDL. + // Explicitly disable OpenAL and Null backends for Emscripten because they both use a background thread which is not properly supported right now. #if !defined(MAL_EMSCRIPTEN) #define MAL_SUPPORT_OPENAL #define MAL_SUPPORT_NULL // All platforms support the null backend. #endif -#define MAL_SUPPORT_SDL // All platforms support SDL. #if !defined(MAL_NO_WASAPI) && defined(MAL_SUPPORT_WASAPI) @@ -758,6 +759,9 @@ struct mal_context mal_proc snd_pcm_avail; mal_proc snd_pcm_avail_update; mal_proc snd_pcm_wait; + mal_proc snd_pcm_info; + mal_proc snd_pcm_info_sizeof; + mal_proc snd_pcm_info_get_name; } alsa; #endif #ifdef MAL_SUPPORT_COREAUDIO @@ -862,8 +866,9 @@ struct mal_context mal_proc alGetBuffer3i; mal_proc alGetBufferiv; - mal_uint32 isFloat32Supported : 1; - mal_uint32 isMCFormatsSupported : 1; + mal_bool32 isEnumerationSupported : 1; + mal_bool32 isFloat32Supported : 1; + mal_bool32 isMCFormatsSupported : 1; } openal; #endif #ifdef MAL_SUPPORT_SDL @@ -1457,6 +1462,8 @@ mal_uint32 mal_dsp_read_frames_ex(mal_dsp* pDSP, mal_uint32 frameCount, void* pF // This function is useful for one-off bulk conversions, but if you're streaming data you should use the DSP APIs instead. mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut, const void* pIn, mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_uint32 frameCountIn); +// Helper for initializing a mal_dsp_config object. +mal_dsp_config mal_dsp_config_init(mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut); /////////////////////////////////////////////////////////////////////////////// // @@ -1583,7 +1590,7 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form // Disable run-time linking on certain backends. -#ifndef MAL_NO_RUNTIME_LINLING +#ifndef MAL_NO_RUNTIME_LINKING #if defined(MAL_ANDROID) || defined(MAL_EMSCRIPTEN) #define MAL_NO_RUNTIME_LINKING #endif @@ -5472,6 +5479,33 @@ static mal_result mal_device__main_loop__winmm(mal_device* pDevice) #ifdef MAL_HAS_ALSA #include +// This array allows mini_al to control device-specific default buffer sizes. This uses a scaling factor. Order is important. If +// any part of the string is present in the device's name, the associated scale will be used. +struct +{ + const char* name; + float scale; +} g_malDefaultBufferSizeScalesALSA[] = { + {"bcm2835 IEC958/HDMI", 32}, + {"bcm2835 ALSA", 32} +}; + +static float mal_find_default_buffer_size_scale__alsa(const char* deviceName) +{ + if (deviceName == NULL) { + return 1; + } + + for (size_t i = 0; i < mal_countof(g_malDefaultBufferSizeScalesALSA); ++i) { + if (strstr(g_malDefaultBufferSizeScalesALSA[i].name, deviceName) != NULL) { + return g_malDefaultBufferSizeScalesALSA[i].scale; + } + } + + return 1; +} + + typedef int (* mal_snd_pcm_open_proc) (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode); typedef int (* mal_snd_pcm_close_proc) (snd_pcm_t *pcm); typedef size_t (* mal_snd_pcm_hw_params_sizeof_proc) (void); @@ -5515,6 +5549,9 @@ typedef snd_pcm_sframes_t (* mal_snd_pcm_writei_proc) (sn typedef snd_pcm_sframes_t (* mal_snd_pcm_avail_proc) (snd_pcm_t *pcm); typedef snd_pcm_sframes_t (* mal_snd_pcm_avail_update_proc) (snd_pcm_t *pcm); typedef int (* mal_snd_pcm_wait_proc) (snd_pcm_t *pcm, int timeout); +typedef int (* mal_snd_pcm_info) (snd_pcm_t *pcm, snd_pcm_info_t* info); +typedef size_t (* mal_snd_pcm_info_sizeof) (); +typedef const char* (* mal_snd_pcm_info_get_name) (const snd_pcm_info_t* info); static snd_pcm_format_t g_mal_ALSAFormats[] = { SND_PCM_FORMAT_UNKNOWN, // mal_format_unknown @@ -5630,6 +5667,9 @@ mal_result mal_context_init__alsa(mal_context* pContext) pContext->alsa.snd_pcm_avail = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_avail"); pContext->alsa.snd_pcm_avail_update = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_avail_update"); pContext->alsa.snd_pcm_wait = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_wait"); + pContext->alsa.snd_pcm_info = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_info"); + pContext->alsa.snd_pcm_info_sizeof = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_info_sizeof"); + pContext->alsa.snd_pcm_info_get_name = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_info_get_name"); return MAL_SUCCESS; } @@ -6300,6 +6340,57 @@ static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type t } } + // We may need to scale the size of the buffer depending on the device. + if (pDevice->usingDefaultBufferSize) { + float bufferSizeScale = 1; + + snd_pcm_info_t* pInfo = (snd_pcm_info_t*)alloca(((mal_snd_pcm_info_sizeof)pContext->alsa.snd_pcm_info_sizeof)()); + mal_zero_memory(pInfo, ((mal_snd_pcm_info_sizeof)pContext->alsa.snd_pcm_info_sizeof)()); + + if (((mal_snd_pcm_info)pContext->alsa.snd_pcm_info)((snd_pcm_t*)pDevice->alsa.pPCM, pInfo) == 0) { + const char* deviceName = ((mal_snd_pcm_info_get_name)pContext->alsa.snd_pcm_info_get_name)(pInfo); + if (deviceName != NULL) { + if (strcmp(deviceName, "default") == 0) { + // It's the default device. We need to use DESC from snd_device_name_hint(). + char** ppDeviceHints; + if (((mal_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints) < 0) { + return MAL_NO_BACKEND; + } + + char** ppNextDeviceHint = ppDeviceHints; + while (*ppNextDeviceHint != NULL) { + char* NAME = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME"); + char* DESC = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC"); + char* IOID = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID"); + + mal_bool32 foundDevice = MAL_FALSE; + if ((type == mal_device_type_playback && (IOID == NULL || strcmp(IOID, "Output") == 0)) || + (type == mal_device_type_capture && (IOID != NULL && strcmp(IOID, "Input" ) == 0))) { + if (strcmp(NAME, deviceName) == 0) { + bufferSizeScale = mal_find_default_buffer_size_scale__alsa(DESC); + foundDevice = MAL_TRUE; + } + } + + free(NAME); + free(DESC); + free(IOID); + + if (foundDevice) { + break; + } + } + + ((mal_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints); + } else { + bufferSizeScale = mal_find_default_buffer_size_scale__alsa(deviceName); + } + } + + pDevice->bufferSizeInFrames = (mal_uint32)(pDevice->bufferSizeInFrames * bufferSizeScale); + } + } + // Hardware parameters. snd_pcm_hw_params_t* pHWParams = (snd_pcm_hw_params_t*)alloca(((mal_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)()); @@ -7658,6 +7749,16 @@ static mal_result mal_device__stop_backend__opensl(mal_device* pDevice) #define MAL_AL_APIENTRY #endif +#ifdef MAL_NO_RUNTIME_LINKING + #if defined(MAL_APPLE) + #include + #include + #else + #include + #include + #endif +#endif + typedef struct mal_ALCdevice_struct mal_ALCdevice; typedef struct mal_ALCcontext_struct mal_ALCcontext; typedef char mal_ALCboolean; @@ -7804,6 +7905,7 @@ mal_result mal_context_init__openal(mal_context* pContext) { mal_assert(pContext != NULL); +#ifndef MAL_NO_RUNTIME_LINKING const char* libName = NULL; #ifdef MAL_WIN32 libName = "OpenAL32.dll"; @@ -7910,13 +8012,89 @@ mal_result mal_context_init__openal(mal_context* pContext) pContext->openal.alGetBufferi = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferi"); pContext->openal.alGetBuffer3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBuffer3i"); pContext->openal.alGetBufferiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferiv"); +#else + pContext->openal.alcCreateContext = (mal_proc)alcCreateContext; + pContext->openal.alcMakeContextCurrent = (mal_proc)alcMakeContextCurrent; + pContext->openal.alcProcessContext = (mal_proc)alcProcessContext; + pContext->openal.alcSuspendContext = (mal_proc)alcSuspendContext; + pContext->openal.alcDestroyContext = (mal_proc)alcDestroyContext; + pContext->openal.alcGetCurrentContext = (mal_proc)alcGetCurrentContext; + pContext->openal.alcGetContextsDevice = (mal_proc)alcGetContextsDevice; + pContext->openal.alcOpenDevice = (mal_proc)alcOpenDevice; + pContext->openal.alcCloseDevice = (mal_proc)alcCloseDevice; + pContext->openal.alcGetError = (mal_proc)alcGetError; + pContext->openal.alcIsExtensionPresent = (mal_proc)alcIsExtensionPresent; + pContext->openal.alcGetProcAddress = (mal_proc)alcGetProcAddress; + pContext->openal.alcGetEnumValue = (mal_proc)alcGetEnumValue; + pContext->openal.alcGetString = (mal_proc)alcGetString; + pContext->openal.alcGetIntegerv = (mal_proc)alcGetIntegerv; + pContext->openal.alcCaptureOpenDevice = (mal_proc)alcCaptureOpenDevice; + pContext->openal.alcCaptureCloseDevice = (mal_proc)alcCaptureCloseDevice; + pContext->openal.alcCaptureStart = (mal_proc)alcCaptureStart; + pContext->openal.alcCaptureStop = (mal_proc)alcCaptureStop; + pContext->openal.alcCaptureSamples = (mal_proc)alcCaptureSamples; - // We depend on the ALC_ENUMERATION_EXT extension. - if (!((MAL_LPALCISEXTENSIONPRESENT)pContext->openal.alcIsExtensionPresent)(NULL, "ALC_ENUMERATION_EXT")) { - mal_dlclose(pContext->openal.hOpenAL); - return MAL_FAILED_TO_INIT_BACKEND; - } + pContext->openal.alEnable = (mal_proc)alEnable; + pContext->openal.alDisable = (mal_proc)alDisable; + pContext->openal.alIsEnabled = (mal_proc)alIsEnabled; + pContext->openal.alGetString = (mal_proc)alGetString; + pContext->openal.alGetBooleanv = (mal_proc)alGetBooleanv; + pContext->openal.alGetIntegerv = (mal_proc)alGetIntegerv; + pContext->openal.alGetFloatv = (mal_proc)alGetFloatv; + pContext->openal.alGetDoublev = (mal_proc)alGetDoublev; + pContext->openal.alGetBoolean = (mal_proc)alGetBoolean; + pContext->openal.alGetInteger = (mal_proc)alGetInteger; + pContext->openal.alGetFloat = (mal_proc)alGetFloat; + pContext->openal.alGetDouble = (mal_proc)alGetDouble; + pContext->openal.alGetError = (mal_proc)alGetError; + pContext->openal.alIsExtensionPresent = (mal_proc)alIsExtensionPresent; + pContext->openal.alGetProcAddress = (mal_proc)alGetProcAddress; + pContext->openal.alGetEnumValue = (mal_proc)alGetEnumValue; + pContext->openal.alGenSources = (mal_proc)alGenSources; + pContext->openal.alDeleteSources = (mal_proc)alDeleteSources; + pContext->openal.alIsSource = (mal_proc)alIsSource; + pContext->openal.alSourcef = (mal_proc)alSourcef; + pContext->openal.alSource3f = (mal_proc)alSource3f; + pContext->openal.alSourcefv = (mal_proc)alSourcefv; + pContext->openal.alSourcei = (mal_proc)alSourcei; + pContext->openal.alSource3i = (mal_proc)alSource3i; + pContext->openal.alSourceiv = (mal_proc)alSourceiv; + pContext->openal.alGetSourcef = (mal_proc)alGetSourcef; + pContext->openal.alGetSource3f = (mal_proc)alGetSource3f; + pContext->openal.alGetSourcefv = (mal_proc)alGetSourcefv; + pContext->openal.alGetSourcei = (mal_proc)alGetSourcei; + pContext->openal.alGetSource3i = (mal_proc)alGetSource3i; + pContext->openal.alGetSourceiv = (mal_proc)alGetSourceiv; + pContext->openal.alSourcePlayv = (mal_proc)alSourcePlayv; + pContext->openal.alSourceStopv = (mal_proc)alSourceStopv; + pContext->openal.alSourceRewindv = (mal_proc)alSourceRewindv; + pContext->openal.alSourcePausev = (mal_proc)alSourcePausev; + pContext->openal.alSourcePlay = (mal_proc)alSourcePlay; + pContext->openal.alSourceStop = (mal_proc)alSourceStop; + pContext->openal.alSourceRewind = (mal_proc)alSourceRewind; + pContext->openal.alSourcePause = (mal_proc)alSourcePause; + pContext->openal.alSourceQueueBuffers = (mal_proc)alSourceQueueBuffers; + pContext->openal.alSourceUnqueueBuffers = (mal_proc)alSourceUnqueueBuffers; + pContext->openal.alGenBuffers = (mal_proc)alGenBuffers; + pContext->openal.alDeleteBuffers = (mal_proc)alDeleteBuffers; + pContext->openal.alIsBuffer = (mal_proc)alIsBuffer; + pContext->openal.alBufferData = (mal_proc)alBufferData; + pContext->openal.alBufferf = (mal_proc)alBufferf; + pContext->openal.alBuffer3f = (mal_proc)alBuffer3f; + pContext->openal.alBufferfv = (mal_proc)alBufferfv; + pContext->openal.alBufferi = (mal_proc)alBufferi; + pContext->openal.alBuffer3i = (mal_proc)alBuffer3i; + pContext->openal.alBufferiv = (mal_proc)alBufferiv; + pContext->openal.alGetBufferf = (mal_proc)alGetBufferf; + pContext->openal.alGetBuffer3f = (mal_proc)alGetBuffer3f; + pContext->openal.alGetBufferfv = (mal_proc)alGetBufferfv; + pContext->openal.alGetBufferi = (mal_proc)alGetBufferi; + pContext->openal.alGetBuffer3i = (mal_proc)alGetBuffer3i; + pContext->openal.alGetBufferiv = (mal_proc)alGetBufferiv; +#endif + // We depend on the ALC_ENUMERATION_EXT extension for enumeration. If this is not supported we fall back to default devices. + pContext->openal.isEnumerationSupported = ((MAL_LPALCISEXTENSIONPRESENT)pContext->openal.alcIsExtensionPresent)(NULL, "ALC_ENUMERATION_EXT"); pContext->openal.isFloat32Supported = ((MAL_LPALISEXTENSIONPRESENT)pContext->openal.alIsExtensionPresent)("AL_EXT_float32"); pContext->openal.isMCFormatsSupported = ((MAL_LPALISEXTENSIONPRESENT)pContext->openal.alIsExtensionPresent)("AL_EXT_MCFORMATS"); @@ -7928,7 +8106,10 @@ mal_result mal_context_uninit__openal(mal_context* pContext) mal_assert(pContext != NULL); mal_assert(pContext->backend == mal_backend_openal); +#ifndef MAL_NO_RUNTIME_LINKING mal_dlclose(pContext->openal.hOpenAL); +#endif + return MAL_SUCCESS; } @@ -7937,35 +8118,55 @@ mal_result mal_enumerate_devices__openal(mal_context* pContext, mal_device_type mal_uint32 infoSize = *pCount; *pCount = 0; - const mal_ALCchar* pDeviceNames = ((MAL_LPALCGETSTRING)pContext->openal.alcGetString)(NULL, (type == mal_device_type_playback) ? MAL_ALC_DEVICE_SPECIFIER : MAL_ALC_CAPTURE_DEVICE_SPECIFIER); - if (pDeviceNames == NULL) { - return MAL_NO_DEVICE; - } + if (pContext->openal.isEnumerationSupported) { + const mal_ALCchar* pDeviceNames = ((MAL_LPALCGETSTRING)pContext->openal.alcGetString)(NULL, (type == mal_device_type_playback) ? MAL_ALC_DEVICE_SPECIFIER : MAL_ALC_CAPTURE_DEVICE_SPECIFIER); + if (pDeviceNames == NULL) { + return MAL_NO_DEVICE; + } - // Each device is stored in pDeviceNames, separated by a null-terminator. The string itself is double-null-terminated. - const mal_ALCchar* pNextDeviceName = pDeviceNames; - while (pNextDeviceName[0] != '\0') { + // Each device is stored in pDeviceNames, separated by a null-terminator. The string itself is double-null-terminated. + const mal_ALCchar* pNextDeviceName = pDeviceNames; + while (pNextDeviceName[0] != '\0') { + if (pInfo != NULL) { + if (infoSize > 0) { + mal_strncpy_s(pInfo->id.openal, sizeof(pInfo->id.openal), (const char*)pNextDeviceName, (size_t)-1); + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), (const char*)pNextDeviceName, (size_t)-1); + + pInfo += 1; + infoSize -= 1; + *pCount += 1; + } + } else { + *pCount += 1; + } + + // Move to the next device name. + while (*pNextDeviceName != '\0') { + pNextDeviceName += 1; + } + + // Skip past the null terminator. + pNextDeviceName += 1; + }; + } else { + // Enumeration is not supported. Use default devices. if (pInfo != NULL) { if (infoSize > 0) { - mal_strncpy_s(pInfo->id.openal, sizeof(pInfo->id.openal), (const char*)pNextDeviceName, (size_t)-1); - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), (const char*)pNextDeviceName, (size_t)-1); + if (type == mal_device_type_playback) { + pInfo->id.sdl = 0; + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1); + } else { + pInfo->id.sdl = 0; + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1); + } pInfo += 1; - infoSize -= 1; *pCount += 1; } } else { *pCount += 1; } - - // Move to the next device name. - while (*pNextDeviceName != '\0') { - pNextDeviceName += 1; - } - - // Skip past the null terminator. - pNextDeviceName += 1; - }; + } return MAL_SUCCESS; } @@ -8043,7 +8244,7 @@ mal_result mal_device_init__openal(mal_context* pContext, mal_device_type type, } if (formatAL == 0) { - return MAL_FORMAT_NOT_SUPPORTED; + return mal_context_post_error(pContext, NULL, "[OpenAL] Format not supported.", MAL_FORMAT_NOT_SUPPORTED); } bufferSizeInSamplesAL *= channelsAL; @@ -10954,6 +11155,20 @@ mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 chann return mal_dsp_read_frames_ex(&dsp, frameCountOut, pOut, MAL_TRUE); } +mal_dsp_config mal_dsp_config_init(mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut) +{ + mal_dsp_config config; + mal_zero_object(&config); + config.formatIn = formatIn; + config.channelsIn = channelsIn; + config.sampleRateIn = sampleRateIn; + config.formatOut = formatOut; + config.channelsOut = channelsOut; + config.sampleRateOut = sampleRateOut; + + return config; +} + From 0cd327ccb253ef13a50ecf879f7bd9ebb8a7097f Mon Sep 17 00:00:00 2001 From: Ray San Date: Mon, 4 Dec 2017 11:03:45 +0100 Subject: [PATCH 060/139] Moved QuaternionNlerp() function --- src/raymath.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/raymath.h b/src/raymath.h index fe0b8947..decd02c5 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -191,8 +191,8 @@ RMDEF void QuaternionNormalize(Quaternion *q); // Normalize pro RMDEF void QuaternionInvert(Quaternion *quat); // Invert provided quaternion RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2); // Calculate two quaternion multiplication RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount); // Calculate linear interpolation between two quaternions -RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount); // Calculates spherical linear interpolation between two quaternions RMDEF Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount); // Calculate slerp-optimized interpolation between two quaternions +RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount); // Calculates spherical linear interpolation between two quaternions RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to); // Calculate quaternion based on the rotation from one vector to another RMDEF Quaternion QuaternionFromMatrix(Matrix matrix); // Returns a quaternion for a given rotation matrix RMDEF Matrix QuaternionToMatrix(Quaternion q); // Returns a matrix for a given quaternion @@ -1083,6 +1083,15 @@ RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount) return result; } +// Calculate slerp-optimized interpolation between two quaternions +RMDEF Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount) +{ + Quaternion result = QuaternionLerp(q1, q2, amount); + QuaternionNormalize(&result); + + return result; +} + // Calculates spherical linear interpolation between two quaternions RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) { @@ -1119,15 +1128,6 @@ RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) return result; } -// Calculate slerp-optimized interpolation between two quaternions -RMDEF Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount) -{ - Quaternion result = QuaternionLerp(q1, q2, amount); - QuaternionNormalize(&result); - - return result; -} - // Calculate quaternion based on the rotation from one vector to another RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to) { From 54d0acc3b6200e044771c28fb01ef97dde5b90a0 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 5 Dec 2017 00:05:05 +0100 Subject: [PATCH 061/139] Change version number for develop Updated raylib version to 1.9-dev for development pourposes. Next raylib version is planned to implement a big amount of changes, so the version bump. --- src/core.c | 4 ++-- src/raylib.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core.c b/src/core.c index c11c69ce..b3dde142 100644 --- a/src/core.c +++ b/src/core.c @@ -414,7 +414,7 @@ static void *GamepadThread(void *arg); // Mouse reading thread // NOTE: data parameter could be used to pass any kind of required data to the initialization void InitWindow(int width, int height, void *data) { - TraceLog(LOG_INFO, "Initializing raylib (v1.8.0)"); + TraceLog(LOG_INFO, "Initializing raylib (v1.9-dev)"); // Input data is window title char data windowTitle = (char *)data; @@ -478,7 +478,7 @@ void InitWindow(int width, int height, void *data) // NOTE: data parameter could be used to pass any kind of required data to the initialization void InitWindow(int width, int height, void *data) { - TraceLog(LOG_INFO, "Initializing raylib (v1.8.0)"); + TraceLog(LOG_INFO, "Initializing raylib (v1.9-dev)"); screenWidth = width; screenHeight = height; diff --git a/src/raylib.h b/src/raylib.h index e5ad8a9d..399b1d4a 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* raylib v1.8.0 +* raylib v1.9-dev * * A simple and easy-to-use library to learn videogames programming (www.raylib.com) * From 104391f82bc4f7466c15cf79263d83b3cb514ee9 Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 5 Dec 2017 18:49:00 +1000 Subject: [PATCH 062/139] Update mini_al. --- src/external/mini_al.h | 851 +++++++++++++++++++++-------------------- 1 file changed, 426 insertions(+), 425 deletions(-) diff --git a/src/external/mini_al.h b/src/external/mini_al.h index fd395832..7d83b548 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -72,7 +72,7 @@ // ---------------- // mal_uint32 on_send_samples(mal_device* pDevice, mal_uint32 frameCount, void* pSamples) // { -// // This callback is set at initialization time and will be called when a playback device needs more +// // This callback is set at initialization time and will be called when a playback device needs more // // data. You need to write as many frames as you can to pSamples (but no more than frameCount) and // // then return the number of frames you wrote. // // @@ -212,11 +212,11 @@ extern "C" { // Some backends are only supported on certain platforms. #if defined(MAL_WIN32) - #define MAL_SUPPORT_WASAPI - #if defined(MAL_WIN32_DESKTOP) // DirectSound and WinMM backends are only supported on desktop's. - #define MAL_SUPPORT_DSOUND - #define MAL_SUPPORT_WINMM - #endif + #define MAL_SUPPORT_WASAPI + #if defined(MAL_WIN32_DESKTOP) // DirectSound and WinMM backends are only supported on desktop's. + #define MAL_SUPPORT_DSOUND + #define MAL_SUPPORT_WINMM + #endif // Don't support WASAPI on older versions of MSVC for now. #if defined(_MSC_VER) @@ -228,20 +228,20 @@ extern "C" { #endif #endif #if defined(MAL_UNIX) - #if defined(MAL_LINUX) - #if !defined(MAL_ANDROID) // ALSA is not supported on Android. - #define MAL_SUPPORT_ALSA - #endif - #endif - #if defined(MAL_APPLE) - #define MAL_SUPPORT_COREAUDIO - #endif - #if defined(MAL_ANDROID) - #define MAL_SUPPORT_OPENSL - #endif - #if !defined(MAL_LINUX) && !defined(MAL_APPLE) && !defined(MAL_ANDROID) && !defined(MAL_EMSCRIPTEN) - #define MAL_SUPPORT_OSS - #endif + #if defined(MAL_LINUX) + #if !defined(MAL_ANDROID) // ALSA is not supported on Android. + #define MAL_SUPPORT_ALSA + #endif + #endif + #if defined(MAL_APPLE) + #define MAL_SUPPORT_COREAUDIO + #endif + #if defined(MAL_ANDROID) + #define MAL_SUPPORT_OPENSL + #endif + #if !defined(MAL_LINUX) && !defined(MAL_APPLE) && !defined(MAL_ANDROID) && !defined(MAL_EMSCRIPTEN) + #define MAL_SUPPORT_OSS + #endif #endif #define MAL_SUPPORT_SDL // All platforms support SDL. @@ -260,13 +260,13 @@ extern "C" { #define MAL_ENABLE_DSOUND #endif #if !defined(MAL_NO_WINMM) && defined(MAL_SUPPORT_WINMM) - #define MAL_ENABLE_WINMM + #define MAL_ENABLE_WINMM #endif #if !defined(MAL_NO_ALSA) && defined(MAL_SUPPORT_ALSA) #define MAL_ENABLE_ALSA #endif #if !defined(MAL_NO_COREAUDIO) && defined(MAL_SUPPORT_COREAUDIO) - #define MAL_ENABLE_COREAUDIO + #define MAL_ENABLE_COREAUDIO #endif #if !defined(MAL_NO_OSS) && defined(MAL_SUPPORT_OSS) #define MAL_ENABLE_OSS @@ -444,8 +444,8 @@ typedef int mal_result; #define MAL_FAILED_TO_INIT_BACKEND -15 #define MAL_FAILED_TO_READ_DATA_FROM_CLIENT -16 #define MAL_FAILED_TO_READ_DATA_FROM_DEVICE -17 -#define MAL_FAILED_TO_SEND_DATA_TO_CLIENT -18 -#define MAL_FAILED_TO_SEND_DATA_TO_DEVICE -19 +#define MAL_FAILED_TO_SEND_DATA_TO_CLIENT -18 +#define MAL_FAILED_TO_SEND_DATA_TO_DEVICE -19 #define MAL_FAILED_TO_OPEN_BACKEND_DEVICE -20 #define MAL_FAILED_TO_START_BACKEND_DEVICE -21 #define MAL_FAILED_TO_STOP_BACKEND_DEVICE -22 @@ -525,16 +525,16 @@ typedef union mal_uint8 dsound[16]; // DirectSound uses a GUID for identification. #endif #ifdef MAL_SUPPORT_WINMM - /*UINT_PTR*/ mal_uint32 winmm; // When creating a device, WinMM expects a Win32 UINT_PTR for device identification. In practice it's actually just a UINT. + /*UINT_PTR*/ mal_uint32 winmm; // When creating a device, WinMM expects a Win32 UINT_PTR for device identification. In practice it's actually just a UINT. #endif #ifdef MAL_SUPPORT_ALSA char alsa[256]; // ALSA uses a name string for identification. #endif #ifdef MAL_SUPPORT_COREAUDIO - // TODO: Implement me. + // TODO: Implement me. #endif #ifdef MAL_SUPPORT_OSS - char oss[64]; // "dev/dsp0", etc. "dev/dsp" for the default device. + char oss[64]; // "dev/dsp0", etc. "dev/dsp" for the default device. #endif #ifdef MAL_SUPPORT_OPENSL mal_uint32 opensl; // OpenSL|ES uses a 32-bit unsigned integer for identification. @@ -546,7 +546,7 @@ typedef union int sdl; // SDL devices are identified with an index. #endif #ifdef MAL_SUPPORT_NULL - int nullbackend; // Always 0. + int nullbackend; // Always 0. #endif } mal_device_id; @@ -690,8 +690,8 @@ struct mal_context } dsound; #endif #ifdef MAL_SUPPORT_WINMM - struct - { + struct + { /*HMODULE*/ mal_handle hWinMM; mal_proc waveOutGetNumDevs; mal_proc waveOutGetDevCapsA; @@ -710,7 +710,7 @@ struct mal_context mal_proc waveInAddBuffer; mal_proc waveInStart; mal_proc waveInReset; - } winmm; + } winmm; #endif #ifdef MAL_SUPPORT_ALSA struct @@ -765,17 +765,17 @@ struct mal_context } alsa; #endif #ifdef MAL_SUPPORT_COREAUDIO - struct - { - int _unused; - } coreaudio; + struct + { + int _unused; + } coreaudio; #endif #ifdef MAL_SUPPORT_OSS - struct - { - int versionMajor; - int versionMinor; - } oss; + struct + { + int versionMajor; + int versionMinor; + } oss; #endif #ifdef MAL_SUPPORT_OPENSL struct @@ -997,8 +997,8 @@ struct mal_device } dsound; #endif #ifdef MAL_SUPPORT_WINMM - struct - { + struct + { /*HWAVEOUT, HWAVEIN*/ mal_handle hDevice; /*HANDLE*/ mal_handle hEvent; mal_uint32 fragmentSizeInFrames; @@ -1008,7 +1008,7 @@ struct mal_device mal_uint8* pIntermediaryBuffer; mal_uint8* _pHeapData; // Used internally and is used for the heap allocated data for the intermediary buffer and the WAVEHDR structures. mal_bool32 breakFromMainLoop; - } winmm; + } winmm; #endif #ifdef MAL_SUPPORT_ALSA struct @@ -1020,19 +1020,19 @@ struct mal_device } alsa; #endif #ifdef MAL_SUPPORT_COREAUDIO - struct - { - int _unused; - } coreaudio; + struct + { + int _unused; + } coreaudio; #endif #ifdef MAL_SUPPORT_OSS - struct - { - int fd; - mal_uint32 fragmentSizeInFrames; - mal_bool32 breakFromMainLoop; - void* pIntermediaryBuffer; - } oss; + struct + { + int fd; + mal_uint32 fragmentSizeInFrames; + mal_bool32 breakFromMainLoop; + void* pIntermediaryBuffer; + } oss; #endif #ifdef MAL_SUPPORT_OPENSL struct @@ -2498,7 +2498,7 @@ static mal_result mal_post_error(mal_device* pDevice, const char* message, mal_r #if !defined(MAL_ANDROID) static void mal_get_default_channel_mapping(mal_backend backend, mal_uint32 channels, mal_channel channelMap[MAL_MAX_CHANNELS]) { - if (channels == 1) { // Mono + if (channels == 1) { // Mono channelMap[0] = MAL_CHANNEL_FRONT_CENTER; } else if (channels == 2) { // Stereo channelMap[0] = MAL_CHANNEL_FRONT_LEFT; @@ -2519,48 +2519,48 @@ static void mal_get_default_channel_mapping(mal_backend backend, mal_uint32 chan channelMap[3] = MAL_CHANNEL_SIDE_RIGHT; channelMap[4] = MAL_CHANNEL_LFE; } else if (channels >= 6) { // 5.1 - // Some backends use different default layouts. - if (backend == mal_backend_wasapi || backend == mal_backend_dsound || backend == mal_backend_winmm || backend == mal_backend_oss) { - channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - channelMap[2] = MAL_CHANNEL_FRONT_CENTER; - channelMap[3] = MAL_CHANNEL_LFE; - channelMap[4] = MAL_CHANNEL_SIDE_LEFT; - channelMap[5] = MAL_CHANNEL_SIDE_RIGHT; - } else { - channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - channelMap[2] = MAL_CHANNEL_SIDE_LEFT; - channelMap[3] = MAL_CHANNEL_SIDE_RIGHT; - channelMap[4] = MAL_CHANNEL_FRONT_CENTER; - channelMap[5] = MAL_CHANNEL_LFE; - } - - if (channels == 7) { // Not sure about this one. - channelMap[6] = MAL_CHANNEL_BACK_CENTER; - } else { - // I don't know what mapping to use in this case, but I'm making it upwards compatible with 7.1. Good luck! - mal_assert(channels >= 8); - channelMap[6] = MAL_CHANNEL_BACK_LEFT; - channelMap[7] = MAL_CHANNEL_BACK_RIGHT; + // Some backends use different default layouts. + if (backend == mal_backend_wasapi || backend == mal_backend_dsound || backend == mal_backend_winmm || backend == mal_backend_oss) { + channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + channelMap[2] = MAL_CHANNEL_FRONT_CENTER; + channelMap[3] = MAL_CHANNEL_LFE; + channelMap[4] = MAL_CHANNEL_SIDE_LEFT; + channelMap[5] = MAL_CHANNEL_SIDE_RIGHT; + } else { + channelMap[0] = MAL_CHANNEL_FRONT_LEFT; + channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; + channelMap[2] = MAL_CHANNEL_SIDE_LEFT; + channelMap[3] = MAL_CHANNEL_SIDE_RIGHT; + channelMap[4] = MAL_CHANNEL_FRONT_CENTER; + channelMap[5] = MAL_CHANNEL_LFE; + } - // Beyond 7.1 I'm just guessing... - if (channels == 9) { - channelMap[8] = MAL_CHANNEL_BACK_CENTER; - } else if (channels == 10) { - channelMap[8] = MAL_CHANNEL_FRONT_LEFT_CENTER; - channelMap[9] = MAL_CHANNEL_FRONT_RIGHT_CENTER; - } else if (channels == 11) { - channelMap[ 8] = MAL_CHANNEL_FRONT_LEFT_CENTER; - channelMap[ 9] = MAL_CHANNEL_FRONT_RIGHT_CENTER; - channelMap[10] = MAL_CHANNEL_BACK_CENTER; - } else { - mal_assert(channels >= 12); - for (mal_uint8 iChannel = 11; iChannel < channels && iChannel < MAL_MAX_CHANNELS; ++iChannel) { - channelMap[iChannel] = iChannel + 1; - } - } - } + if (channels == 7) { // Not sure about this one. + channelMap[6] = MAL_CHANNEL_BACK_CENTER; + } else { + // I don't know what mapping to use in this case, but I'm making it upwards compatible with 7.1. Good luck! + mal_assert(channels >= 8); + channelMap[6] = MAL_CHANNEL_BACK_LEFT; + channelMap[7] = MAL_CHANNEL_BACK_RIGHT; + + // Beyond 7.1 I'm just guessing... + if (channels == 9) { + channelMap[8] = MAL_CHANNEL_BACK_CENTER; + } else if (channels == 10) { + channelMap[8] = MAL_CHANNEL_FRONT_LEFT_CENTER; + channelMap[9] = MAL_CHANNEL_FRONT_RIGHT_CENTER; + } else if (channels == 11) { + channelMap[ 8] = MAL_CHANNEL_FRONT_LEFT_CENTER; + channelMap[ 9] = MAL_CHANNEL_FRONT_RIGHT_CENTER; + channelMap[10] = MAL_CHANNEL_BACK_CENTER; + } else { + mal_assert(channels >= 12); + for (mal_uint8 iChannel = 11; iChannel < channels && iChannel < MAL_MAX_CHANNELS; ++iChannel) { + channelMap[iChannel] = iChannel + 1; + } + } + } } } #endif @@ -2748,7 +2748,7 @@ static mal_result mal_context__try_get_device_name_by_id(mal_context* pContext, #ifdef MAL_HAS_COREAUDIO case mal_backend_coreaudio { - // TODO: Implement me. + // TODO: Implement me. } break; #endif #ifdef MAL_HAS_OSS @@ -3123,24 +3123,24 @@ static DWORD mal_channel_id_to_win32(DWORD id) { switch (id) { - case MAL_CHANNEL_FRONT_LEFT: return SPEAKER_FRONT_LEFT; - case MAL_CHANNEL_FRONT_RIGHT: return SPEAKER_FRONT_RIGHT; - case MAL_CHANNEL_FRONT_CENTER: return SPEAKER_FRONT_CENTER; - case MAL_CHANNEL_LFE: return SPEAKER_LOW_FREQUENCY; - case MAL_CHANNEL_BACK_LEFT: return SPEAKER_BACK_LEFT; - case MAL_CHANNEL_BACK_RIGHT: return SPEAKER_BACK_RIGHT; - case MAL_CHANNEL_FRONT_LEFT_CENTER: return SPEAKER_FRONT_LEFT_OF_CENTER; + case MAL_CHANNEL_FRONT_LEFT: return SPEAKER_FRONT_LEFT; + case MAL_CHANNEL_FRONT_RIGHT: return SPEAKER_FRONT_RIGHT; + case MAL_CHANNEL_FRONT_CENTER: return SPEAKER_FRONT_CENTER; + case MAL_CHANNEL_LFE: return SPEAKER_LOW_FREQUENCY; + case MAL_CHANNEL_BACK_LEFT: return SPEAKER_BACK_LEFT; + case MAL_CHANNEL_BACK_RIGHT: return SPEAKER_BACK_RIGHT; + case MAL_CHANNEL_FRONT_LEFT_CENTER: return SPEAKER_FRONT_LEFT_OF_CENTER; case MAL_CHANNEL_FRONT_RIGHT_CENTER: return SPEAKER_FRONT_RIGHT_OF_CENTER; - case MAL_CHANNEL_BACK_CENTER: return SPEAKER_BACK_CENTER; - case MAL_CHANNEL_SIDE_LEFT: return SPEAKER_SIDE_LEFT; - case MAL_CHANNEL_SIDE_RIGHT: return SPEAKER_SIDE_RIGHT; - case MAL_CHANNEL_TOP_CENTER: return SPEAKER_TOP_CENTER; - case MAL_CHANNEL_TOP_FRONT_LEFT: return SPEAKER_TOP_FRONT_LEFT; - case MAL_CHANNEL_TOP_FRONT_CENTER: return SPEAKER_TOP_FRONT_CENTER; - case MAL_CHANNEL_TOP_FRONT_RIGHT: return SPEAKER_TOP_FRONT_RIGHT; - case MAL_CHANNEL_TOP_BACK_LEFT: return SPEAKER_TOP_BACK_LEFT; - case MAL_CHANNEL_TOP_BACK_CENTER: return SPEAKER_TOP_BACK_CENTER; - case MAL_CHANNEL_TOP_BACK_RIGHT: return SPEAKER_TOP_BACK_RIGHT; + case MAL_CHANNEL_BACK_CENTER: return SPEAKER_BACK_CENTER; + case MAL_CHANNEL_SIDE_LEFT: return SPEAKER_SIDE_LEFT; + case MAL_CHANNEL_SIDE_RIGHT: return SPEAKER_SIDE_RIGHT; + case MAL_CHANNEL_TOP_CENTER: return SPEAKER_TOP_CENTER; + case MAL_CHANNEL_TOP_FRONT_LEFT: return SPEAKER_TOP_FRONT_LEFT; + case MAL_CHANNEL_TOP_FRONT_CENTER: return SPEAKER_TOP_FRONT_CENTER; + case MAL_CHANNEL_TOP_FRONT_RIGHT: return SPEAKER_TOP_FRONT_RIGHT; + case MAL_CHANNEL_TOP_BACK_LEFT: return SPEAKER_TOP_BACK_LEFT; + case MAL_CHANNEL_TOP_BACK_CENTER: return SPEAKER_TOP_BACK_CENTER; + case MAL_CHANNEL_TOP_BACK_RIGHT: return SPEAKER_TOP_BACK_RIGHT; default: return 0; } } @@ -3692,7 +3692,7 @@ static mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type iid = g_malIID_DEVINTERFACE_AUDIO_CAPTURE; } } - + LPOLESTR iidStr; hr = StringFromIID(iid, &iidStr); if (FAILED(hr)) { @@ -3890,7 +3890,7 @@ static mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type goto done; } - + if (shareMode == AUDCLNT_SHAREMODE_SHARED) { pDevice->exclusiveMode = MAL_FALSE; } else /*if (shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)*/ { @@ -3916,7 +3916,7 @@ static mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type errorMsg = "[WASAPI] Failed to create stop event for main loop break notification.", result = MAL_FAILED_TO_CREATE_EVENT; goto done; } - + result = MAL_SUCCESS; done: @@ -4045,10 +4045,10 @@ static mal_uint32 mal_device__wait_for_frames__wasapi(mal_device* pDevice) } // Break from the main loop if the device isn't started anymore. Likely what's happened is the application - // has requested that the device be stopped. - if (!mal_device_is_started(pDevice)) { - break; - } + // has requested that the device be stopped. + if (!mal_device_is_started(pDevice)) { + break; + } mal_uint32 framesAvailable = mal_device__get_available_frames__wasapi(pDevice); if (framesAvailable > 0) { @@ -4135,7 +4135,7 @@ static mal_result mal_device__main_loop__wasapi(mal_device* pDevice) #ifdef MAL_HAS_DSOUND #include -#if 0 // MAL_GUID_NULL is not currently used, but leaving it here in case I need to add it back again. +#if 0 // MAL_GUID_NULL is not currently used, but leaving it here in case I need to add it back again. static GUID MAL_GUID_NULL = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; #endif static GUID MAL_GUID_IID_DirectSoundNotify = {0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}}; @@ -4815,9 +4815,9 @@ mal_result mal_context_init__winmm(mal_context* pContext) pContext->winmm.waveInPrepareHeader = mal_dlsym(pContext->winmm.hWinMM, "waveInPrepareHeader"); pContext->winmm.waveInUnprepareHeader = mal_dlsym(pContext->winmm.hWinMM, "waveInUnprepareHeader"); pContext->winmm.waveInAddBuffer = mal_dlsym(pContext->winmm.hWinMM, "waveInAddBuffer"); - pContext->winmm.waveInStart = mal_dlsym(pContext->winmm.hWinMM, "waveInStart"); + pContext->winmm.waveInStart = mal_dlsym(pContext->winmm.hWinMM, "waveInStart"); pContext->winmm.waveInReset = mal_dlsym(pContext->winmm.hWinMM, "waveInReset"); - + return MAL_SUCCESS; } @@ -4878,7 +4878,7 @@ static mal_result mal_enumerate_devices__winmm(mal_context* pContext, mal_device } } } - + return MAL_SUCCESS; } @@ -5109,7 +5109,7 @@ static mal_result mal_device_init__winmm(mal_context* pContext, mal_device_type formatChannels = 2; formatSampleRate = 96000; } break; - default: + default: { errorMsg = "[WinMM] The internal device does not support any of the standard formats.", errorCode = MAL_ERROR; // <-- Should never hit this. goto on_error; @@ -5336,7 +5336,7 @@ static mal_result mal_device__stop_backend__winmm(mal_device* pDevice) if (resultMM != MMSYSERR_NOERROR) { mal_post_error(pDevice, "[WinMM] WARNING: Failed to reset capture device.", mal_result_from_MMRESULT(resultMM)); } - + // Unprepare all WAVEHDR structures. for (mal_uint32 i = 0; i < pDevice->periods; ++i) { resultMM = ((MAL_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); @@ -5373,10 +5373,10 @@ static mal_result mal_device__main_loop__winmm(mal_device* pDevice) } // Break from the main loop if the device isn't started anymore. Likely what's happened is the application - // has requested that the device be stopped. - if (!mal_device_is_started(pDevice)) { - break; - } + // has requested that the device be stopped. + if (!mal_device_is_started(pDevice)) { + break; + } // Any headers that are marked as done need to be handled. We start by processing the completed blocks. Then we reset the event // and then write or add replacement buffers to the device. @@ -5388,7 +5388,7 @@ static mal_result mal_device__main_loop__winmm(mal_device* pDevice) } if (pDevice->type == mal_device_type_playback) { - // Playback. + // Playback. MMRESULT resultMM = ((MAL_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); if (resultMM != MMSYSERR_NOERROR) { mal_post_error(pDevice, "[WinMM] Failed to unprepare header for playback device in preparation for sending a new block of data to the device for playback.", mal_result_from_MMRESULT(resultMM)); @@ -5401,16 +5401,16 @@ static mal_result mal_device__main_loop__winmm(mal_device* pDevice) ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwFlags = 0L; ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwLoops = 0L; ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwUser = 1; // <-- Used in the next section to identify the buffers that needs to be re-written to the device. - mal_device__read_frames_from_client(pDevice, pDevice->winmm.fragmentSizeInFrames, ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData); + mal_device__read_frames_from_client(pDevice, pDevice->winmm.fragmentSizeInFrames, ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData); resultMM = ((MAL_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); if (resultMM != MMSYSERR_NOERROR) { mal_post_error(pDevice, "[WinMM] Failed to prepare header for playback device in preparation for sending a new block of data to the device for playback.", mal_result_from_MMRESULT(resultMM)); break; } - } else { - // Capture. - mal_uint32 framesCaptured = (mal_uint32)(((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBytesRecorded) / pDevice->internalChannels / mal_get_sample_size_in_bytes(pDevice->internalFormat); + } else { + // Capture. + mal_uint32 framesCaptured = (mal_uint32)(((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBytesRecorded) / pDevice->internalChannels / mal_get_sample_size_in_bytes(pDevice->internalFormat); if (framesCaptured > 0) { mal_device__send_frames_to_client(pDevice, framesCaptured, ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData); } @@ -5433,7 +5433,7 @@ static mal_result mal_device__main_loop__winmm(mal_device* pDevice) mal_post_error(pDevice, "[WinMM] Failed to prepare header for capture device in preparation for adding a new capture buffer for the device.", mal_result_from_MMRESULT(resultMM)); break; } - } + } pDevice->winmm.iNextHeader = (pDevice->winmm.iNextHeader + 1) % pDevice->periods; } @@ -5447,23 +5447,23 @@ static mal_result mal_device__main_loop__winmm(mal_device* pDevice) ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwUser = 0; if (pDevice->type == mal_device_type_playback) { - // Playback. + // Playback. MMRESULT resultMM = ((MAL_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); if (resultMM != MMSYSERR_NOERROR) { mal_post_error(pDevice, "[WinMM] Failed to write data to the internal playback device.", mal_result_from_MMRESULT(resultMM)); break; } - } else { - // Capture. + } else { + // Capture. MMRESULT resultMM = ((MAL_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); if (resultMM != MMSYSERR_NOERROR) { mal_post_error(pDevice, "[WinMM] Failed to add new capture buffer to the internal capture device.", mal_result_from_MMRESULT(resultMM)); break; } - } + } } } - } + } return MAL_SUCCESS; } @@ -5611,7 +5611,7 @@ mal_channel mal_convert_alsa_channel_position_to_mal_channel(unsigned int alsaCh case SND_CHMAP_TRC: return MAL_CHANNEL_TOP_BACK_CENTER; default: break; } - + return 0; } @@ -5976,7 +5976,7 @@ static mal_bool32 mal_is_device_name_in_hw_format__alsa(const char* hwid) } hwid += 3; - + int commaPos; const char* dev = mal_find_char(hwid, ',', &commaPos); if (dev == NULL) { @@ -6045,7 +6045,7 @@ static int mal_convert_device_name_to_hw_format__alsa(mal_context* pContext, cha //printf("TESTING: CARD=%s,DEV=%s\n", card, dev); - + // Construction. dst[0] = 'h'; dst[1] = 'w'; dst[2] = ':'; if (mal_itoa_s(cardIndex, dst+3, dstSize-3, 10) != 0) { @@ -6112,7 +6112,7 @@ static mal_result mal_enumerate_devices__alsa(mal_context* pContext, mal_device_ } } - + if (includeThisDevice) { #if 0 @@ -6198,7 +6198,7 @@ static mal_result mal_enumerate_devices__alsa(mal_context* pContext, mal_device_ mal_strcpy_s(pInfo->name, sizeof(pInfo->name), DESC); } } - + pInfo += 1; infoSize -= 1; *pCount += 1; @@ -6343,7 +6343,7 @@ static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type t // We may need to scale the size of the buffer depending on the device. if (pDevice->usingDefaultBufferSize) { float bufferSizeScale = 1; - + snd_pcm_info_t* pInfo = (snd_pcm_info_t*)alloca(((mal_snd_pcm_info_sizeof)pContext->alsa.snd_pcm_info_sizeof)()); mal_zero_memory(pInfo, ((mal_snd_pcm_info_sizeof)pContext->alsa.snd_pcm_info_sizeof)()); @@ -6518,15 +6518,15 @@ static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type t } pDevice->bufferSizeInFrames = actualBufferSize; - + // Apply hardware parameters. if (((mal_snd_pcm_hw_params_proc)pContext->alsa.snd_pcm_hw_params)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams) < 0) { mal_device_uninit__alsa(pDevice); return mal_post_error(pDevice, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed.", MAL_ALSA_FAILED_TO_SET_HW_PARAMS); } - - + + // Software parameters. snd_pcm_sw_params_t* pSWParams = (snd_pcm_sw_params_t*)alloca(((mal_snd_pcm_sw_params_sizeof_proc)pContext->alsa.snd_pcm_sw_params_sizeof)()); @@ -6564,8 +6564,8 @@ static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type t return mal_post_error(pDevice, "[ALSA] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY); } } - - + + // Grab the internal channel map. For now we're not going to bother trying to change the channel map and // instead just do it ourselves. @@ -6580,7 +6580,7 @@ static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type t } else { // Excess channels use defaults. Do an initial fill with defaults, overwrite the first pChmap->channels, validate to ensure there are no duplicate // channels. If validation fails, fall back to defaults. - + // Fill with defaults. mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); @@ -6602,7 +6602,7 @@ static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type t // If our channel map is invalid, fall back to defaults. if (!isValid) { - mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); + mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); } } @@ -6699,37 +6699,37 @@ static mal_result mal_device__main_loop__alsa(mal_device* pDevice) int mal_open_temp_device__oss() { - // The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. - int fd = open("/dev/mixer", O_RDONLY, 0); - if (fd >= 0) { - return fd; - } + // The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. + int fd = open("/dev/mixer", O_RDONLY, 0); + if (fd >= 0) { + return fd; + } - return -1; + return -1; } mal_result mal_context_init__oss(mal_context* pContext) { mal_assert(pContext != NULL); - // Try opening a temporary device first so we can get version information. This is closed at the end. - int fd = mal_open_temp_device__oss(); - if (fd == -1) { + // Try opening a temporary device first so we can get version information. This is closed at the end. + int fd = mal_open_temp_device__oss(); + if (fd == -1) { return mal_context_post_error(pContext, NULL, "[OSS] Failed to open temporary device for retrieving system properties.", MAL_NO_BACKEND); // Looks liks OSS isn't installed, or there are no available devices. - } + } - // Grab the OSS version. - int ossVersion = 0; - int result = ioctl(fd, OSS_GETVERSION, &ossVersion); - if (result == -1) { - close(fd); + // Grab the OSS version. + int ossVersion = 0; + int result = ioctl(fd, OSS_GETVERSION, &ossVersion); + if (result == -1) { + close(fd); return mal_context_post_error(pContext, NULL, "[OSS] Failed to retrieve OSS version.", MAL_NO_BACKEND); - } + } - pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16); - pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8); + pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16); + pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8); - close(fd); + close(fd); return MAL_SUCCESS; } @@ -6749,41 +6749,41 @@ static mal_result mal_enumerate_devices__oss(mal_context* pContext, mal_device_t mal_uint32 infoSize = *pCount; *pCount = 0; - // The object returned by SNDCTL_SYSINFO will have the information we're after. - int fd = mal_open_temp_device__oss(); - if (fd == -1) { + // The object returned by SNDCTL_SYSINFO will have the information we're after. + int fd = mal_open_temp_device__oss(); + if (fd == -1) { return mal_context_post_error(pContext, NULL, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MAL_NO_BACKEND); - } + } - oss_sysinfo si; - int result = ioctl(fd, SNDCTL_SYSINFO, &si); - if (result != -1) { - for (int iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) { - oss_audioinfo ai; - ai.dev = iAudioDevice; - result = ioctl(fd, SNDCTL_AUDIOINFO, &ai); - if (result != -1) { - mal_bool32 includeThisDevice = MAL_FALSE; - if (type == mal_device_type_playback && (ai.caps & PCM_CAP_OUTPUT) != 0) { - includeThisDevice = MAL_TRUE; - } else if (type == mal_device_type_capture && (ai.caps & PCM_CAP_INPUT) != 0) { - includeThisDevice = MAL_TRUE; - } + oss_sysinfo si; + int result = ioctl(fd, SNDCTL_SYSINFO, &si); + if (result != -1) { + for (int iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) { + oss_audioinfo ai; + ai.dev = iAudioDevice; + result = ioctl(fd, SNDCTL_AUDIOINFO, &ai); + if (result != -1) { + mal_bool32 includeThisDevice = MAL_FALSE; + if (type == mal_device_type_playback && (ai.caps & PCM_CAP_OUTPUT) != 0) { + includeThisDevice = MAL_TRUE; + } else if (type == mal_device_type_capture && (ai.caps & PCM_CAP_INPUT) != 0) { + includeThisDevice = MAL_TRUE; + } - if (includeThisDevice) { - if (ai.devnode[0] != '\0') { // <-- Can be blank, according to documentation. + if (includeThisDevice) { + if (ai.devnode[0] != '\0') { // <-- Can be blank, according to documentation. if (pInfo != NULL) { if (infoSize > 0) { mal_strncpy_s(pInfo->id.oss, sizeof(pInfo->id.oss), ai.devnode, (size_t)-1); - - // The human readable device name should be in the "ai.handle" variable, but it can - // sometimes be empty in which case we just fall back to "ai.name" which is less user - // friendly, but usually has a value. - if (ai.handle[0] != '\0') { - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), ai.handle, (size_t)-1); - } else { - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), ai.name, (size_t)-1); - } + + // The human readable device name should be in the "ai.handle" variable, but it can + // sometimes be empty in which case we just fall back to "ai.name" which is less user + // friendly, but usually has a value. + if (ai.handle[0] != '\0') { + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), ai.handle, (size_t)-1); + } else { + mal_strncpy_s(pInfo->name, sizeof(pInfo->name), ai.name, (size_t)-1); + } pInfo += 1; infoSize -= 1; @@ -6792,29 +6792,29 @@ static mal_result mal_enumerate_devices__oss(mal_context* pContext, mal_device_t } else { *pCount += 1; } - } - } - } - } - } else { - // Failed to retrieve the system information. Just return a default device for both playback and capture. - if (pInfo != NULL) { + } + } + } + } + } else { + // Failed to retrieve the system information. Just return a default device for both playback and capture. + if (pInfo != NULL) { if (infoSize > 0) { - mal_strncpy_s(pInfo[0].id.oss, sizeof(pInfo[0].id.oss), "/dev/dsp", (size_t)-1); - if (type == mal_device_type_playback) { - mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Playback Device", (size_t)-1); - } else { - mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Capture Device", (size_t)-1); - } + mal_strncpy_s(pInfo[0].id.oss, sizeof(pInfo[0].id.oss), "/dev/dsp", (size_t)-1); + if (type == mal_device_type_playback) { + mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Playback Device", (size_t)-1); + } else { + mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Capture Device", (size_t)-1); + } *pCount = 1; } - } else { + } else { *pCount = 1; } - } + } - close(fd); + close(fd); return MAL_SUCCESS; } @@ -6822,8 +6822,8 @@ static void mal_device_uninit__oss(mal_device* pDevice) { mal_assert(pDevice != NULL); - close(pDevice->oss.fd); - mal_free(pDevice->oss.pIntermediaryBuffer); + close(pDevice->oss.fd); + mal_free(pDevice->oss.pIntermediaryBuffer); } static mal_result mal_device_init__oss(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) @@ -6833,111 +6833,111 @@ static mal_result mal_device_init__oss(mal_context* pContext, mal_device_type ty mal_assert(pDevice != NULL); mal_zero_object(&pDevice->oss); - char deviceName[64]; - if (pDeviceID != NULL) { - mal_strncpy_s(deviceName, sizeof(deviceName), pDeviceID->oss, (size_t)-1); - } else { - mal_strncpy_s(deviceName, sizeof(deviceName), "/dev/dsp", (size_t)-1); - } + char deviceName[64]; + if (pDeviceID != NULL) { + mal_strncpy_s(deviceName, sizeof(deviceName), pDeviceID->oss, (size_t)-1); + } else { + mal_strncpy_s(deviceName, sizeof(deviceName), "/dev/dsp", (size_t)-1); + } - pDevice->oss.fd = open(deviceName, (type == mal_device_type_playback) ? O_WRONLY : O_RDONLY, 0); - if (pDevice->oss.fd == -1) { + pDevice->oss.fd = open(deviceName, (type == mal_device_type_playback) ? O_WRONLY : O_RDONLY, 0); + if (pDevice->oss.fd == -1) { return mal_post_error(pDevice, "[OSS] Failed to open device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } + } - // The OSS documantation is very clear about the order we should be initializing the device's properties: - // 1) Format - // 2) Channels - // 3) Sample rate. - - // Format. - int ossFormat = AFMT_U8; - switch (pDevice->format) { - case mal_format_s16: ossFormat = AFMT_S16_LE; break; - case mal_format_s24: ossFormat = AFMT_S32_LE; break; - case mal_format_s32: ossFormat = AFMT_S32_LE; break; - case mal_format_f32: ossFormat = AFMT_S32_LE; break; - case mal_format_u8: - default: ossFormat = AFMT_U8; break; - } - int result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SETFMT, &ossFormat); - if (result == -1) { - close(pDevice->oss.fd); + // The OSS documantation is very clear about the order we should be initializing the device's properties: + // 1) Format + // 2) Channels + // 3) Sample rate. + + // Format. + int ossFormat = AFMT_U8; + switch (pDevice->format) { + case mal_format_s16: ossFormat = AFMT_S16_LE; break; + case mal_format_s24: ossFormat = AFMT_S32_LE; break; + case mal_format_s32: ossFormat = AFMT_S32_LE; break; + case mal_format_f32: ossFormat = AFMT_S32_LE; break; + case mal_format_u8: + default: ossFormat = AFMT_U8; break; + } + int result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SETFMT, &ossFormat); + if (result == -1) { + close(pDevice->oss.fd); return mal_post_error(pDevice, "[OSS] Failed to set format.", MAL_FORMAT_NOT_SUPPORTED); - } - - switch (ossFormat) { - case AFMT_U8: pDevice->internalFormat = mal_format_u8; break; - case AFMT_S16_LE: pDevice->internalFormat = mal_format_s16; break; - case AFMT_S32_LE: pDevice->internalFormat = mal_format_s32; break; - default: mal_post_error(pDevice, "[OSS] The device's internal format is not supported by mini_al.", MAL_FORMAT_NOT_SUPPORTED); - } + } + + switch (ossFormat) { + case AFMT_U8: pDevice->internalFormat = mal_format_u8; break; + case AFMT_S16_LE: pDevice->internalFormat = mal_format_s16; break; + case AFMT_S32_LE: pDevice->internalFormat = mal_format_s32; break; + default: mal_post_error(pDevice, "[OSS] The device's internal format is not supported by mini_al.", MAL_FORMAT_NOT_SUPPORTED); + } - // Channels. - int ossChannels = (int)pConfig->channels; - result = ioctl(pDevice->oss.fd, SNDCTL_DSP_CHANNELS, &ossChannels); - if (result == -1) { - close(pDevice->oss.fd); + // Channels. + int ossChannels = (int)pConfig->channels; + result = ioctl(pDevice->oss.fd, SNDCTL_DSP_CHANNELS, &ossChannels); + if (result == -1) { + close(pDevice->oss.fd); return mal_post_error(pDevice, "[OSS] Failed to set channel count.", MAL_FORMAT_NOT_SUPPORTED); - } + } - pDevice->internalChannels = ossChannels; + pDevice->internalChannels = ossChannels; - // Sample rate. - int ossSampleRate = (int)pConfig->sampleRate; - result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SPEED, &ossSampleRate); - if (result == -1) { - close(pDevice->oss.fd); - return mal_post_error(pDevice, "[OSS] Failed to set sample rate.", MAL_FORMAT_NOT_SUPPORTED); - } + // Sample rate. + int ossSampleRate = (int)pConfig->sampleRate; + result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SPEED, &ossSampleRate); + if (result == -1) { + close(pDevice->oss.fd); + return mal_post_error(pDevice, "[OSS] Failed to set sample rate.", MAL_FORMAT_NOT_SUPPORTED); + } - pDevice->sampleRate = ossSampleRate; + pDevice->sampleRate = ossSampleRate; - // The documentation says that the fragment settings should be set as soon as possible, but I'm not sure if - // it should be done before or after format/channels/rate. - // - // OSS wants the fragment size in bytes and a power of 2. When setting, we specify the power, not the actual - // value. - mal_uint32 fragmentSizeInBytes = mal_round_to_power_of_2(pDevice->bufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); - if (fragmentSizeInBytes < 16) { - fragmentSizeInBytes = 16; - } + // The documentation says that the fragment settings should be set as soon as possible, but I'm not sure if + // it should be done before or after format/channels/rate. + // + // OSS wants the fragment size in bytes and a power of 2. When setting, we specify the power, not the actual + // value. + mal_uint32 fragmentSizeInBytes = mal_round_to_power_of_2(pDevice->bufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); + if (fragmentSizeInBytes < 16) { + fragmentSizeInBytes = 16; + } - mal_uint32 ossFragmentSizePower = 4; - fragmentSizeInBytes >>= 4; - while (fragmentSizeInBytes >>= 1) { - ossFragmentSizePower += 1; - } + mal_uint32 ossFragmentSizePower = 4; + fragmentSizeInBytes >>= 4; + while (fragmentSizeInBytes >>= 1) { + ossFragmentSizePower += 1; + } - int ossFragment = (int)((pDevice->periods << 16) | ossFragmentSizePower); - result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SETFRAGMENT, &ossFragment); - if (result == -1) { - close(pDevice->oss.fd); - return mal_post_error(pDevice, "[OSS] Failed to set fragment size and period count.", MAL_FORMAT_NOT_SUPPORTED); - } + int ossFragment = (int)((pDevice->periods << 16) | ossFragmentSizePower); + result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SETFRAGMENT, &ossFragment); + if (result == -1) { + close(pDevice->oss.fd); + return mal_post_error(pDevice, "[OSS] Failed to set fragment size and period count.", MAL_FORMAT_NOT_SUPPORTED); + } - int actualFragmentSizeInBytes = 1 << (ossFragment & 0xFFFF); - pDevice->oss.fragmentSizeInFrames = actualFragmentSizeInBytes / mal_get_sample_size_in_bytes(pDevice->internalFormat) / pDevice->internalChannels; + int actualFragmentSizeInBytes = 1 << (ossFragment & 0xFFFF); + pDevice->oss.fragmentSizeInFrames = actualFragmentSizeInBytes / mal_get_sample_size_in_bytes(pDevice->internalFormat) / pDevice->internalChannels; - pDevice->periods = (mal_uint32)(ossFragment >> 16); - pDevice->bufferSizeInFrames = (mal_uint32)(pDevice->oss.fragmentSizeInFrames * pDevice->periods); - - - // Set the internal channel map. Not sure if this can be queried. For now just using our default assumptions. - mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); + pDevice->periods = (mal_uint32)(ossFragment >> 16); + pDevice->bufferSizeInFrames = (mal_uint32)(pDevice->oss.fragmentSizeInFrames * pDevice->periods); - // When not using MMAP mode, we need to use an intermediary buffer for the client <-> device transfer. We do - // everything by the size of a fragment. - pDevice->oss.pIntermediaryBuffer = mal_malloc(fragmentSizeInBytes); - if (pDevice->oss.pIntermediaryBuffer == NULL) { - close(pDevice->oss.fd); - return mal_post_error(pDevice, "[OSS] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY); - } + // Set the internal channel map. Not sure if this can be queried. For now just using our default assumptions. + mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); + + + // When not using MMAP mode, we need to use an intermediary buffer for the client <-> device transfer. We do + // everything by the size of a fragment. + pDevice->oss.pIntermediaryBuffer = mal_malloc(fragmentSizeInBytes); + if (pDevice->oss.pIntermediaryBuffer == NULL) { + close(pDevice->oss.fd); + return mal_post_error(pDevice, "[OSS] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY); + } return MAL_SUCCESS; } @@ -6947,21 +6947,21 @@ static mal_result mal_device__start_backend__oss(mal_device* pDevice) { mal_assert(pDevice != NULL); - // The device is started by the next calls to read() and write(). For playback it's simple - just read - // data from the client, then write it to the device with write() which will in turn start the device. - // For capture it's a bit less intuitive - we do nothing (it'll be started automatically by the first - // call to read(). - if (pDevice->type == mal_device_type_playback) { - // Playback. - mal_device__read_frames_from_client(pDevice, pDevice->oss.fragmentSizeInFrames, pDevice->oss.pIntermediaryBuffer); + // The device is started by the next calls to read() and write(). For playback it's simple - just read + // data from the client, then write it to the device with write() which will in turn start the device. + // For capture it's a bit less intuitive - we do nothing (it'll be started automatically by the first + // call to read(). + if (pDevice->type == mal_device_type_playback) { + // Playback. + mal_device__read_frames_from_client(pDevice, pDevice->oss.fragmentSizeInFrames, pDevice->oss.pIntermediaryBuffer); - int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); - if (bytesWritten == -1) { + int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); + if (bytesWritten == -1) { return mal_post_error(pDevice, "[OSS] Failed to send initial chunk of data to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); - } - } else { - // Capture. Do nothing. - } + } + } else { + // Capture. Do nothing. + } return MAL_SUCCESS; } @@ -6970,21 +6970,21 @@ static mal_result mal_device__stop_backend__oss(mal_device* pDevice) { mal_assert(pDevice != NULL); - // We want to use SNDCTL_DSP_HALT. From the documentation: + // We want to use SNDCTL_DSP_HALT. From the documentation: // - // In multithreaded applications SNDCTL_DSP_HALT (SNDCTL_DSP_RESET) must only be called by the thread + // In multithreaded applications SNDCTL_DSP_HALT (SNDCTL_DSP_RESET) must only be called by the thread // that actually reads/writes the audio device. It must not be called by some master thread to kill the // audio thread. The audio thread will not stop or get any kind of notification that the device was // stopped by the master thread. The device gets stopped but the next read or write call will silently // restart the device. // // This is actually safe in our case, because this function is only ever called from within our worker - // thread anyway. Just keep this in mind, though... + // thread anyway. Just keep this in mind, though... - int result = ioctl(pDevice->oss.fd, SNDCTL_DSP_HALT, 0); - if (result == -1) { - return mal_post_error(pDevice, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); - } + int result = ioctl(pDevice->oss.fd, SNDCTL_DSP_HALT, 0); + if (result == -1) { + return mal_post_error(pDevice, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); + } return MAL_SUCCESS; } @@ -6993,7 +6993,7 @@ static mal_result mal_device__break_main_loop__oss(mal_device* pDevice) { mal_assert(pDevice != NULL); - pDevice->oss.breakFromMainLoop = MAL_TRUE; + pDevice->oss.breakFromMainLoop = MAL_TRUE; return MAL_SUCCESS; } @@ -7001,33 +7001,33 @@ static mal_result mal_device__main_loop__oss(mal_device* pDevice) { mal_assert(pDevice != NULL); - pDevice->oss.breakFromMainLoop = MAL_FALSE; - while (!pDevice->oss.breakFromMainLoop) { - // Break from the main loop if the device isn't started anymore. Likely what's happened is the application - // has requested that the device be stopped. - if (!mal_device_is_started(pDevice)) { - break; - } + pDevice->oss.breakFromMainLoop = MAL_FALSE; + while (!pDevice->oss.breakFromMainLoop) { + // Break from the main loop if the device isn't started anymore. Likely what's happened is the application + // has requested that the device be stopped. + if (!mal_device_is_started(pDevice)) { + break; + } - if (pDevice->type == mal_device_type_playback) { - // Playback. - mal_device__read_frames_from_client(pDevice, pDevice->oss.fragmentSizeInFrames, pDevice->oss.pIntermediaryBuffer); + if (pDevice->type == mal_device_type_playback) { + // Playback. + mal_device__read_frames_from_client(pDevice, pDevice->oss.fragmentSizeInFrames, pDevice->oss.pIntermediaryBuffer); - int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); - if (bytesWritten < 0) { + int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); + if (bytesWritten < 0) { return mal_post_error(pDevice, "[OSS] Failed to send data from the client to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); - } - } else { - // Capture. - int bytesRead = read(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * mal_get_sample_size_in_bytes(pDevice->internalFormat)); - if (bytesRead < 0) { + } + } else { + // Capture. + int bytesRead = read(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * mal_get_sample_size_in_bytes(pDevice->internalFormat)); + if (bytesRead < 0) { return mal_post_error(pDevice, "[OSS] Failed to read data from the device to be sent to the client.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE); - } + } - mal_uint32 framesRead = (mal_uint32)bytesRead / pDevice->internalChannels / mal_get_sample_size_in_bytes(pDevice->internalFormat); - mal_device__send_frames_to_client(pDevice, framesRead, pDevice->oss.pIntermediaryBuffer); - } - } + mal_uint32 framesRead = (mal_uint32)bytesRead / pDevice->internalChannels / mal_get_sample_size_in_bytes(pDevice->internalFormat); + mal_device__send_frames_to_client(pDevice, framesRead, pDevice->oss.pIntermediaryBuffer); + } + } return MAL_SUCCESS; } @@ -7077,24 +7077,24 @@ static SLuint32 mal_channel_id_to_opensl(mal_uint8 id) { switch (id) { - case MAL_CHANNEL_FRONT_LEFT: return SL_SPEAKER_FRONT_LEFT; - case MAL_CHANNEL_FRONT_RIGHT: return SL_SPEAKER_FRONT_RIGHT; - case MAL_CHANNEL_FRONT_CENTER: return SL_SPEAKER_FRONT_CENTER; - case MAL_CHANNEL_LFE: return SL_SPEAKER_LOW_FREQUENCY; - case MAL_CHANNEL_BACK_LEFT: return SL_SPEAKER_BACK_LEFT; - case MAL_CHANNEL_BACK_RIGHT: return SL_SPEAKER_BACK_RIGHT; - case MAL_CHANNEL_FRONT_LEFT_CENTER: return SL_SPEAKER_FRONT_LEFT_OF_CENTER; + case MAL_CHANNEL_FRONT_LEFT: return SL_SPEAKER_FRONT_LEFT; + case MAL_CHANNEL_FRONT_RIGHT: return SL_SPEAKER_FRONT_RIGHT; + case MAL_CHANNEL_FRONT_CENTER: return SL_SPEAKER_FRONT_CENTER; + case MAL_CHANNEL_LFE: return SL_SPEAKER_LOW_FREQUENCY; + case MAL_CHANNEL_BACK_LEFT: return SL_SPEAKER_BACK_LEFT; + case MAL_CHANNEL_BACK_RIGHT: return SL_SPEAKER_BACK_RIGHT; + case MAL_CHANNEL_FRONT_LEFT_CENTER: return SL_SPEAKER_FRONT_LEFT_OF_CENTER; case MAL_CHANNEL_FRONT_RIGHT_CENTER: return SL_SPEAKER_FRONT_RIGHT_OF_CENTER; - case MAL_CHANNEL_BACK_CENTER: return SL_SPEAKER_BACK_CENTER; - case MAL_CHANNEL_SIDE_LEFT: return SL_SPEAKER_SIDE_LEFT; - case MAL_CHANNEL_SIDE_RIGHT: return SL_SPEAKER_SIDE_RIGHT; - case MAL_CHANNEL_TOP_CENTER: return SL_SPEAKER_TOP_CENTER; - case MAL_CHANNEL_TOP_FRONT_LEFT: return SL_SPEAKER_TOP_FRONT_LEFT; - case MAL_CHANNEL_TOP_FRONT_CENTER: return SL_SPEAKER_TOP_FRONT_CENTER; - case MAL_CHANNEL_TOP_FRONT_RIGHT: return SL_SPEAKER_TOP_FRONT_RIGHT; - case MAL_CHANNEL_TOP_BACK_LEFT: return SL_SPEAKER_TOP_BACK_LEFT; - case MAL_CHANNEL_TOP_BACK_CENTER: return SL_SPEAKER_TOP_BACK_CENTER; - case MAL_CHANNEL_TOP_BACK_RIGHT: return SL_SPEAKER_TOP_BACK_RIGHT; + case MAL_CHANNEL_BACK_CENTER: return SL_SPEAKER_BACK_CENTER; + case MAL_CHANNEL_SIDE_LEFT: return SL_SPEAKER_SIDE_LEFT; + case MAL_CHANNEL_SIDE_RIGHT: return SL_SPEAKER_SIDE_RIGHT; + case MAL_CHANNEL_TOP_CENTER: return SL_SPEAKER_TOP_CENTER; + case MAL_CHANNEL_TOP_FRONT_LEFT: return SL_SPEAKER_TOP_FRONT_LEFT; + case MAL_CHANNEL_TOP_FRONT_CENTER: return SL_SPEAKER_TOP_FRONT_CENTER; + case MAL_CHANNEL_TOP_FRONT_RIGHT: return SL_SPEAKER_TOP_FRONT_RIGHT; + case MAL_CHANNEL_TOP_BACK_LEFT: return SL_SPEAKER_TOP_BACK_LEFT; + case MAL_CHANNEL_TOP_BACK_CENTER: return SL_SPEAKER_TOP_BACK_CENTER; + case MAL_CHANNEL_TOP_BACK_RIGHT: return SL_SPEAKER_TOP_BACK_RIGHT; default: return 0; } } @@ -7380,7 +7380,7 @@ static void mal_device_uninit__opensl(mal_device* pDevice) } mal_free(pDevice->opensl.pBuffer); - + // Uninit global data. if (g_malOpenSLInitCounter > 0) { @@ -7916,10 +7916,10 @@ mal_result mal_context_init__openal(mal_context* pContext) #ifdef MAL_APPLE libName = "OpenAL.framework/OpenAL"; #endif - if (libName == NULL) { - return MAL_NO_BACKEND; // Don't know what the library name is called. - } - + if (libName == NULL) { + return MAL_NO_BACKEND; // Don't know what the library name is called. + } + pContext->openal.hOpenAL = mal_dlopen(libName); @@ -8097,7 +8097,7 @@ mal_result mal_context_init__openal(mal_context* pContext) pContext->openal.isEnumerationSupported = ((MAL_LPALCISEXTENSIONPRESENT)pContext->openal.alcIsExtensionPresent)(NULL, "ALC_ENUMERATION_EXT"); pContext->openal.isFloat32Supported = ((MAL_LPALISEXTENSIONPRESENT)pContext->openal.alIsExtensionPresent)("AL_EXT_float32"); pContext->openal.isMCFormatsSupported = ((MAL_LPALISEXTENSIONPRESENT)pContext->openal.alIsExtensionPresent)("AL_EXT_MCFORMATS"); - + return MAL_SUCCESS; } @@ -8123,7 +8123,7 @@ mal_result mal_enumerate_devices__openal(mal_context* pContext, mal_device_type if (pDeviceNames == NULL) { return MAL_NO_DEVICE; } - + // Each device is stored in pDeviceNames, separated by a null-terminator. The string itself is double-null-terminated. const mal_ALCchar* pNextDeviceName = pDeviceNames; while (pNextDeviceName[0] != '\0') { @@ -8694,7 +8694,7 @@ mal_result mal_context_init__sdl(mal_context* pContext) if (pContext->sdl.hSDL == NULL) { return MAL_NO_BACKEND; // Couldn't find SDL2.dll, etc. Most likely it's not installed. } - + pContext->sdl.SDL_InitSubSystem = mal_dlsym(pContext->sdl.hSDL, "SDL_InitSubSystem"); pContext->sdl.SDL_QuitSubSystem = mal_dlsym(pContext->sdl.hSDL, "SDL_QuitSubSystem"); pContext->sdl.SDL_CloseAudio = mal_dlsym(pContext->sdl.hSDL, "SDL_CloseAudio"); @@ -8737,7 +8737,7 @@ mal_result mal_context_init__sdl(mal_context* pContext) if (resultSDL != 0) { return MAL_ERROR; } - + return MAL_SUCCESS; } @@ -8991,9 +8991,9 @@ static mal_result mal_device__start_backend(mal_device* pDevice) } #endif #ifdef MAL_HAS_OSS - if (pDevice->pContext->backend == mal_backend_oss) { - result = mal_device__start_backend__oss(pDevice); - } + if (pDevice->pContext->backend == mal_backend_oss) { + result = mal_device__start_backend__oss(pDevice); + } #endif #ifdef MAL_HAS_OPENAL if (pDevice->pContext->backend == mal_backend_openal) { @@ -9035,9 +9035,9 @@ static mal_result mal_device__stop_backend(mal_device* pDevice) } #endif #ifdef MAL_HAS_OSS - if (pDevice->pContext->backend == mal_backend_oss) { - result = mal_device__stop_backend__oss(pDevice); - } + if (pDevice->pContext->backend == mal_backend_oss) { + result = mal_device__stop_backend__oss(pDevice); + } #endif #ifdef MAL_HAS_OPENAL if (pDevice->pContext->backend == mal_backend_openal) { @@ -9079,9 +9079,9 @@ static mal_result mal_device__break_main_loop(mal_device* pDevice) } #endif #ifdef MAL_HAS_OSS - if (pDevice->pContext->backend == mal_backend_oss) { - result = mal_device__break_main_loop__oss(pDevice); - } + if (pDevice->pContext->backend == mal_backend_oss) { + result = mal_device__break_main_loop__oss(pDevice); + } #endif #ifdef MAL_HAS_OPENAL if (pDevice->pContext->backend == mal_backend_openal) { @@ -9123,9 +9123,9 @@ static mal_result mal_device__main_loop(mal_device* pDevice) } #endif #ifdef MAL_HAS_OSS - if (pDevice->pContext->backend == mal_backend_oss) { - result = mal_device__main_loop__oss(pDevice); - } + if (pDevice->pContext->backend == mal_backend_oss) { + result = mal_device__main_loop__oss(pDevice); + } #endif #ifdef MAL_HAS_OPENAL if (pDevice->pContext->backend == mal_backend_openal) { @@ -9145,7 +9145,7 @@ mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData) { mal_device* pDevice = (mal_device*)pData; mal_assert(pDevice != NULL); - + #ifdef MAL_WIN32 mal_CoInitializeEx(pDevice->pContext, NULL, 0); // 0 = COINIT_MULTITHREADED #endif @@ -9406,12 +9406,12 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, con result = mal_context_init__alsa(pContext); } break; #endif - #ifdef MAL_HAS_OSS - case mal_backend_oss: - { - result = mal_context_init__oss(pContext); - } break; - #endif + #ifdef MAL_HAS_OSS + case mal_backend_oss: + { + result = mal_context_init__oss(pContext); + } break; + #endif #ifdef MAL_HAS_OPENSL case mal_backend_opensl: { @@ -9454,7 +9454,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, con mal_result mal_context_uninit(mal_context* pContext) { if (pContext == NULL) return MAL_INVALID_ARGS; - + switch (pContext->backend) { #ifdef MAL_HAS_WASAPI case mal_backend_wasapi: @@ -9480,12 +9480,12 @@ mal_result mal_context_uninit(mal_context* pContext) return mal_context_uninit__alsa(pContext); } break; #endif - #ifdef MAL_HAS_OSS - case mal_backend_oss: - { - return mal_context_uninit__oss(pContext); - } break; - #endif + #ifdef MAL_HAS_OSS + case mal_backend_oss: + { + return mal_context_uninit__oss(pContext); + } break; + #endif #ifdef MAL_HAS_OPENSL case mal_backend_opensl: { @@ -9556,12 +9556,12 @@ mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, ma return mal_enumerate_devices__alsa(pContext, type, pCount, pInfo); } break; #endif - #ifdef MAL_HAS_OSS - case mal_backend_oss: - { - return mal_enumerate_devices__oss(pContext, type, pCount, pInfo); - } break; - #endif + #ifdef MAL_HAS_OSS + case mal_backend_oss: + { + return mal_enumerate_devices__oss(pContext, type, pCount, pInfo); + } break; + #endif #ifdef MAL_HAS_OPENSL case mal_backend_opensl: { @@ -9661,7 +9661,7 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi pDevice->sampleRate = config.sampleRate; pDevice->bufferSizeInFrames = config.bufferSizeInFrames; pDevice->periods = config.periods; - + // The internal format, channel count and sample rate can be modified by the backend. pDevice->internalFormat = pDevice->format; pDevice->internalChannels = pDevice->channels; @@ -9721,12 +9721,12 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi result = mal_device_init__alsa(pContext, type, pDeviceID, &config, pDevice); } break; #endif - #ifdef MAL_HAS_OSS - case mal_backend_oss: - { - result = mal_device_init__oss(pContext, type, pDeviceID, &config, pDevice); - } break; - #endif + #ifdef MAL_HAS_OSS + case mal_backend_oss: + { + result = mal_device_init__oss(pContext, type, pDeviceID, &config, pDevice); + } break; + #endif #ifdef MAL_HAS_OPENSL case mal_backend_opensl: { @@ -9758,7 +9758,7 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi if (result != MAL_SUCCESS) { return MAL_NO_BACKEND; // The error message will have been posted with mal_post_error() by the source of the error so don't bother calling it here. } - + // If the backend did not fill out a name for the device, try a generic method. if (pDevice->name[0] == '\0') { @@ -9807,7 +9807,7 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi mal_dsp_init(&dspConfig, mal_device__on_read_from_device, pDevice, &pDevice->dsp); } - + // Some backends don't require the worker thread. @@ -9875,9 +9875,9 @@ void mal_device_uninit(mal_device* pDevice) } #endif #ifdef MAL_HAS_OSS - if (pDevice->pContext->backend == mal_backend_oss) { - mal_device_uninit__oss(pDevice); - } + if (pDevice->pContext->backend == mal_backend_oss) { + mal_device_uninit__oss(pDevice); + } #endif #ifdef MAL_HAS_OPENSL if (pDevice->pContext->backend == mal_backend_opensl) { @@ -9925,7 +9925,7 @@ mal_result mal_device_start(mal_device* pDevice) { if (pDevice == NULL) return mal_post_error(pDevice, "mal_device_start() called with invalid arguments (pDevice == NULL).", MAL_INVALID_ARGS); if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) return mal_post_error(pDevice, "mal_device_start() called for an uninitialized device.", MAL_DEVICE_NOT_INITIALIZED); - + mal_result result = MAL_ERROR; mal_mutex_lock(&pDevice->lock); { @@ -10394,11 +10394,11 @@ mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void pSRC->linear.isPrevFramesLoaded = MAL_FALSE; } } - + break; } } - + mal_pcm_convert(pFramesOut, pSRC->config.formatOut, pFrame, mal_format_f32, 1 * pSRC->config.channels); pFramesOut = (mal_uint8*)pFramesOut + (1 * pSRC->config.channels * mal_get_sample_size_in_bytes(pSRC->config.formatOut)); @@ -10702,7 +10702,7 @@ static void mal_dsp_mix_channels__dec(float* pFramesOut, mal_uint32 channelsOut, } } } else { - // Blend mode is where we just use simple averaging to blend based on spacial locality. + // Blend mode is where we just use simple averaging to blend based on spacial locality. if (channelsOut == 1) { for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { float total = 0; @@ -11039,7 +11039,7 @@ mal_uint32 mal_dsp_read_frames_ex(mal_dsp* pDSP, mal_uint32 frameCount, void* pF if (framesRead == 0) { break; } - + // Channel mixing. The input format must be in f32 which may require a conversion. if (pDSP->config.channelsIn != pDSP->config.channelsOut) { @@ -11061,7 +11061,7 @@ mal_uint32 mal_dsp_read_frames_ex(mal_dsp* pDSP, mal_uint32 frameCount, void* pF mal_rearrange_channels(pFrames[iFrames] + (i * pDSP->config.channelsOut * mal_get_sample_size_in_bytes(pFramesFormat[iFrames])), pDSP->config.channelsOut, pDSP->channelShuffleTable, pFramesFormat[iFrames]); } } - + // Final conversion to output format. mal_pcm_convert(pFramesOut, pDSP->config.formatOut, pFrames[iFrames], pFramesFormat[iFrames], framesRead * pDSP->config.channelsOut); @@ -11498,6 +11498,7 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) // audio data to a different format. // - Improvements to f32 -> u8/s16/s24/s32 conversion routines. // - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL and SDL backends. +// - Fixes and improvements for Raspberry Pi. // - Warning fixes. // // v0.5 - 2017-11-11 From acbfba92508566cb93ff91da2939ebc0cc4b800e Mon Sep 17 00:00:00 2001 From: Ray San Date: Tue, 5 Dec 2017 13:22:26 +0100 Subject: [PATCH 063/139] Updated library features and dependencies --- README.md | 16 ++++++++-------- src/raylib.h | 34 +++++++++++++++++----------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index db8e9698..a82ea12c 100644 --- a/README.md +++ b/README.md @@ -18,20 +18,20 @@ pure spartan-programmers way. Are you ready to learn? Jump to [code examples!](h features -------- - + * Written in plain C code (C99) in PascalCase/camelCase notation - * Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES2) + * Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES2 - choose at compile) * Unique OpenGL abstraction layer (usable as standalone module): [rlgl](https://github.com/raysan5/raylib/blob/master/src/rlgl.c) - * Powerful fonts module with SpriteFonts support (XNA bitmap fonts, AngelCode fonts, TTF) - * Outstanding texture formats support, including compressed formats (DXT, ETC, PVRT, ASTC) - * Basic 3d support for Geometrics, Models, Billboards, Heightmaps and Cubicmaps + * Powerful fonts module with SpriteFonts support (XNA fonts, AngelCode fonts, TTF) + * Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC) + * Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more! * Flexible Materials system, supporting classic maps and PBR maps * Shaders support, including Model shaders and Postprocessing shaders * Powerful math module for Vector, Matrix and Quaternion operations: [raymath](https://github.com/raysan5/raylib/blob/master/src/raymath.h) * Audio loading and playing with streaming support (WAV, OGG, FLAC, XM, MOD) - * Multiple platforms support: Windows, Linux, Mac, **Android**, **Raspberry Pi** and **HTML5** - * VR stereo rendering support with configurable HMD device parameters - * Minimal external dependencies (OpenGL, OpenAL) + * Multiple platforms support: Windows, Linux, FreeBSD, MacOS, UWP, Android, Raspberry Pi, HTML5. + * VR stereo rendering with configurable HMD device parameters + * NO external dependencies, all required libraries included with raylib * Complete bindings to LUA ([raylib-lua](https://github.com/raysan5/raylib-lua)) and Go ([raylib-go](https://github.com/gen2brain/raylib-go)) raylib uses on its core module the outstanding [GLFW3](http://www.glfw.org/) library. The best option I found for diff --git a/src/raylib.h b/src/raylib.h index 95247235..a3914c4d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -6,18 +6,18 @@ * * FEATURES: * - Written in plain C code (C99) in PascalCase/camelCase notation -* - Multiple platforms support: Windows, Linux, Mac, Android, Raspberry Pi and HTML5 -* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES 2.0) +* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES2 - choose at compile) * - Unique OpenGL abstraction layer (usable as standalone module): [rlgl] -* - Powerful fonts module with SpriteFonts support (XNA bitmap fonts, AngelCode fonts, TTF) -* - Outstanding texture formats support, including compressed formats (DXT, ETC, PVRT, ASTC) -* - Basic 3d support for Geometrics, Models, Billboards, Heightmaps and Cubicmaps +* - Powerful fonts module with SpriteFonts support (XNA fonts, AngelCode fonts, TTF) +* - Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC) +* - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more! * - Flexible Materials system, supporting classic maps and PBR maps * - Shaders support, including Model shaders and Postprocessing shaders -* - Powerful math module for Vector2, Vector3, Matrix and Quaternion operations: [raymath] -* - Audio loading and playing with streaming support and mixing channels: [audio] -* - VR stereo rendering support with configurable HMD device parameters -* - Minimal external dependencies (GLFW3, OpenGL, OpenAL) +* - Powerful math module for Vector, Matrix and Quaternion operations: [raymath] +* - Audio loading and playing with streaming support (WAV, OGG, FLAC, XM, MOD) +* - Multiple platforms support: Windows, Linux, FreeBSD, MacOS, UWP, Android, Raspberry Pi, HTML5. +* - VR stereo rendering with configurable HMD device parameters +* - NO external dependencies, all required libraries included with raylib * - Complete bindings to LUA (raylib-lua) and Go (raylib-go) * * NOTES: @@ -25,17 +25,17 @@ * If using OpenGL 3.3 or ES2, one default shader is loaded automatically (internally defined) [rlgl] * If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads * -* DEPENDENCIES: -* GLFW3 (www.glfw.org) for window/context management and input [core] -* GLAD for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) [rlgl] -* OpenAL Soft for audio device/context management [audio] +* DEPENDENCIES (included): +* rglfw (github.com/glfw/glfw) for window/context management and input (only PLATFORM_DESKTOP) [core] +* glad (github.com/Dav1dde/glad) for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) [rlgl] +* mini_al (github.com/dr-soft/mini_al) for audio device/context management [audio] * -* OPTIONAL DEPENDENCIES: -* stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA) [textures] +* OPTIONAL DEPENDENCIES (included): +* stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...) [textures] * stb_image_resize (Sean Barret) for image resizing algorythms [textures] * stb_image_write (Sean Barret) for image writting (PNG) [utils] * stb_truetype (Sean Barret) for ttf fonts loading [text] -* stb_vorbis (Sean Barret) for ogg audio loading [audio] +* stb_vorbis (Sean Barret) for OGG audio loading [audio] * stb_perlin (Sean Barret) for Perlin noise image generation [textures] * par_shapes (Philip Rideout) for parametric 3d shapes generation [models] * jar_xm (Joshua Reisenauer) for XM audio module loading [audio] @@ -50,7 +50,7 @@ * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: * -* Copyright (c) 2013-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. From 33eec3157510cf76b67c9491e606f4f75f5ea2bc Mon Sep 17 00:00:00 2001 From: Ray San Date: Tue, 5 Dec 2017 13:23:04 +0100 Subject: [PATCH 064/139] Updated external libraries dependencies Added dr_wav for a future use --- src/external/dr_flac.h | 4427 +++++++++++++++++++++++++--------------- src/external/dr_wav.h | 3455 +++++++++++++++++++++++++++++++ 2 files changed, 6204 insertions(+), 1678 deletions(-) create mode 100644 src/external/dr_wav.h diff --git a/src/external/dr_flac.h b/src/external/dr_flac.h index d2bebea5..60f57ece 100644 --- a/src/external/dr_flac.h +++ b/src/external/dr_flac.h @@ -1,13 +1,13 @@ // FLAC audio decoder. Public domain. See "unlicense" statement at the end of this file. -// dr_flac - v0.4c - 2016-12-26 +// dr_flac - v0.8d - 2017-09-22 // // David Reid - mackron@gmail.com // USAGE // // dr_flac is a single-file library. To use it, do something like the following in one .c file. -// #define DR_FLAC_IMPLEMENTATION -// #include "dr_flac.h" +// #define DR_FLAC_IMPLEMENTATION +// #include "dr_flac.h" // // You can then #include this file in other parts of the program as you would with any other header file. To decode audio data, // do something like the following: @@ -17,8 +17,8 @@ // // Failed to open FLAC file // } // -// int32_t* pSamples = malloc(pFlac->totalSampleCount * sizeof(int32_t)); -// uint64_t numberOfInterleavedSamplesActuallyRead = drflac_read_s32(pFlac, pFlac->totalSampleCount, pSamples); +// drflac_int32* pSamples = malloc(pFlac->totalSampleCount * sizeof(drflac_int32)); +// drflac_uint64 numberOfInterleavedSamplesActuallyRead = drflac_read_s32(pFlac, pFlac->totalSampleCount, pSamples); // // The drflac object represents the decoder. It is a transparent type so all the information you need, such as the number of // channels and the bits per sample, should be directly accessible - just make sure you don't change their values. Samples are @@ -43,8 +43,8 @@ // // unsigned int channels; // unsigned int sampleRate; -// uint64_t totalSampleCount; -// int32_t* pSampleData = drflac_open_and_decode_file("MySong.flac", &channels, &sampleRate, &totalSampleCount); +// drflac_uint64 totalSampleCount; +// drflac_int32* pSampleData = drflac_open_and_decode_file_s32("MySong.flac", &channels, &sampleRate, &totalSampleCount); // if (pSampleData == NULL) { // // Failed to open and decode FLAC file. // } @@ -54,13 +54,25 @@ // drflac_free(pSampleData); // // +// You can read samples as signed 16-bit integer and 32-bit floating-point PCM with the *_s16() and *_f32() family of APIs +// respectively, but note that these should be considered lossy. +// +// // If you need access to metadata (album art, etc.), use drflac_open_with_metadata(), drflac_open_file_with_metdata() or // drflac_open_memory_with_metadata(). The rationale for keeping these APIs separate is that they're slightly slower than the // normal versions and also just a little bit harder to use. // // dr_flac reports metadata to the application through the use of a callback, and every metadata block is reported before -// drflac_open_with_metdata() returns. See https://github.com/mackron/dr_libs_tests/blob/master/dr_flac/dr_flac_test_2.c for -// an example on how to read metadata. +// drflac_open_with_metdata() returns. +// +// +// The main opening APIs (drflac_open(), etc.) will fail if the header is not present. The presents a problem in certain +// scenarios such as broadcast style streams like internet radio where the header may not be present because the user has +// started playback mid-stream. To handle this, use the relaxed APIs: drflac_open_relaxed() and drflac_open_with_metadata_relaxed(). +// +// It is not recommended to use these APIs for file based streams because a missing header would usually indicate a +// corrupted or perverse file. In addition, these APIs can take a long time to initialize because they may need to spend +// a lot of time finding the first frame. // // // @@ -84,54 +96,53 @@ // returns after about 4KB (which is the default). Consider reducing this if you have a very efficient implementation of // onRead(), or increase it if it's very inefficient. Must be a multiple of 8. // +// #define DR_FLAC_NO_CRC +// Disables CRC checks. This will offer a performance boost when CRC is unnecessary. +// +// #define DR_FLAC_NO_SIMD +// Disables SIMD optimizations (SSE on x86/x64 architectures). Use this if you are having compatibility issues with your +// compiler. +// // // // QUICK NOTES -// - Based on my tests, the performance of the 32-bit build is at about parity with the reference implementation. The 64-bit build -// is slightly faster. -// - dr_flac does not currently do any CRC checks. -// - dr_flac should work fine with valid native FLAC files, but for broadcast streams it won't work if the header and STREAMINFO -// block is unavailable. // - Audio data is output as signed 32-bit PCM, regardless of the bits per sample the FLAC stream is encoded as. // - This has not been tested on big-endian architectures. // - Rice codes in unencoded binary form (see https://xiph.org/flac/format.html#rice_partition) has not been tested. If anybody // knows where I can find some test files for this, let me know. -// - Perverse and erroneous files have not been tested. Again, if you know where I can get some test files let me know. // - dr_flac is not thread-safe, but it's APIs can be called from any thread so long as you do your own synchronization. +// - When using Ogg encapsulation, a corrupted metadata block will result in drflac_open_with_metadata() and drflac_open() +// returning inconsistent samples. #ifndef dr_flac_h #define dr_flac_h -#include #include -#ifndef DR_SIZED_TYPES_DEFINED -#define DR_SIZED_TYPES_DEFINED #if defined(_MSC_VER) && _MSC_VER < 1600 -typedef signed char dr_int8; -typedef unsigned char dr_uint8; -typedef signed short dr_int16; -typedef unsigned short dr_uint16; -typedef signed int dr_int32; -typedef unsigned int dr_uint32; -typedef signed __int64 dr_int64; -typedef unsigned __int64 dr_uint64; +typedef signed char drflac_int8; +typedef unsigned char drflac_uint8; +typedef signed short drflac_int16; +typedef unsigned short drflac_uint16; +typedef signed int drflac_int32; +typedef unsigned int drflac_uint32; +typedef signed __int64 drflac_int64; +typedef unsigned __int64 drflac_uint64; #else #include -typedef int8_t dr_int8; -typedef uint8_t dr_uint8; -typedef int16_t dr_int16; -typedef uint16_t dr_uint16; -typedef int32_t dr_int32; -typedef uint32_t dr_uint32; -typedef int64_t dr_int64; -typedef uint64_t dr_uint64; -#endif -typedef dr_int8 dr_bool8; -typedef dr_int32 dr_bool32; -#define DR_TRUE 1 -#define DR_FALSE 0 +typedef int8_t drflac_int8; +typedef uint8_t drflac_uint8; +typedef int16_t drflac_int16; +typedef uint16_t drflac_uint16; +typedef int32_t drflac_int32; +typedef uint32_t drflac_uint32; +typedef int64_t drflac_int64; +typedef uint64_t drflac_uint64; #endif +typedef drflac_uint8 drflac_bool8; +typedef drflac_uint32 drflac_bool32; +#define DRFLAC_TRUE 1 +#define DRFLAC_FALSE 0 // As data is read from the client it is placed into an internal buffer for fast access. This controls the // size of that buffer. Larger values means more speed, but also more memory. In my testing there is diminishing @@ -156,9 +167,9 @@ extern "C" { #endif #ifdef DRFLAC_64BIT -typedef uint64_t drflac_cache_t; +typedef drflac_uint64 drflac_cache_t; #else -typedef uint32_t drflac_cache_t; +typedef drflac_uint32 drflac_cache_t; #endif // The various metadata block types. @@ -197,7 +208,8 @@ typedef uint32_t drflac_cache_t; typedef enum { drflac_container_native, - drflac_container_ogg + drflac_container_ogg, + drflac_container_unknown } drflac_container; typedef enum @@ -210,29 +222,29 @@ typedef enum #pragma pack(2) typedef struct { - uint64_t firstSample; - uint64_t frameOffset; // The offset from the first byte of the header of the first frame. - uint16_t sampleCount; + drflac_uint64 firstSample; + drflac_uint64 frameOffset; // The offset from the first byte of the header of the first frame. + drflac_uint16 sampleCount; } drflac_seekpoint; #pragma pack() typedef struct { - uint16_t minBlockSize; - uint16_t maxBlockSize; - uint32_t minFrameSize; - uint32_t maxFrameSize; - uint32_t sampleRate; - uint8_t channels; - uint8_t bitsPerSample; - uint64_t totalSampleCount; - uint8_t md5[16]; + drflac_uint16 minBlockSize; + drflac_uint16 maxBlockSize; + drflac_uint32 minFrameSize; + drflac_uint32 maxFrameSize; + drflac_uint32 sampleRate; + drflac_uint8 channels; + drflac_uint8 bitsPerSample; + drflac_uint64 totalSampleCount; + drflac_uint8 md5[16]; } drflac_streaminfo; typedef struct { // The metadata type. Use this to know how to interpret the data below. - uint32_t type; + drflac_uint32 type; // A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to // not modify the contents of this buffer. Use the structures below for more meaningful and structured @@ -240,7 +252,7 @@ typedef struct const void* pRawData; // The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. - uint32_t rawDataSize; + drflac_uint32 rawDataSize; union { @@ -253,50 +265,49 @@ typedef struct struct { - uint32_t id; + drflac_uint32 id; const void* pData; - uint32_t dataSize; + drflac_uint32 dataSize; } application; struct { - uint32_t seekpointCount; + drflac_uint32 seekpointCount; const drflac_seekpoint* pSeekpoints; } seektable; struct { - uint32_t vendorLength; + drflac_uint32 vendorLength; const char* vendor; - uint32_t commentCount; + drflac_uint32 commentCount; const char* comments; } vorbis_comment; struct { char catalog[128]; - uint64_t leadInSampleCount; - dr_bool32 isCD; - uint8_t trackCount; - const uint8_t* pTrackData; + drflac_uint64 leadInSampleCount; + drflac_bool32 isCD; + drflac_uint8 trackCount; + const drflac_uint8* pTrackData; } cuesheet; struct { - uint32_t type; - uint32_t mimeLength; + drflac_uint32 type; + drflac_uint32 mimeLength; const char* mime; - uint32_t descriptionLength; + drflac_uint32 descriptionLength; const char* description; - uint32_t width; - uint32_t height; - uint32_t colorDepth; - uint32_t indexColorCount; - uint32_t pictureDataSize; - const uint8_t* pPictureData; + drflac_uint32 width; + drflac_uint32 height; + drflac_uint32 colorDepth; + drflac_uint32 indexColorCount; + drflac_uint32 pictureDataSize; + const drflac_uint8* pPictureData; } picture; } data; - } drflac_metadata; @@ -307,6 +318,9 @@ typedef struct // bytesToRead [in] The number of bytes to read. // // Returns the number of bytes actually read. +// +// A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until +// either the entire bytesToRead is filled or you have reached the end of the stream. typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); // Callback for when data needs to be seeked. @@ -319,7 +333,7 @@ typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t by // // The offset will never be negative. Whether or not it is relative to the beginning or current position is determined // by the "origin" parameter which will be either drflac_seek_origin_start or drflac_seek_origin_current. -typedef dr_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin); +typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin); // Callback for when a metadata block is read. // @@ -333,7 +347,7 @@ typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata); // Structure for internal use. Only used for decoders opened with drflac_open_memory. typedef struct { - const uint8_t* data; + const drflac_uint8* data; size_t dataSize; size_t currentReadPos; } drflac__memory_stream; @@ -360,64 +374,67 @@ typedef struct drflac_cache_t unalignedCache; // The index of the next valid cache line in the "L2" cache. - size_t nextL2Line; + drflac_uint32 nextL2Line; // The number of bits that have been consumed by the cache. This is used to determine how many valid bits are remaining. - size_t consumedBits; + drflac_uint32 consumedBits; // The cached data which was most recently read from the client. There are two levels of cache. Data flows as such: // Client -> L2 -> L1. The L2 -> L1 movement is aligned and runs on a fast path in just a few instructions. drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)]; drflac_cache_t cache; + // CRC-16. This is updated whenever bits are read from the bit stream. Manually set this to 0 to reset the CRC. For FLAC, this + // is reset to 0 at the beginning of each frame. + drflac_uint16 crc16; + drflac_cache_t crc16Cache; // A cache for optimizing CRC calculations. This is filled when when the L1 cache is reloaded. + drflac_uint32 crc16CacheIgnoredBytes; // The number of bytes to ignore when updating the CRC-16 from the CRC-16 cache. } drflac_bs; typedef struct { // The type of the subframe: SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED or SUBFRAME_LPC. - uint8_t subframeType; + drflac_uint8 subframeType; // The number of wasted bits per sample as specified by the sub-frame header. - uint8_t wastedBitsPerSample; + drflac_uint8 wastedBitsPerSample; // The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC. - uint8_t lpcOrder; + drflac_uint8 lpcOrder; // The number of bits per sample for this subframe. This is not always equal to the current frame's bit per sample because // an extra bit is required for side channels when interchannel decorrelation is being used. - uint32_t bitsPerSample; - - // A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData, or - // NULL if the heap is not being used. Note that it's a signed 32-bit integer for each value. - int32_t* pDecodedSamples; + drflac_uint32 bitsPerSample; + // A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData. Note that + // it's a signed 32-bit integer for each value. + drflac_int32* pDecodedSamples; } drflac_subframe; typedef struct { // If the stream uses variable block sizes, this will be set to the index of the first sample. If fixed block sizes are used, this will // always be set to 0. - uint64_t sampleNumber; + drflac_uint64 sampleNumber; // If the stream uses fixed block sizes, this will be set to the frame number. If variable block sizes are used, this will always be 0. - uint32_t frameNumber; + drflac_uint32 frameNumber; // The sample rate of this frame. - uint32_t sampleRate; + drflac_uint32 sampleRate; // The number of samples in each sub-frame within this frame. - uint16_t blockSize; + drflac_uint16 blockSize; // The channel assignment of this frame. This is not always set to the channel count. If interchannel decorrelation is being used this // will be set to DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE, DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE or DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE. - uint8_t channelAssignment; + drflac_uint8 channelAssignment; // The number of bits per sample within this frame. - uint8_t bitsPerSample; - - // The frame's CRC. This is set, but unused at the moment. - uint8_t crc8; + drflac_uint8 bitsPerSample; + // The frame's CRC. + drflac_uint8 crc8; } drflac_frame_header; typedef struct @@ -427,11 +444,10 @@ typedef struct // The number of samples left to be read in this frame. This is initially set to the block size multiplied by the channel count. As samples // are read, this will be decremented. When it reaches 0, the decoder will see this frame as fully consumed and load the next frame. - uint32_t samplesRemaining; + drflac_uint32 samplesRemaining; // The list of sub-frames within the frame. There is one sub-frame for each channel, and there's a maximum of 8 channels. drflac_subframe subframes[8]; - } drflac_frame; typedef struct @@ -444,22 +460,22 @@ typedef struct // The sample rate. Will be set to something like 44100. - uint32_t sampleRate; + drflac_uint32 sampleRate; // The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. Maximum 8. This is set based on the // value specified in the STREAMINFO block. - uint8_t channels; + drflac_uint8 channels; // The bits per sample. Will be set to somthing like 16, 24, etc. - uint8_t bitsPerSample; + drflac_uint8 bitsPerSample; // The maximum block size, in samples. This number represents the number of samples in each channel (not combined). - uint16_t maxBlockSize; + drflac_uint16 maxBlockSize; // The total number of samples making up the stream. This includes every channel. For example, if the stream has 2 channels, // with each channel having a total of 4096, this value will be set to 2*4096 = 8192. Can be 0 in which case it's still a // valid stream, but just means the total sample count is unknown. Likely the case with streams like internet radio. - uint64_t totalSampleCount; + drflac_uint64 totalSampleCount; // The container type. This is set based on whether or not the decoder was opened from a native or Ogg stream. @@ -467,34 +483,34 @@ typedef struct // The position of the seektable in the file. - uint64_t seektablePos; + drflac_uint64 seektablePos; // The size of the seektable. - uint32_t seektableSize; + drflac_uint32 seektableSize; // Information about the frame the decoder is currently sitting on. drflac_frame currentFrame; // The position of the first frame in the stream. This is only ever used for seeking. - uint64_t firstFramePos; + drflac_uint64 firstFramePos; // A hack to avoid a malloc() when opening a decoder with drflac_open_memory(). drflac__memory_stream memoryStream; - // A pointer to the decoded sample data. This is an offset of pExtraData. - int32_t* pDecodedSamples; + drflac_int32* pDecodedSamples; + // Internal use only. Only used with Ogg containers. Points to a drflac_oggbs object. This is an offset of pExtraData. + void* _oggbs; // The bit streamer. The raw FLAC data is fed through this object. drflac_bs bs; - // Variable length extra data. We attach this to the end of the object so we avoid unnecessary mallocs. - uint8_t pExtraData[1]; - + // Variable length extra data. We attach this to the end of the object so we can avoid unnecessary mallocs. + drflac_uint8 pExtraData[1]; } drflac; @@ -515,11 +531,22 @@ typedef struct // This is the lowest level function for opening a FLAC stream. You can also use drflac_open_file() and drflac_open_memory() // to open the stream from a file or from a block of memory respectively. // -// The STREAMINFO block must be present for this to succeed. +// The STREAMINFO block must be present for this to succeed. Use drflac_open_relaxed() to open a FLAC stream where +// the header may not be present. // // See also: drflac_open_file(), drflac_open_memory(), drflac_open_with_metadata(), drflac_close() drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData); +// The same as drflac_open(), except attempts to open the stream even when a header block is not present. +// +// Because the header is not necessarily available, the caller must explicitly define the container (Native or Ogg). Do +// not set this to drflac_container_unknown - that is for internal use only. +// +// Opening in relaxed mode will continue reading data from onRead until it finds a valid frame. If a frame is never +// found it will continue forever. To abort, force your onRead callback to return 0, which dr_flac will use as an +// indicator that the end of the stream was found. +drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData); + // Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.). // // onRead [in] The function to call when data needs to be read from the client. @@ -531,15 +558,29 @@ drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUse // // Close the decoder with drflac_close(). // -// This is slower than drflac_open(), so avoid this one if you don't need metadata. Internally, this will do a malloc() -// and free() for every metadata block except for STREAMINFO and PADDING blocks. +// This is slower than drflac_open(), so avoid this one if you don't need metadata. Internally, this will do a DRFLAC_MALLOC() +// and DRFLAC_FREE() for every metadata block except for STREAMINFO and PADDING blocks. // -// The caller is notified of the metadata via the onMeta callback. All metadata blocks with be handled before the function +// The caller is notified of the metadata via the onMeta callback. All metadata blocks will be handled before the function // returns. // +// The STREAMINFO block must be present for this to succeed. Use drflac_open_with_metadata_relaxed() to open a FLAC +// stream where the header may not be present. +// +// Note that this will behave inconsistently with drflac_open() if the stream is an Ogg encapsulated stream and a metadata +// block is corrupted. This is due to the way the Ogg stream recovers from corrupted pages. When drflac_open_with_metadata() +// is being used, the open routine will try to read the contents of the metadata block, whereas drflac_open() will simply +// seek past it (for the sake of efficiency). This inconsistency can result in different samples being returned depending on +// whether or not the stream is being opened with metadata. +// // See also: drflac_open_file_with_metadata(), drflac_open_memory_with_metadata(), drflac_open(), drflac_close() drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData); +// The same as drflac_open_with_metadata(), except attemps to open the stream even when a header block is not present. +// +// See also: drflac_open_with_metadata(), drflac_open_relaxed() +drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData); + // Closes the given FLAC decoder. // // pFlac [in] The decoder to close. @@ -558,25 +599,50 @@ void drflac_close(drflac* pFlac); // // pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of samples // seeked. -uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* pBufferOut); +drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int32* pBufferOut); -// Same as drflac_read_s32(), except outputs samples as 16-bit integer PCM rather than 32-bit. Note -// that this is lossey. -uint64_t drflac_read_s16(drflac* pFlac, uint64_t samplesToRead, int16_t* pBufferOut); +// Same as drflac_read_s32(), except outputs samples as 16-bit integer PCM rather than 32-bit. +// +// pFlac [in] The decoder. +// samplesToRead [in] The number of samples to read. +// pBufferOut [out, optional] A pointer to the buffer that will receive the decoded samples. +// +// Returns the number of samples actually read. +// +// pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of samples +// seeked. +// +// Note that this is lossy for streams where the bits per sample is larger than 16. +drflac_uint64 drflac_read_s16(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int16* pBufferOut); + +// Same as drflac_read_s32(), except outputs samples as 32-bit floating-point PCM. +// +// pFlac [in] The decoder. +// samplesToRead [in] The number of samples to read. +// pBufferOut [out, optional] A pointer to the buffer that will receive the decoded samples. +// +// Returns the number of samples actually read. +// +// pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of samples +// seeked. +// +// Note that this should be considered lossy due to the nature of floating point numbers not being able to exactly +// represent every possible number. +drflac_uint64 drflac_read_f32(drflac* pFlac, drflac_uint64 samplesToRead, float* pBufferOut); // Seeks to the sample at the given index. // // pFlac [in] The decoder. // sampleIndex [in] The index of the sample to seek to. See notes below. // -// Returns DR_TRUE if successful; DR_FALSE otherwise. +// Returns DRFLAC_TRUE if successful; DRFLAC_FALSE otherwise. // // The sample index is based on interleaving. In a stereo stream, for example, the sample at index 0 is the first sample // in the left channel; the sample at index 1 is the first sample on the right channel, and so on. // // When seeking, you will likely want to ensure it's rounded to a multiple of the channel count. You can do this with // something like drflac_seek_to_sample(pFlac, (mySampleIndex + (mySampleIndex % pFlac->channels))) -dr_bool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex); +drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex); @@ -618,43 +684,58 @@ drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drfl //// High Level APIs //// // Opens a FLAC stream from the given callbacks and fully decodes it in a single operation. The return value is a -// pointer to the sample data as interleaved signed 32-bit PCM. The returned data must be freed with drflac_free(). +// pointer to the sample data as interleaved signed 32-bit PCM. The returned data must be freed with DRFLAC_FREE(). // // Sometimes a FLAC file won't keep track of the total sample count. In this situation the function will continuously // read samples into a dynamically sized buffer on the heap until no samples are left. // // Do not call this function on a broadcast type of stream (like internet radio streams and whatnot). -int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount); -int16_t* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount); +drflac_int32* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); + +// Same as drflac_open_and_decode_s32(), except returns signed 16-bit integer samples. +drflac_int16* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); + +// Same as drflac_open_and_decode_s32(), except returns 32-bit floating-point samples. +float* drflac_open_and_decode_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); #ifndef DR_FLAC_NO_STDIO // Same as drflac_open_and_decode_s32() except opens the decoder from a file. -int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount); -int16_t* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount); +drflac_int32* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); + +// Same as drflac_open_and_decode_file_s32(), except returns signed 16-bit integer samples. +drflac_int16* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); + +// Same as drflac_open_and_decode_file_f32(), except returns 32-bit floating-point samples. +float* drflac_open_and_decode_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); #endif // Same as drflac_open_and_decode_s32() except opens the decoder from a block of memory. -int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount); -int16_t* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount); +drflac_int32* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); -// Frees data returned by drflac_open_and_decode_*(). -void drflac_free(void* pSampleDataReturnedByOpenAndDecode); +// Same as drflac_open_and_decode_memory_s32(), except returns signed 16-bit integer samples. +drflac_int16* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); + +// Same as drflac_open_and_decode_memory_s32(), except returns 32-bit floating-point samples. +float* drflac_open_and_decode_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); + +// Frees memory that was allocated internally by dr_flac. +void drflac_free(void* p); // Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block. typedef struct { - uint32_t countRemaining; + drflac_uint32 countRemaining; const char* pRunningData; } drflac_vorbis_comment_iterator; // Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT // metadata block. -void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, uint32_t commentCount, const char* pComments); +void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const char* pComments); // Goes to the next vorbis comment in the given iterator. If null is returned it means there are no more comments. The // returned string is NOT null terminated. -const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, uint32_t* pCommentLengthOut); +const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut); @@ -672,22 +753,119 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, ui #ifdef DR_FLAC_IMPLEMENTATION #include #include -#include -#ifdef _MSC_VER -#include // For _byteswap_ulong and _byteswap_uint64 +// CPU architecture. +#if defined(__x86_64__) || defined(_M_X64) +#define DRFLAC_X64 +#elif defined(__i386) || defined(_M_IX86) +#define DRFLAC_X86 #endif +// Compile-time CPU feature support. +#if !defined(DR_FLAC_NO_SIMD) && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) + #ifdef _MSC_VER + #if _MSC_VER >= 1400 + #include + static void drflac__cpuid(int info[4], int fid) + { + __cpuid(info, fid); + } + #else + #define DRFLAC_NO_CPUID + #endif + #else + #if defined(__GNUC__) || defined(__clang__) + static void drflac__cpuid(int info[4], int fid) + { + asm ( + "movl %[fid], %%eax\n\t" + "cpuid\n\t" + "movl %%eax, %[info0]\n\t" + "movl %%ebx, %[info1]\n\t" + "movl %%ecx, %[info2]\n\t" + "movl %%edx, %[info3]\n\t" + : [info0] "=rm"(info[0]), + [info1] "=rm"(info[1]), + [info2] "=rm"(info[2]), + [info3] "=rm"(info[3]) + : [fid] "rm"(fid) + : "eax", "ebx", "ecx", "edx" + ); + } + #else + #define DRFLAC_NO_CPUID + #endif + #endif +#else +#define DRFLAC_NO_CPUID +#endif + + #ifdef __linux__ #define _BSD_SOURCE #include #endif +#if defined(_MSC_VER) && _MSC_VER >= 1500 +#define DRFLAC_HAS_LZCNT_INTRINSIC +#elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) +#define DRFLAC_HAS_LZCNT_INTRINSIC +#elif defined(__clang__) + #if __has_builtin(__builtin_clzll) || __has_builtin(__builtin_clzl) + #define DRFLAC_HAS_LZCNT_INTRINSIC + #endif +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1300 +#define DRFLAC_HAS_BYTESWAP_INTRINSIC +#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) +#define DRFLAC_HAS_BYTESWAP_INTRINSIC +#elif defined(__clang__) + #if __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64) + #define DRFLAC_HAS_BYTESWAP_INTRINSIC + #endif +#endif + + +// Standard library stuff. +#ifndef DRFLAC_ASSERT +#include +#define DRFLAC_ASSERT(expression) assert(expression) +#endif +#ifndef DRFLAC_MALLOC +#define DRFLAC_MALLOC(sz) malloc((sz)) +#endif +#ifndef DRFLAC_REALLOC +#define DRFLAC_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef DRFLAC_FREE +#define DRFLAC_FREE(p) free((p)) +#endif +#ifndef DRFLAC_COPY_MEMORY +#define DRFLAC_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#endif +#ifndef DRFLAC_ZERO_MEMORY +#define DRFLAC_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +#endif + +#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 // 64 for AVX-512 in the future. + #ifdef _MSC_VER #define DRFLAC_INLINE __forceinline #else +#ifdef __GNUC__ +#define DRFLAC_INLINE inline __attribute__((always_inline)) +#else #define DRFLAC_INLINE inline #endif +#endif + +typedef drflac_int32 drflac_result; +#define DRFLAC_SUCCESS 0 +#define DRFLAC_ERROR -1 // A generic error. +#define DRFLAC_INVALID_ARGS -2 +#define DRFLAC_END_OF_STREAM -128 +#define DRFLAC_CRC_MISMATCH -129 #define DRFLAC_SUBFRAME_CONSTANT 0 #define DRFLAC_SUBFRAME_VERBATIM 1 @@ -704,31 +882,68 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, ui #define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10 -//// Endian Management //// -static DRFLAC_INLINE dr_bool32 drflac__is_little_endian() +#define drflac_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) +#define drflac_assert DRFLAC_ASSERT +#define drflac_copy_memory DRFLAC_COPY_MEMORY +#define drflac_zero_memory DRFLAC_ZERO_MEMORY + + +// CPU caps. +static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE; +#ifndef DRFLAC_NO_CPUID +static drflac_bool32 drflac__gIsSSE42Supported = DRFLAC_FALSE; +static void drflac__init_cpu_caps() { + int info[4] = {0}; + + // LZCNT + drflac__cpuid(info, 0x80000001); + drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0; + + // SSE4.2 + drflac__cpuid(info, 1); + drflac__gIsSSE42Supported = (info[2] & (1 << 19)) != 0; +} +#endif + + +//// Endian Management //// +static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian() +{ +#if defined(DRFLAC_X86) || defined(DRFLAC_X64) + return DRFLAC_TRUE; +#else int n = 1; return (*(char*)&n) == 1; +#endif } -static DRFLAC_INLINE uint16_t drflac__swap_endian_uint16(uint16_t n) +static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n) { -#ifdef _MSC_VER - return _byteswap_ushort(n); -#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - return __builtin_bswap16(n); +#ifdef DRFLAC_HAS_BYTESWAP_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_ushort(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap16(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif #else return ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); #endif } -static DRFLAC_INLINE uint32_t drflac__swap_endian_uint32(uint32_t n) +static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n) { -#ifdef _MSC_VER - return _byteswap_ulong(n); -#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - return __builtin_bswap32(n); +#ifdef DRFLAC_HAS_BYTESWAP_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_ulong(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap32(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif #else return ((n & 0xFF000000) >> 24) | ((n & 0x00FF0000) >> 8) | @@ -737,25 +952,30 @@ static DRFLAC_INLINE uint32_t drflac__swap_endian_uint32(uint32_t n) #endif } -static DRFLAC_INLINE uint64_t drflac__swap_endian_uint64(uint64_t n) +static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n) { -#ifdef _MSC_VER - return _byteswap_uint64(n); -#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - return __builtin_bswap64(n); +#ifdef DRFLAC_HAS_BYTESWAP_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_uint64(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap64(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif #else - return ((n & 0xFF00000000000000ULL) >> 56) | - ((n & 0x00FF000000000000ULL) >> 40) | - ((n & 0x0000FF0000000000ULL) >> 24) | - ((n & 0x000000FF00000000ULL) >> 8) | - ((n & 0x00000000FF000000ULL) << 8) | - ((n & 0x0000000000FF0000ULL) << 24) | - ((n & 0x000000000000FF00ULL) << 40) | - ((n & 0x00000000000000FFULL) << 56); + return ((n & (drflac_uint64)0xFF00000000000000) >> 56) | + ((n & (drflac_uint64)0x00FF000000000000) >> 40) | + ((n & (drflac_uint64)0x0000FF0000000000) >> 24) | + ((n & (drflac_uint64)0x000000FF00000000) >> 8) | + ((n & (drflac_uint64)0x00000000FF000000) << 8) | + ((n & (drflac_uint64)0x0000000000FF0000) << 24) | + ((n & (drflac_uint64)0x000000000000FF00) << 40) | + ((n & (drflac_uint64)0x00000000000000FF) << 56); #endif } -static DRFLAC_INLINE uint16_t drflac__be2host_16(uint16_t n) + +static DRFLAC_INLINE drflac_uint16 drflac__be2host_16(drflac_uint16 n) { #ifdef __linux__ return be16toh(n); @@ -768,7 +988,7 @@ static DRFLAC_INLINE uint16_t drflac__be2host_16(uint16_t n) #endif } -static DRFLAC_INLINE uint32_t drflac__be2host_32(uint32_t n) +static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n) { #ifdef __linux__ return be32toh(n); @@ -781,7 +1001,7 @@ static DRFLAC_INLINE uint32_t drflac__be2host_32(uint32_t n) #endif } -static DRFLAC_INLINE uint64_t drflac__be2host_64(uint64_t n) +static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n) { #ifdef __linux__ return be64toh(n); @@ -795,7 +1015,7 @@ static DRFLAC_INLINE uint64_t drflac__be2host_64(uint64_t n) } -static DRFLAC_INLINE uint32_t drflac__le2host_32(uint32_t n) +static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n) { #ifdef __linux__ return le32toh(n); @@ -809,13 +1029,242 @@ static DRFLAC_INLINE uint32_t drflac__le2host_32(uint32_t n) } +static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n) +{ + drflac_uint32 result = 0; + result |= (n & 0x7F000000) >> 3; + result |= (n & 0x007F0000) >> 2; + result |= (n & 0x00007F00) >> 1; + result |= (n & 0x0000007F) >> 0; + + return result; +} + + + +// The CRC code below is based on this document: http://zlib.net/crc_v3.txt +static drflac_uint8 drflac__crc8_table[] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 +}; + +static drflac_uint16 drflac__crc16_table[] = { + 0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011, + 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022, + 0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072, + 0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041, + 0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2, + 0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1, + 0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1, + 0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082, + 0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192, + 0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1, + 0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1, + 0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2, + 0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151, + 0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162, + 0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132, + 0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101, + 0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312, + 0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371, + 0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342, + 0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1, + 0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2, + 0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2, + 0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381, + 0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291, + 0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2, + 0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2, + 0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1, + 0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252, + 0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261, + 0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231, + 0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202 +}; + +static DRFLAC_INLINE drflac_uint8 drflac_crc8_byte(drflac_uint8 crc, drflac_uint8 data) +{ + return drflac__crc8_table[crc ^ data]; +} + +static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 data, drflac_uint32 count) +{ + drflac_assert(count <= 32); + +#ifdef DR_FLAC_NO_CRC + (void)crc; + (void)data; + (void)count; + return 0; +#else +#if 0 + // REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc8(crc, 0, 8);") + drflac_uint8 p = 0x07; + for (int i = count-1; i >= 0; --i) { + drflac_uint8 bit = (data & (1 << i)) >> i; + if (crc & 0x80) { + crc = ((crc << 1) | bit) ^ p; + } else { + crc = ((crc << 1) | bit); + } + } + return crc; +#else + drflac_uint32 wholeBytes = count >> 3; + drflac_uint32 leftoverBits = count - (wholeBytes*8); + + static drflac_uint64 leftoverDataMaskTable[8] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + drflac_uint64 leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + switch (wholeBytes) { + case 4: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc8_table[(crc >> (8 - leftoverBits)) ^ (data & leftoverDataMask)]; + } + return crc; +#endif +#endif +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16_byte(drflac_uint16 crc, drflac_uint8 data) +{ + return (crc << 8) ^ drflac__crc16_table[(drflac_uint8)(crc >> 8) ^ data]; +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16_bytes(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 byteCount) +{ + switch (byteCount) + { +#ifdef DRFLAC_64BIT + case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF)); + case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF)); + case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF)); + case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF)); +#endif + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF)); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF)); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 8) & 0xFF)); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 0) & 0xFF)); + } + + return crc; +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac_uint32 data, drflac_uint32 count) +{ + drflac_assert(count <= 64); + +#ifdef DR_FLAC_NO_CRC + (void)crc; + (void)data; + (void)count; + return 0; +#else +#if 0 + // REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc16(crc, 0, 16);") + drflac_uint16 p = 0x8005; + for (int i = count-1; i >= 0; --i) { + drflac_uint16 bit = (data & (1ULL << i)) >> i; + if (r & 0x8000) { + r = ((r << 1) | bit) ^ p; + } else { + r = ((r << 1) | bit); + } + } + + return crc; +#else + drflac_uint32 wholeBytes = count >> 3; + drflac_uint32 leftoverBits = count - (wholeBytes*8); + + static drflac_uint64 leftoverDataMaskTable[8] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + drflac_uint64 leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + switch (wholeBytes) { + default: + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)]; + } + return crc; +#endif +#endif +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16__64bit(drflac_uint16 crc, drflac_uint64 data, drflac_uint32 count) +{ + drflac_assert(count <= 64); + +#ifdef DR_FLAC_NO_CRC + (void)crc; + (void)data; + (void)count; + return 0; +#else + drflac_uint32 wholeBytes = count >> 3; + drflac_uint32 leftoverBits = count - (wholeBytes*8); + + static drflac_uint64 leftoverDataMaskTable[8] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + drflac_uint64 leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + switch (wholeBytes) { + default: + case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0xFF00000000000000 << leftoverBits)) >> (56 + leftoverBits))); + case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x00FF000000000000 << leftoverBits)) >> (48 + leftoverBits))); + case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x0000FF0000000000 << leftoverBits)) >> (40 + leftoverBits))); + case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x000000FF00000000 << leftoverBits)) >> (32 + leftoverBits))); + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x00000000FF000000 << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x0000000000FF0000 << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x000000000000FF00 << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x00000000000000FF << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)]; + } + return crc; +#endif +} + + +static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 count) +{ +#ifdef DRFLAC_64BIT + return drflac_crc16__64bit(crc, data, count); +#else + return drflac_crc16__32bit(crc, data, count); +#endif +} + + #ifdef DRFLAC_64BIT #define drflac__be2host__cache_line drflac__be2host_64 #else #define drflac__be2host__cache_line drflac__be2host_32 #endif - // BIT READING ATTEMPT #2 // // This uses a 32- or 64-bit bit-shifted cache - as bits are read, the cache is shifted such that the first valid bit is sitting @@ -827,9 +1276,9 @@ static DRFLAC_INLINE uint32_t drflac__le2host_32(uint32_t n) #define DRFLAC_CACHE_L1_SIZE_BITS(bs) (sizeof((bs)->cache)*8) #define DRFLAC_CACHE_L1_BITS_REMAINING(bs) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - ((bs)->consumedBits)) #ifdef DRFLAC_64BIT -#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((uint64_t)-1LL) >> (_bitCount))) +#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((drflac_uint64)-1LL) >> (_bitCount))) #else -#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((uint32_t)-1) >> (_bitCount))) +#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((drflac_uint32)-1) >> (_bitCount))) #endif #define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount)) #define DRFLAC_CACHE_L1_SELECT(bs, _bitCount) (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount)) @@ -838,18 +1287,54 @@ static DRFLAC_INLINE uint32_t drflac__le2host_32(uint32_t n) #define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0])) #define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line) -static DRFLAC_INLINE dr_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs) + +#ifndef DR_FLAC_NO_CRC +static DRFLAC_INLINE void drflac__reset_crc16(drflac_bs* bs) +{ + bs->crc16 = 0; + bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; +} + +static DRFLAC_INLINE void drflac__update_crc16(drflac_bs* bs) +{ + bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache, DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bs->crc16CacheIgnoredBytes); + bs->crc16CacheIgnoredBytes = 0; +} + +static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs) +{ + // We should never be flushing in a situation where we are not aligned on a byte boundary. + drflac_assert((DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0); + + // The bits that were read from the L1 cache need to be accumulated. The number of bytes needing to be accumulated is determined + // by the number of bits that have been consumed. + if (DRFLAC_CACHE_L1_BITS_REMAINING(bs) == 0) { + drflac__update_crc16(bs); + } else { + // We only accumulate the consumed bits. + bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache >> DRFLAC_CACHE_L1_BITS_REMAINING(bs), (bs->consumedBits >> 3) - bs->crc16CacheIgnoredBytes); + + // The bits that we just accumulated should never be accumulated again. We need to keep track of how many bytes were accumulated + // so we can handle that later. + bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; + } + + return bs->crc16; +} +#endif + +static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs) { // Fast path. Try loading straight from L2. if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { bs->cache = bs->cacheL2[bs->nextL2Line++]; - return DR_TRUE; + return DRFLAC_TRUE; } // If we get here it means we've run out of data in the L2 cache. We'll need to fetch more from the client, if there's // any left. if (bs->unalignedByteCount > 0) { - return DR_FALSE; // If we have any unaligned bytes it means there's not more aligned bytes left in the client. + return DRFLAC_FALSE; // If we have any unaligned bytes it means there's no more aligned bytes left in the client. } size_t bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs)); @@ -857,7 +1342,7 @@ static DRFLAC_INLINE dr_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs) bs->nextL2Line = 0; if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) { bs->cache = bs->cacheL2[bs->nextL2Line++]; - return DR_TRUE; + return DRFLAC_TRUE; } @@ -870,35 +1355,39 @@ static DRFLAC_INLINE dr_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs) // We need to keep track of any unaligned bytes for later use. bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs)); if (bs->unalignedByteCount > 0) { - bs->unalignedCache = bs->cacheL2[alignedL1LineCount]; + bs->unalignedCache = bs->cacheL2[alignedL1LineCount]; } - if (alignedL1LineCount > 0) - { + if (alignedL1LineCount > 0) { size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount; for (size_t i = alignedL1LineCount; i > 0; --i) { bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1]; } - bs->nextL2Line = offset; + bs->nextL2Line = (drflac_uint32)offset; bs->cache = bs->cacheL2[bs->nextL2Line++]; - return DR_TRUE; - } - else - { + return DRFLAC_TRUE; + } else { // If we get into this branch it means we weren't able to load any L1-aligned data. bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); - return DR_FALSE; + return DRFLAC_FALSE; } } -static dr_bool32 drflac__reload_cache(drflac_bs* bs) +static drflac_bool32 drflac__reload_cache(drflac_bs* bs) { +#ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); +#endif + // Fast path. Try just moving the next value in the L2 cache to the L1 cache. if (drflac__reload_l1_cache_from_l2(bs)) { bs->cache = drflac__be2host__cache_line(bs->cache); bs->consumedBits = 0; - return DR_TRUE; +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache; +#endif + return DRFLAC_TRUE; } // Slow path. @@ -908,15 +1397,21 @@ static dr_bool32 drflac__reload_cache(drflac_bs* bs) // data from the unaligned cache. size_t bytesRead = bs->unalignedByteCount; if (bytesRead == 0) { - return DR_FALSE; + return DRFLAC_FALSE; } - assert(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs)); - bs->consumedBits = (DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8; + drflac_assert(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs)); + bs->consumedBits = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8; bs->cache = drflac__be2host__cache_line(bs->unalignedCache); bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs->consumedBits); // <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property. - return DR_TRUE; + bs->unalignedByteCount = 0; // <-- At this point the unaligned bytes have been moved into the cache and we thus have no more unaligned bytes. + +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache >> bs->consumedBits; + bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; +#endif + return DRFLAC_TRUE; } static void drflac__reset_cache(drflac_bs* bs) @@ -926,69 +1421,24 @@ static void drflac__reset_cache(drflac_bs* bs) bs->cache = 0; bs->unalignedByteCount = 0; // <-- This clears the trailing unaligned bytes. bs->unalignedCache = 0; + +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = 0; + bs->crc16CacheIgnoredBytes = 0; +#endif } -static dr_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek) + +static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, drflac_uint32* pResultOut) { - if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { - bs->consumedBits += bitsToSeek; - bs->cache <<= bitsToSeek; - return DR_TRUE; - } else { - // It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here. - bitsToSeek -= DRFLAC_CACHE_L1_BITS_REMAINING(bs); - bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs); - bs->cache = 0; - - size_t wholeBytesRemaining = bitsToSeek/8; - if (wholeBytesRemaining > 0) - { - // The next bytes to seek will be located in the L2 cache. The problem is that the L2 cache is not byte aligned, - // but rather DRFLAC_CACHE_L1_SIZE_BYTES aligned (usually 4 or 8). If, for example, the number of bytes to seek is - // 3, we'll need to handle it in a special way. - size_t wholeCacheLinesRemaining = wholeBytesRemaining / DRFLAC_CACHE_L1_SIZE_BYTES(bs); - if (wholeCacheLinesRemaining < DRFLAC_CACHE_L2_LINES_REMAINING(bs)) - { - wholeBytesRemaining -= wholeCacheLinesRemaining * DRFLAC_CACHE_L1_SIZE_BYTES(bs); - bitsToSeek -= wholeCacheLinesRemaining * DRFLAC_CACHE_L1_SIZE_BITS(bs); - bs->nextL2Line += wholeCacheLinesRemaining; - } - else - { - wholeBytesRemaining -= DRFLAC_CACHE_L2_LINES_REMAINING(bs) * DRFLAC_CACHE_L1_SIZE_BYTES(bs); - bitsToSeek -= DRFLAC_CACHE_L2_LINES_REMAINING(bs) * DRFLAC_CACHE_L1_SIZE_BITS(bs); - bs->nextL2Line += DRFLAC_CACHE_L2_LINES_REMAINING(bs); - - if (wholeBytesRemaining > 0) { - bs->onSeek(bs->pUserData, (int)wholeBytesRemaining, drflac_seek_origin_current); - bitsToSeek -= wholeBytesRemaining*8; - } - } - } - - - if (bitsToSeek > 0) { - if (!drflac__reload_cache(bs)) { - return DR_FALSE; - } - - return drflac__seek_bits(bs, bitsToSeek); - } - - return DR_TRUE; - } -} - -static dr_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, uint32_t* pResultOut) -{ - assert(bs != NULL); - assert(pResultOut != NULL); - assert(bitCount > 0); - assert(bitCount <= 32); + drflac_assert(bs != NULL); + drflac_assert(pResultOut != NULL); + drflac_assert(bitCount > 0); + drflac_assert(bitCount <= 32); if (bs->consumedBits == DRFLAC_CACHE_L1_SIZE_BITS(bs)) { if (!drflac__reload_cache(bs)) { - return DR_FALSE; + return DRFLAC_FALSE; } } @@ -998,165 +1448,259 @@ static dr_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, uint3 bs->consumedBits += bitCount; bs->cache <<= bitCount; } else { - *pResultOut = (uint32_t)bs->cache; + *pResultOut = (drflac_uint32)bs->cache; bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); bs->cache = 0; } - return DR_TRUE; + return DRFLAC_TRUE; } else { // It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. - size_t bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs); - size_t bitCountLo = bitCount - bitCountHi; - uint32_t resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi); + drflac_uint32 bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs); + drflac_uint32 bitCountLo = bitCount - bitCountHi; + drflac_uint32 resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi); if (!drflac__reload_cache(bs)) { - return DR_FALSE; + return DRFLAC_FALSE; } *pResultOut = (resultHi << bitCountLo) | DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo); bs->consumedBits += bitCountLo; bs->cache <<= bitCountLo; - return DR_TRUE; + return DRFLAC_TRUE; } } -static dr_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, int32_t* pResult) +static drflac_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, drflac_int32* pResult) { - assert(bs != NULL); - assert(pResult != NULL); - assert(bitCount > 0); - assert(bitCount <= 32); + drflac_assert(bs != NULL); + drflac_assert(pResult != NULL); + drflac_assert(bitCount > 0); + drflac_assert(bitCount <= 32); - uint32_t result; + drflac_uint32 result; if (!drflac__read_uint32(bs, bitCount, &result)) { - return DR_FALSE; + return DRFLAC_FALSE; } - uint32_t signbit = ((result >> (bitCount-1)) & 0x01); + drflac_uint32 signbit = ((result >> (bitCount-1)) & 0x01); result |= (~signbit + 1) << bitCount; - *pResult = (int32_t)result; - return DR_TRUE; + *pResult = (drflac_int32)result; + return DRFLAC_TRUE; } -static dr_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, uint64_t* pResultOut) +static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, drflac_uint64* pResultOut) { - assert(bitCount <= 64); - assert(bitCount > 32); + drflac_assert(bitCount <= 64); + drflac_assert(bitCount > 32); - uint32_t resultHi; + drflac_uint32 resultHi; if (!drflac__read_uint32(bs, bitCount - 32, &resultHi)) { - return DR_FALSE; + return DRFLAC_FALSE; } - uint32_t resultLo; + drflac_uint32 resultLo; if (!drflac__read_uint32(bs, 32, &resultLo)) { - return DR_FALSE; + return DRFLAC_FALSE; } - *pResultOut = (((uint64_t)resultHi) << 32) | ((uint64_t)resultLo); - return DR_TRUE; + *pResultOut = (((drflac_uint64)resultHi) << 32) | ((drflac_uint64)resultLo); + return DRFLAC_TRUE; } // Function below is unused, but leaving it here in case I need to quickly add it again. #if 0 -static dr_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, int64_t* pResultOut) +static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, drflac_int64* pResultOut) { - assert(bitCount <= 64); + drflac_assert(bitCount <= 64); - uint64_t result; + drflac_uint64 result; if (!drflac__read_uint64(bs, bitCount, &result)) { - return DR_FALSE; + return DRFLAC_FALSE; } - uint64_t signbit = ((result >> (bitCount-1)) & 0x01); + drflac_uint64 signbit = ((result >> (bitCount-1)) & 0x01); result |= (~signbit + 1) << bitCount; - *pResultOut = (int64_t)result; - return DR_TRUE; + *pResultOut = (drflac_int64)result; + return DRFLAC_TRUE; } #endif -static dr_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, uint16_t* pResult) +static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, drflac_uint16* pResult) { - assert(bs != NULL); - assert(pResult != NULL); - assert(bitCount > 0); - assert(bitCount <= 16); + drflac_assert(bs != NULL); + drflac_assert(pResult != NULL); + drflac_assert(bitCount > 0); + drflac_assert(bitCount <= 16); - uint32_t result; + drflac_uint32 result; if (!drflac__read_uint32(bs, bitCount, &result)) { - return DR_FALSE; + return DRFLAC_FALSE; } - *pResult = (uint16_t)result; - return DR_TRUE; + *pResult = (drflac_uint16)result; + return DRFLAC_TRUE; } -static dr_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, int16_t* pResult) +#if 0 +static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, drflac_int16* pResult) { - assert(bs != NULL); - assert(pResult != NULL); - assert(bitCount > 0); - assert(bitCount <= 16); + drflac_assert(bs != NULL); + drflac_assert(pResult != NULL); + drflac_assert(bitCount > 0); + drflac_assert(bitCount <= 16); - int32_t result; + drflac_int32 result; if (!drflac__read_int32(bs, bitCount, &result)) { - return DR_FALSE; + return DRFLAC_FALSE; } - *pResult = (int16_t)result; - return DR_TRUE; + *pResult = (drflac_int16)result; + return DRFLAC_TRUE; } +#endif -static dr_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, uint8_t* pResult) +static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, drflac_uint8* pResult) { - assert(bs != NULL); - assert(pResult != NULL); - assert(bitCount > 0); - assert(bitCount <= 8); + drflac_assert(bs != NULL); + drflac_assert(pResult != NULL); + drflac_assert(bitCount > 0); + drflac_assert(bitCount <= 8); - uint32_t result; + drflac_uint32 result; if (!drflac__read_uint32(bs, bitCount, &result)) { - return DR_FALSE; + return DRFLAC_FALSE; } - *pResult = (uint8_t)result; - return DR_TRUE; + *pResult = (drflac_uint8)result; + return DRFLAC_TRUE; } -static dr_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, int8_t* pResult) +static drflac_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, drflac_int8* pResult) { - assert(bs != NULL); - assert(pResult != NULL); - assert(bitCount > 0); - assert(bitCount <= 8); + drflac_assert(bs != NULL); + drflac_assert(pResult != NULL); + drflac_assert(bitCount > 0); + drflac_assert(bitCount <= 8); - int32_t result; + drflac_int32 result; if (!drflac__read_int32(bs, bitCount, &result)) { - return DR_FALSE; + return DRFLAC_FALSE; } - *pResult = (int8_t)result; - return DR_TRUE; + *pResult = (drflac_int8)result; + return DRFLAC_TRUE; } -static inline dr_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut) +static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek) { - unsigned int zeroCounter = 0; - while (bs->cache == 0) { - zeroCounter += (unsigned int)DRFLAC_CACHE_L1_BITS_REMAINING(bs); - if (!drflac__reload_cache(bs)) { - return DR_FALSE; + if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + bs->consumedBits += (drflac_uint32)bitsToSeek; + bs->cache <<= bitsToSeek; + return DRFLAC_TRUE; + } else { + // It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here. + bitsToSeek -= DRFLAC_CACHE_L1_BITS_REMAINING(bs); + bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs); + bs->cache = 0; + + // Simple case. Seek in groups of the same number as bits that fit within a cache line. +#ifdef DRFLAC_64BIT + while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + drflac_uint64 bin; + if (!drflac__read_uint64(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs); + } +#else + while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + drflac_uint32 bin; + if (!drflac__read_uint32(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs); + } +#endif + + // Whole leftover bytes. + while (bitsToSeek >= 8) { + drflac_uint8 bin; + if (!drflac__read_uint8(bs, 8, &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek -= 8; + } + + // Leftover bits. + if (bitsToSeek > 0) { + drflac_uint8 bin; + if (!drflac__read_uint8(bs, (drflac_uint32)bitsToSeek, &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek = 0; // <-- Necessary for the assert below. + } + + drflac_assert(bitsToSeek == 0); + return DRFLAC_TRUE; + } +} + + +// This function moves the bit streamer to the first bit after the sync code (bit 15 of the of the frame header). It will also update the CRC-16. +static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) +{ + drflac_assert(bs != NULL); + + // The sync code is always aligned to 8 bits. This is convenient for us because it means we can do byte-aligned movements. The first + // thing to do is align to the next byte. + if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { + return DRFLAC_FALSE; + } + + for (;;) { +#ifndef DR_FLAC_NO_CRC + drflac__reset_crc16(bs); +#endif + + drflac_uint8 hi; + if (!drflac__read_uint8(bs, 8, &hi)) { + return DRFLAC_FALSE; + } + + if (hi == 0xFF) { + drflac_uint8 lo; + if (!drflac__read_uint8(bs, 6, &lo)) { + return DRFLAC_FALSE; + } + + if (lo == 0x3E) { + return DRFLAC_TRUE; + } else { + if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { + return DRFLAC_FALSE; + } + } } } - // At this point the cache should not be zero, in which case we know the first set bit should be somewhere in here. There is - // no need for us to perform any cache reloading logic here which should make things much faster. - assert(bs->cache != 0); + // Should never get here. + //return DRFLAC_FALSE; +} - unsigned int bitOffsetTable[] = { + +#if !defined(DR_FLAC_NO_SIMD) && defined(DRFLAC_HAS_LZCNT_INTRINSIC) +#define DRFLAC_IMPLEMENT_CLZ_LZCNT +#endif +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#define DRFLAC_IMPLEMENT_CLZ_MSVC +#endif + +static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) +{ + static drflac_uint32 clz_table_4[] = { 0, 4, 3, 3, @@ -1164,91 +1708,169 @@ static inline dr_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned i 1, 1, 1, 1, 1, 1, 1, 1 }; - unsigned int setBitOffsetPlus1 = bitOffsetTable[DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, 4)]; - if (setBitOffsetPlus1 == 0) { - if (bs->cache == 1) { - setBitOffsetPlus1 = DRFLAC_CACHE_L1_SIZE_BITS(bs); - } else { - setBitOffsetPlus1 = 5; - for (;;) - { - if ((bs->cache & DRFLAC_CACHE_L1_SELECT(bs, setBitOffsetPlus1))) { - break; - } + drflac_uint32 n = clz_table_4[x >> (sizeof(x)*8 - 4)]; + if (n == 0) { +#ifdef DRFLAC_64BIT + if ((x & 0xFFFFFFFF00000000ULL) == 0) { n = 32; x <<= 32; } + if ((x & 0xFFFF000000000000ULL) == 0) { n += 16; x <<= 16; } + if ((x & 0xFF00000000000000ULL) == 0) { n += 8; x <<= 8; } + if ((x & 0xF000000000000000ULL) == 0) { n += 4; x <<= 4; } +#else + if ((x & 0xFFFF0000) == 0) { n = 16; x <<= 16; } + if ((x & 0xFF000000) == 0) { n += 8; x <<= 8; } + if ((x & 0xF0000000) == 0) { n += 4; x <<= 4; } +#endif + n += clz_table_4[x >> (sizeof(x)*8 - 4)]; + } - setBitOffsetPlus1 += 1; - } + return n - 1; +} + +#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT +static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported() +{ + // If the compiler itself does not support the intrinsic then we'll need to return false. +#ifdef DRFLAC_HAS_LZCNT_INTRINSIC + return drflac__gIsLZCNTSupported; +#else + return DRFLAC_FALSE; +#endif +} + +static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x) +{ +#ifdef _MSC_VER + #ifdef DRFLAC_64BIT + return (drflac_uint32)__lzcnt64(x); + #else + return (drflac_uint32)__lzcnt(x); + #endif +#else + #if defined(__GNUC__) || defined(__clang__) + #ifdef DRFLAC_64BIT + return (drflac_uint32)__builtin_clzll((unsigned long long)x); + #else + return (drflac_uint32)__builtin_clzl((unsigned long)x); + #endif + #else + // Unsupported compiler. + #error "This compiler does not support the lzcnt intrinsic." + #endif +#endif +} +#endif + +#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC +static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) +{ + drflac_uint32 n; +#ifdef DRFLAC_64BIT + _BitScanReverse64((unsigned long*)&n, x); +#else + _BitScanReverse((unsigned long*)&n, x); +#endif + return sizeof(x)*8 - n - 1; +} +#endif + +static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) +{ + // This function assumes at least one bit is set. Checking for 0 needs to be done at a higher level, outside this function. +#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT + if (drflac__is_lzcnt_supported()) { + return drflac__clz_lzcnt(x); + } else +#endif + { + #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC + return drflac__clz_msvc(x); + #else + return drflac__clz_software(x); + #endif + } +} + + +static inline drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut) +{ + drflac_uint32 zeroCounter = 0; + while (bs->cache == 0) { + zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; } } + drflac_uint32 setBitOffsetPlus1 = drflac__clz(bs->cache); + zeroCounter += setBitOffsetPlus1; + setBitOffsetPlus1 += 1; + bs->consumedBits += setBitOffsetPlus1; bs->cache <<= setBitOffsetPlus1; *pOffsetOut = zeroCounter + setBitOffsetPlus1 - 1; - return DR_TRUE; + return DRFLAC_TRUE; } -static dr_bool32 drflac__seek_to_byte(drflac_bs* bs, uint64_t offsetFromStart) +static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFromStart) { - assert(bs != NULL); - assert(offsetFromStart > 0); + drflac_assert(bs != NULL); + drflac_assert(offsetFromStart > 0); // Seeking from the start is not quite as trivial as it sounds because the onSeek callback takes a signed 32-bit integer (which // is intentional because it simplifies the implementation of the onSeek callbacks), however offsetFromStart is unsigned 64-bit. // To resolve we just need to do an initial seek from the start, and then a series of offset seeks to make up the remainder. - if (offsetFromStart > 0x7FFFFFFF) - { - uint64_t bytesRemaining = offsetFromStart; + if (offsetFromStart > 0x7FFFFFFF) { + drflac_uint64 bytesRemaining = offsetFromStart; if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) { - return DR_FALSE; + return DRFLAC_FALSE; } bytesRemaining -= 0x7FFFFFFF; - while (bytesRemaining > 0x7FFFFFFF) { if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) { - return DR_FALSE; + return DRFLAC_FALSE; } bytesRemaining -= 0x7FFFFFFF; } - if (bytesRemaining > 0) { if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) { - return DR_FALSE; + return DRFLAC_FALSE; } } - } - else - { + } else { if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) { - return DR_FALSE; + return DRFLAC_FALSE; } } - // The cache should be reset to force a reload of fresh data from the client. drflac__reset_cache(bs); - return DR_TRUE; + return DRFLAC_TRUE; } -static dr_bool32 drflac__read_utf8_coded_number(drflac_bs* bs, uint64_t* pNumberOut) +static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64* pNumberOut, drflac_uint8* pCRCOut) { - assert(bs != NULL); - assert(pNumberOut != NULL); + drflac_assert(bs != NULL); + drflac_assert(pNumberOut != NULL); + + drflac_uint8 crc = *pCRCOut; unsigned char utf8[7] = {0}; if (!drflac__read_uint8(bs, 8, utf8)) { *pNumberOut = 0; - return DR_FALSE; + return DRFLAC_END_OF_STREAM; } + crc = drflac_crc8(crc, utf8[0], 8); if ((utf8[0] & 0x80) == 0) { *pNumberOut = utf8[0]; - return DR_TRUE; + *pCRCOut = crc; + return DRFLAC_SUCCESS; } int byteCount = 1; @@ -1266,57 +1888,43 @@ static dr_bool32 drflac__read_utf8_coded_number(drflac_bs* bs, uint64_t* pNumber byteCount = 7; } else { *pNumberOut = 0; - return DR_FALSE; // Bad UTF-8 encoding. + return DRFLAC_CRC_MISMATCH; // Bad UTF-8 encoding. } // Read extra bytes. - assert(byteCount > 1); + drflac_assert(byteCount > 1); - uint64_t result = (uint64_t)(utf8[0] & (0xFF >> (byteCount + 1))); + drflac_uint64 result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1))); for (int i = 1; i < byteCount; ++i) { if (!drflac__read_uint8(bs, 8, utf8 + i)) { *pNumberOut = 0; - return DR_FALSE; + return DRFLAC_END_OF_STREAM; } + crc = drflac_crc8(crc, utf8[i], 8); result = (result << 6) | (utf8[i] & 0x3F); } *pNumberOut = result; - return DR_TRUE; + *pCRCOut = crc; + return DRFLAC_SUCCESS; } -static DRFLAC_INLINE dr_bool32 drflac__read_and_seek_rice(drflac_bs* bs, uint8_t m) -{ - unsigned int unused; - if (!drflac__seek_past_next_set_bit(bs, &unused)) { - return DR_FALSE; - } - - if (m > 0) { - if (!drflac__seek_bits(bs, m)) { - return DR_FALSE; - } - } - - return DR_TRUE; -} - // The next two functions are responsible for calculating the prediction. // // When the bits per sample is >16 we need to use 64-bit integer arithmetic because otherwise we'll run out of precision. It's // safe to assume this will be slower on 32-bit platforms so we use a more optimal solution when the bits per sample is <=16. -static DRFLAC_INLINE int32_t drflac__calculate_prediction_32(uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples) +static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { - assert(order <= 32); + drflac_assert(order <= 32); // 32-bit version. // VC++ optimizes this to a single jmp. I've not yet verified this for other compilers. - int32_t prediction = 0; + drflac_int32 prediction = 0; switch (order) { @@ -1354,137 +1962,137 @@ static DRFLAC_INLINE int32_t drflac__calculate_prediction_32(uint32_t order, int case 1: prediction += coefficients[ 0] * pDecodedSamples[- 1]; } - return (int32_t)(prediction >> shift); + return (drflac_int32)(prediction >> shift); } -static DRFLAC_INLINE int32_t drflac__calculate_prediction_64(uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples) +static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { - assert(order <= 32); + drflac_assert(order <= 32); // 64-bit version. // This method is faster on the 32-bit build when compiling with VC++. See note below. #ifndef DRFLAC_64BIT - int64_t prediction; + drflac_int64 prediction; if (order == 8) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; - prediction += coefficients[1] * (int64_t)pDecodedSamples[-2]; - prediction += coefficients[2] * (int64_t)pDecodedSamples[-3]; - prediction += coefficients[3] * (int64_t)pDecodedSamples[-4]; - prediction += coefficients[4] * (int64_t)pDecodedSamples[-5]; - prediction += coefficients[5] * (int64_t)pDecodedSamples[-6]; - prediction += coefficients[6] * (int64_t)pDecodedSamples[-7]; - prediction += coefficients[7] * (int64_t)pDecodedSamples[-8]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; } else if (order == 7) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; - prediction += coefficients[1] * (int64_t)pDecodedSamples[-2]; - prediction += coefficients[2] * (int64_t)pDecodedSamples[-3]; - prediction += coefficients[3] * (int64_t)pDecodedSamples[-4]; - prediction += coefficients[4] * (int64_t)pDecodedSamples[-5]; - prediction += coefficients[5] * (int64_t)pDecodedSamples[-6]; - prediction += coefficients[6] * (int64_t)pDecodedSamples[-7]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; } else if (order == 3) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; - prediction += coefficients[1] * (int64_t)pDecodedSamples[-2]; - prediction += coefficients[2] * (int64_t)pDecodedSamples[-3]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; } else if (order == 6) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; - prediction += coefficients[1] * (int64_t)pDecodedSamples[-2]; - prediction += coefficients[2] * (int64_t)pDecodedSamples[-3]; - prediction += coefficients[3] * (int64_t)pDecodedSamples[-4]; - prediction += coefficients[4] * (int64_t)pDecodedSamples[-5]; - prediction += coefficients[5] * (int64_t)pDecodedSamples[-6]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; } else if (order == 5) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; - prediction += coefficients[1] * (int64_t)pDecodedSamples[-2]; - prediction += coefficients[2] * (int64_t)pDecodedSamples[-3]; - prediction += coefficients[3] * (int64_t)pDecodedSamples[-4]; - prediction += coefficients[4] * (int64_t)pDecodedSamples[-5]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; } else if (order == 4) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; - prediction += coefficients[1] * (int64_t)pDecodedSamples[-2]; - prediction += coefficients[2] * (int64_t)pDecodedSamples[-3]; - prediction += coefficients[3] * (int64_t)pDecodedSamples[-4]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; } else if (order == 12) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; - prediction += coefficients[1] * (int64_t)pDecodedSamples[-2]; - prediction += coefficients[2] * (int64_t)pDecodedSamples[-3]; - prediction += coefficients[3] * (int64_t)pDecodedSamples[-4]; - prediction += coefficients[4] * (int64_t)pDecodedSamples[-5]; - prediction += coefficients[5] * (int64_t)pDecodedSamples[-6]; - prediction += coefficients[6] * (int64_t)pDecodedSamples[-7]; - prediction += coefficients[7] * (int64_t)pDecodedSamples[-8]; - prediction += coefficients[8] * (int64_t)pDecodedSamples[-9]; - prediction += coefficients[9] * (int64_t)pDecodedSamples[-10]; - prediction += coefficients[10] * (int64_t)pDecodedSamples[-11]; - prediction += coefficients[11] * (int64_t)pDecodedSamples[-12]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; + prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; + prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12]; } else if (order == 2) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; - prediction += coefficients[1] * (int64_t)pDecodedSamples[-2]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; } else if (order == 1) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; } else if (order == 10) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; - prediction += coefficients[1] * (int64_t)pDecodedSamples[-2]; - prediction += coefficients[2] * (int64_t)pDecodedSamples[-3]; - prediction += coefficients[3] * (int64_t)pDecodedSamples[-4]; - prediction += coefficients[4] * (int64_t)pDecodedSamples[-5]; - prediction += coefficients[5] * (int64_t)pDecodedSamples[-6]; - prediction += coefficients[6] * (int64_t)pDecodedSamples[-7]; - prediction += coefficients[7] * (int64_t)pDecodedSamples[-8]; - prediction += coefficients[8] * (int64_t)pDecodedSamples[-9]; - prediction += coefficients[9] * (int64_t)pDecodedSamples[-10]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; } else if (order == 9) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; - prediction += coefficients[1] * (int64_t)pDecodedSamples[-2]; - prediction += coefficients[2] * (int64_t)pDecodedSamples[-3]; - prediction += coefficients[3] * (int64_t)pDecodedSamples[-4]; - prediction += coefficients[4] * (int64_t)pDecodedSamples[-5]; - prediction += coefficients[5] * (int64_t)pDecodedSamples[-6]; - prediction += coefficients[6] * (int64_t)pDecodedSamples[-7]; - prediction += coefficients[7] * (int64_t)pDecodedSamples[-8]; - prediction += coefficients[8] * (int64_t)pDecodedSamples[-9]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; } else if (order == 11) { - prediction = coefficients[0] * (int64_t)pDecodedSamples[-1]; - prediction += coefficients[1] * (int64_t)pDecodedSamples[-2]; - prediction += coefficients[2] * (int64_t)pDecodedSamples[-3]; - prediction += coefficients[3] * (int64_t)pDecodedSamples[-4]; - prediction += coefficients[4] * (int64_t)pDecodedSamples[-5]; - prediction += coefficients[5] * (int64_t)pDecodedSamples[-6]; - prediction += coefficients[6] * (int64_t)pDecodedSamples[-7]; - prediction += coefficients[7] * (int64_t)pDecodedSamples[-8]; - prediction += coefficients[8] * (int64_t)pDecodedSamples[-9]; - prediction += coefficients[9] * (int64_t)pDecodedSamples[-10]; - prediction += coefficients[10] * (int64_t)pDecodedSamples[-11]; + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; + prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; } else { prediction = 0; for (int j = 0; j < (int)order; ++j) { - prediction += coefficients[j] * (int64_t)pDecodedSamples[-j-1]; + prediction += coefficients[j] * (drflac_int64)pDecodedSamples[-j-1]; } } #endif @@ -1492,190 +2100,268 @@ static DRFLAC_INLINE int32_t drflac__calculate_prediction_64(uint32_t order, int // VC++ optimizes this to a single jmp instruction, but only the 64-bit build. The 32-bit build generates less efficient code for some // reason. The ugly version above is faster so we'll just switch between the two depending on the target platform. #ifdef DRFLAC_64BIT - int64_t prediction = 0; + drflac_int64 prediction = 0; switch (order) { - case 32: prediction += coefficients[31] * (int64_t)pDecodedSamples[-32]; - case 31: prediction += coefficients[30] * (int64_t)pDecodedSamples[-31]; - case 30: prediction += coefficients[29] * (int64_t)pDecodedSamples[-30]; - case 29: prediction += coefficients[28] * (int64_t)pDecodedSamples[-29]; - case 28: prediction += coefficients[27] * (int64_t)pDecodedSamples[-28]; - case 27: prediction += coefficients[26] * (int64_t)pDecodedSamples[-27]; - case 26: prediction += coefficients[25] * (int64_t)pDecodedSamples[-26]; - case 25: prediction += coefficients[24] * (int64_t)pDecodedSamples[-25]; - case 24: prediction += coefficients[23] * (int64_t)pDecodedSamples[-24]; - case 23: prediction += coefficients[22] * (int64_t)pDecodedSamples[-23]; - case 22: prediction += coefficients[21] * (int64_t)pDecodedSamples[-22]; - case 21: prediction += coefficients[20] * (int64_t)pDecodedSamples[-21]; - case 20: prediction += coefficients[19] * (int64_t)pDecodedSamples[-20]; - case 19: prediction += coefficients[18] * (int64_t)pDecodedSamples[-19]; - case 18: prediction += coefficients[17] * (int64_t)pDecodedSamples[-18]; - case 17: prediction += coefficients[16] * (int64_t)pDecodedSamples[-17]; - case 16: prediction += coefficients[15] * (int64_t)pDecodedSamples[-16]; - case 15: prediction += coefficients[14] * (int64_t)pDecodedSamples[-15]; - case 14: prediction += coefficients[13] * (int64_t)pDecodedSamples[-14]; - case 13: prediction += coefficients[12] * (int64_t)pDecodedSamples[-13]; - case 12: prediction += coefficients[11] * (int64_t)pDecodedSamples[-12]; - case 11: prediction += coefficients[10] * (int64_t)pDecodedSamples[-11]; - case 10: prediction += coefficients[ 9] * (int64_t)pDecodedSamples[-10]; - case 9: prediction += coefficients[ 8] * (int64_t)pDecodedSamples[- 9]; - case 8: prediction += coefficients[ 7] * (int64_t)pDecodedSamples[- 8]; - case 7: prediction += coefficients[ 6] * (int64_t)pDecodedSamples[- 7]; - case 6: prediction += coefficients[ 5] * (int64_t)pDecodedSamples[- 6]; - case 5: prediction += coefficients[ 4] * (int64_t)pDecodedSamples[- 5]; - case 4: prediction += coefficients[ 3] * (int64_t)pDecodedSamples[- 4]; - case 3: prediction += coefficients[ 2] * (int64_t)pDecodedSamples[- 3]; - case 2: prediction += coefficients[ 1] * (int64_t)pDecodedSamples[- 2]; - case 1: prediction += coefficients[ 0] * (int64_t)pDecodedSamples[- 1]; + case 32: prediction += coefficients[31] * (drflac_int64)pDecodedSamples[-32]; + case 31: prediction += coefficients[30] * (drflac_int64)pDecodedSamples[-31]; + case 30: prediction += coefficients[29] * (drflac_int64)pDecodedSamples[-30]; + case 29: prediction += coefficients[28] * (drflac_int64)pDecodedSamples[-29]; + case 28: prediction += coefficients[27] * (drflac_int64)pDecodedSamples[-28]; + case 27: prediction += coefficients[26] * (drflac_int64)pDecodedSamples[-27]; + case 26: prediction += coefficients[25] * (drflac_int64)pDecodedSamples[-26]; + case 25: prediction += coefficients[24] * (drflac_int64)pDecodedSamples[-25]; + case 24: prediction += coefficients[23] * (drflac_int64)pDecodedSamples[-24]; + case 23: prediction += coefficients[22] * (drflac_int64)pDecodedSamples[-23]; + case 22: prediction += coefficients[21] * (drflac_int64)pDecodedSamples[-22]; + case 21: prediction += coefficients[20] * (drflac_int64)pDecodedSamples[-21]; + case 20: prediction += coefficients[19] * (drflac_int64)pDecodedSamples[-20]; + case 19: prediction += coefficients[18] * (drflac_int64)pDecodedSamples[-19]; + case 18: prediction += coefficients[17] * (drflac_int64)pDecodedSamples[-18]; + case 17: prediction += coefficients[16] * (drflac_int64)pDecodedSamples[-17]; + case 16: prediction += coefficients[15] * (drflac_int64)pDecodedSamples[-16]; + case 15: prediction += coefficients[14] * (drflac_int64)pDecodedSamples[-15]; + case 14: prediction += coefficients[13] * (drflac_int64)pDecodedSamples[-14]; + case 13: prediction += coefficients[12] * (drflac_int64)pDecodedSamples[-13]; + case 12: prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12]; + case 11: prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; + case 10: prediction += coefficients[ 9] * (drflac_int64)pDecodedSamples[-10]; + case 9: prediction += coefficients[ 8] * (drflac_int64)pDecodedSamples[- 9]; + case 8: prediction += coefficients[ 7] * (drflac_int64)pDecodedSamples[- 8]; + case 7: prediction += coefficients[ 6] * (drflac_int64)pDecodedSamples[- 7]; + case 6: prediction += coefficients[ 5] * (drflac_int64)pDecodedSamples[- 6]; + case 5: prediction += coefficients[ 4] * (drflac_int64)pDecodedSamples[- 5]; + case 4: prediction += coefficients[ 3] * (drflac_int64)pDecodedSamples[- 4]; + case 3: prediction += coefficients[ 2] * (drflac_int64)pDecodedSamples[- 3]; + case 2: prediction += coefficients[ 1] * (drflac_int64)pDecodedSamples[- 2]; + case 1: prediction += coefficients[ 0] * (drflac_int64)pDecodedSamples[- 1]; } #endif - return (int32_t)(prediction >> shift); + return (drflac_int32)(prediction >> shift); } - -// Reads and decodes a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes. -// -// This is the most frequently called function in the library. It does both the Rice decoding and the prediction in a single loop -// iteration. The prediction is done at the end, and there's an annoying branch I'd like to avoid so the main function is defined -// as a #define - sue me! -#define DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(funcName, predictionFunc) \ -static dr_bool32 funcName (drflac_bs* bs, uint32_t count, uint8_t riceParam, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut) \ -{ \ - assert(bs != NULL); \ - assert(count > 0); \ - assert(pSamplesOut != NULL); \ - \ - static unsigned int bitOffsetTable[] = { \ - 0, \ - 4, \ - 3, 3, \ - 2, 2, 2, 2, \ - 1, 1, 1, 1, 1, 1, 1, 1 \ - }; \ - \ - drflac_cache_t riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); \ - drflac_cache_t resultHiShift = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParam; \ - \ - for (int i = 0; i < (int)count; ++i) \ - { \ - unsigned int zeroCounter = 0; \ - while (bs->cache == 0) { \ - zeroCounter += (unsigned int)DRFLAC_CACHE_L1_BITS_REMAINING(bs); \ - if (!drflac__reload_cache(bs)) { \ - return DR_FALSE; \ - } \ - } \ - \ - /* At this point the cache should not be zero, in which case we know the first set bit should be somewhere in here. There is \ - no need for us to perform any cache reloading logic here which should make things much faster. */ \ - assert(bs->cache != 0); \ - unsigned int decodedRice; \ - \ - unsigned int setBitOffsetPlus1 = bitOffsetTable[DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, 4)]; \ - if (setBitOffsetPlus1 > 0) { \ - decodedRice = (zeroCounter + (setBitOffsetPlus1-1)) << riceParam; \ - } else { \ - if (bs->cache == 1) { \ - setBitOffsetPlus1 = DRFLAC_CACHE_L1_SIZE_BITS(bs); \ - decodedRice = (zeroCounter + (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1)) << riceParam; \ - } else { \ - setBitOffsetPlus1 = 5; \ - for (;;) \ - { \ - if ((bs->cache & DRFLAC_CACHE_L1_SELECT(bs, setBitOffsetPlus1))) { \ - decodedRice = (zeroCounter + (setBitOffsetPlus1-1)) << riceParam; \ - break; \ - } \ - \ - setBitOffsetPlus1 += 1; \ - } \ - } \ - } \ - \ - \ - unsigned int bitsLo = 0; \ - unsigned int riceLength = setBitOffsetPlus1 + riceParam; \ - if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) \ - { \ - bitsLo = (unsigned int)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> (DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceLength)); \ - \ - bs->consumedBits += riceLength; \ - bs->cache <<= riceLength; \ - } \ - else \ - { \ - bs->consumedBits += riceLength; \ - bs->cache <<= setBitOffsetPlus1; \ - \ - /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */ \ - size_t bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); \ - drflac_cache_t resultHi = bs->cache & riceParamMask; /* <-- This mask is OK because all bits after the first bits are always zero. */ \ - \ - \ - if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { \ - bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); \ - } else { \ - /* Slow path. We need to fetch more data from the client. */ \ - if (!drflac__reload_cache(bs)) { \ - return DR_FALSE; \ - } \ - } \ - \ - bitsLo = (unsigned int)((resultHi >> resultHiShift) | DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo)); \ - bs->consumedBits = bitCountLo; \ - bs->cache <<= bitCountLo; \ - } \ - \ - decodedRice |= bitsLo; \ - decodedRice = (decodedRice >> 1) ^ (~(decodedRice & 0x01) + 1); /* <-- Ah, much faster! :) */ \ - /* \ - if ((decodedRice & 0x01)) { \ - decodedRice = ~(decodedRice >> 1); \ - } else { \ - decodedRice = (decodedRice >> 1); \ - } \ - */ \ - \ - /* In order to properly calculate the prediction when the bits per sample is >16 we need to do it using 64-bit arithmetic. We can assume this \ - is probably going to be slower on 32-bit systems so we'll do a more optimized 32-bit version when the bits per sample is low enough.*/ \ - pSamplesOut[i] = ((int)decodedRice + predictionFunc(order, shift, coefficients, pSamplesOut + i)); \ - } \ - \ - return DR_TRUE; \ -} \ - -DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(drflac__decode_samples_with_residual__rice_64, drflac__calculate_prediction_64) -DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(drflac__decode_samples_with_residual__rice_32, drflac__calculate_prediction_32) - - -// Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes. -static dr_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, uint32_t count, uint8_t riceParam) +#if 0 +// Reference implementation for reading and decoding samples with residual. This is intentionally left unoptimized for the +// sake of readability and should only be used as a reference. +static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { - assert(bs != NULL); - assert(count > 0); + drflac_assert(bs != NULL); + drflac_assert(count > 0); + drflac_assert(pSamplesOut != NULL); - for (uint32_t i = 0; i < count; ++i) { - if (!drflac__read_and_seek_rice(bs, riceParam)) { - return DR_FALSE; + for (drflac_uint32 i = 0; i < count; ++i) { + drflac_uint32 zeroCounter = 0; + for (;;) { + drflac_uint8 bit; + if (!drflac__read_uint8(bs, 1, &bit)) { + return DRFLAC_FALSE; + } + + if (bit == 0) { + zeroCounter += 1; + } else { + break; + } + } + + drflac_uint32 decodedRice; + if (riceParam > 0) { + if (!drflac__read_uint32(bs, riceParam, &decodedRice)) { + return DRFLAC_FALSE; + } + } else { + decodedRice = 0; + } + + decodedRice |= (zeroCounter << riceParam); + if ((decodedRice & 0x01)) { + decodedRice = ~(decodedRice >> 1); + } else { + decodedRice = (decodedRice >> 1); + } + + + if (bitsPerSample > 16) { + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); + } else { + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); } } - return DR_TRUE; + return DRFLAC_TRUE; +} +#endif + +#if 0 +static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) +{ + drflac_uint32 zeroCounter = 0; + for (;;) { + drflac_uint8 bit; + if (!drflac__read_uint8(bs, 1, &bit)) { + return DRFLAC_FALSE; + } + + if (bit == 0) { + zeroCounter += 1; + } else { + break; + } + } + + drflac_uint32 decodedRice; + if (riceParam > 0) { + if (!drflac__read_uint32(bs, riceParam, &decodedRice)) { + return DRFLAC_FALSE; + } + } else { + decodedRice = 0; + } + + *pZeroCounterOut = zeroCounter; + *pRiceParamPartOut = decodedRice; + return DRFLAC_TRUE; +} +#endif + +static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) +{ + drflac_cache_t riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); + drflac_cache_t resultHiShift = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParam; + + + drflac_uint32 zeroCounter = 0; + while (bs->cache == 0) { + zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + } + + drflac_uint32 setBitOffsetPlus1 = drflac__clz(bs->cache); + zeroCounter += setBitOffsetPlus1; + setBitOffsetPlus1 += 1; + + + drflac_uint32 riceParamPart; + drflac_uint32 riceLength = setBitOffsetPlus1 + riceParam; + if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> (DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceLength)); + + bs->consumedBits += riceLength; + bs->cache <<= riceLength; + } else { + bs->consumedBits += riceLength; + if (setBitOffsetPlus1 < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + bs->cache <<= setBitOffsetPlus1; + } + + // It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. + drflac_uint32 bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); + drflac_cache_t resultHi = bs->cache & riceParamMask; // <-- This mask is OK because all bits after the first bits are always zero. + + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs->consumedBits = 0; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache; + #endif + } else { + // Slow path. We need to fetch more data from the client. + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + } + + riceParamPart = (drflac_uint32)((resultHi >> resultHiShift) | DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo)); + + bs->consumedBits += bitCountLo; + bs->cache <<= bitCountLo; + } + + *pZeroCounterOut = zeroCounter; + *pRiceParamPartOut = riceParamPart; + return DRFLAC_TRUE; } -static dr_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, uint32_t bitsPerSample, uint32_t count, uint8_t unencodedBitsPerSample, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut) -{ - assert(bs != NULL); - assert(count > 0); - assert(unencodedBitsPerSample > 0 && unencodedBitsPerSample <= 32); - assert(pSamplesOut != NULL); - for (unsigned int i = 0; i < count; ++i) - { +static drflac_bool32 drflac__decode_samples_with_residual__rice__simple(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + drflac_assert(bs != NULL); + drflac_assert(count > 0); + drflac_assert(pSamplesOut != NULL); + + drflac_uint32 zeroCountPart; + drflac_uint32 riceParamPart; + + drflac_uint32 i = 0; + while (i < count) { + // Rice extraction. + if (!drflac__read_rice_parts(bs, riceParam, &zeroCountPart, &riceParamPart)) { + return DRFLAC_FALSE; + } + + // Rice reconstruction. + static drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + riceParamPart |= (zeroCountPart << riceParam); + riceParamPart = (riceParamPart >> 1) ^ t[riceParamPart & 0x01]; + //riceParamPart = (riceParamPart >> 1) ^ (~(riceParamPart & 0x01) + 1); + + // Sample reconstruction. + if (bitsPerSample > 16) { + pSamplesOut[i] = riceParamPart + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); + } else { + pSamplesOut[i] = riceParamPart + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); + } + + i += 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ +#if 0 + return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); +#else + return drflac__decode_samples_with_residual__rice__simple(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); +#endif +} + +// Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes. +static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam) +{ + drflac_assert(bs != NULL); + drflac_assert(count > 0); + + for (drflac_uint32 i = 0; i < count; ++i) { + drflac_uint32 zeroCountPart; + drflac_uint32 riceParamPart; + if (!drflac__read_rice_parts(bs, riceParam, &zeroCountPart, &riceParamPart)) { + return DRFLAC_FALSE; + } + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + drflac_assert(bs != NULL); + drflac_assert(count > 0); + drflac_assert(unencodedBitsPerSample > 0 && unencodedBitsPerSample <= 32); + drflac_assert(pSamplesOut != NULL); + + for (unsigned int i = 0; i < count; ++i) { if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (bitsPerSample > 16) { @@ -1685,53 +2371,52 @@ static dr_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, } } - return DR_TRUE; + return DRFLAC_TRUE; } // Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called // when the decoder is sitting at the very start of the RESIDUAL block. The first residuals will be ignored. The // and parameters are used to determine how many residual values need to be decoded. -static dr_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, uint32_t bitsPerSample, uint32_t blockSize, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples) +static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { - assert(bs != NULL); - assert(blockSize != 0); - assert(pDecodedSamples != NULL); // <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode? + drflac_assert(bs != NULL); + drflac_assert(blockSize != 0); + drflac_assert(pDecodedSamples != NULL); // <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode? - uint8_t residualMethod; + drflac_uint8 residualMethod; if (!drflac__read_uint8(bs, 2, &residualMethod)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { - return DR_FALSE; // Unknown or unsupported residual coding method. + return DRFLAC_FALSE; // Unknown or unsupported residual coding method. } // Ignore the first values. pDecodedSamples += order; - uint8_t partitionOrder; + drflac_uint8 partitionOrder; if (!drflac__read_uint8(bs, 4, &partitionOrder)) { - return DR_FALSE; + return DRFLAC_FALSE; } - uint32_t samplesInPartition = (blockSize / (1 << partitionOrder)) - order; - uint32_t partitionsRemaining = (1 << partitionOrder); - for (;;) - { - uint8_t riceParam = 0; + drflac_uint32 samplesInPartition = (blockSize / (1 << partitionOrder)) - order; + drflac_uint32 partitionsRemaining = (1 << partitionOrder); + for (;;) { + drflac_uint8 riceParam = 0; if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { if (!drflac__read_uint8(bs, 4, &riceParam)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (riceParam == 16) { riceParam = 0xFF; } } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { if (!drflac__read_uint8(bs, 5, &riceParam)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (riceParam == 32) { riceParam = 0xFF; @@ -1739,23 +2424,17 @@ static dr_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, uint32_t bi } if (riceParam != 0xFF) { - if (bitsPerSample > 16) { - if (!drflac__decode_samples_with_residual__rice_64(bs, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) { - return DR_FALSE; - } - } else { - if (!drflac__decode_samples_with_residual__rice_32(bs, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) { - return DR_FALSE; - } + if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) { + return DRFLAC_FALSE; } } else { unsigned char unencodedBitsPerSample = 0; if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) { - return DR_FALSE; + return DRFLAC_FALSE; } } @@ -1770,46 +2449,46 @@ static dr_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, uint32_t bi samplesInPartition = blockSize / (1 << partitionOrder); } - return DR_TRUE; + return DRFLAC_TRUE; } // Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called // when the decoder is sitting at the very start of the RESIDUAL block. The first residuals will be set to 0. The // and parameters are used to determine how many residual values need to be decoded. -static dr_bool32 drflac__read_and_seek_residual(drflac_bs* bs, uint32_t blockSize, uint32_t order) +static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 order) { - assert(bs != NULL); - assert(blockSize != 0); + drflac_assert(bs != NULL); + drflac_assert(blockSize != 0); - uint8_t residualMethod; + drflac_uint8 residualMethod; if (!drflac__read_uint8(bs, 2, &residualMethod)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { - return DR_FALSE; // Unknown or unsupported residual coding method. + return DRFLAC_FALSE; // Unknown or unsupported residual coding method. } - uint8_t partitionOrder; + drflac_uint8 partitionOrder; if (!drflac__read_uint8(bs, 4, &partitionOrder)) { - return DR_FALSE; + return DRFLAC_FALSE; } - uint32_t samplesInPartition = (blockSize / (1 << partitionOrder)) - order; - uint32_t partitionsRemaining = (1 << partitionOrder); + drflac_uint32 samplesInPartition = (blockSize / (1 << partitionOrder)) - order; + drflac_uint32 partitionsRemaining = (1 << partitionOrder); for (;;) { - uint8_t riceParam = 0; + drflac_uint8 riceParam = 0; if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { if (!drflac__read_uint8(bs, 4, &riceParam)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (riceParam == 16) { riceParam = 0xFF; } } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { if (!drflac__read_uint8(bs, 5, &riceParam)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (riceParam == 32) { riceParam = 0xFF; @@ -1818,16 +2497,16 @@ static dr_bool32 drflac__read_and_seek_residual(drflac_bs* bs, uint32_t blockSiz if (riceParam != 0xFF) { if (!drflac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) { - return DR_FALSE; + return DRFLAC_FALSE; } } else { unsigned char unencodedBitsPerSample = 0; if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (!drflac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) { - return DR_FALSE; + return DRFLAC_FALSE; } } @@ -1840,44 +2519,44 @@ static dr_bool32 drflac__read_and_seek_residual(drflac_bs* bs, uint32_t blockSiz samplesInPartition = blockSize / (1 << partitionOrder); } - return DR_TRUE; + return DRFLAC_TRUE; } -static dr_bool32 drflac__decode_samples__constant(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples) +static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_int32* pDecodedSamples) { // Only a single sample needs to be decoded here. - int32_t sample; + drflac_int32 sample; if (!drflac__read_int32(bs, bitsPerSample, &sample)) { - return DR_FALSE; + return DRFLAC_FALSE; } // We don't really need to expand this, but it does simplify the process of reading samples. If this becomes a performance issue (unlikely) // we'll want to look at a more efficient way. - for (uint32_t i = 0; i < blockSize; ++i) { + for (drflac_uint32 i = 0; i < blockSize; ++i) { pDecodedSamples[i] = sample; } - return DR_TRUE; + return DRFLAC_TRUE; } -static dr_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples) +static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_int32* pDecodedSamples) { - for (uint32_t i = 0; i < blockSize; ++i) { - int32_t sample; + for (drflac_uint32 i = 0; i < blockSize; ++i) { + drflac_int32 sample; if (!drflac__read_int32(bs, bitsPerSample, &sample)) { - return DR_FALSE; + return DRFLAC_FALSE; } pDecodedSamples[i] = sample; } - return DR_TRUE; + return DRFLAC_TRUE; } -static dr_bool32 drflac__decode_samples__fixed(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples) +static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) { - short lpcCoefficientsTable[5][4] = { + drflac_int32 lpcCoefficientsTable[5][4] = { {0, 0, 0, 0}, {1, 0, 0, 0}, {2, -1, 0, 0}, @@ -1886,10 +2565,10 @@ static dr_bool32 drflac__decode_samples__fixed(drflac_bs* bs, uint32_t blockSize }; // Warm up samples and coefficients. - for (uint32_t i = 0; i < lpcOrder; ++i) { - int32_t sample; + for (drflac_uint32 i = 0; i < lpcOrder; ++i) { + drflac_int32 sample; if (!drflac__read_int32(bs, bitsPerSample, &sample)) { - return DR_FALSE; + return DRFLAC_FALSE; } pDecodedSamples[i] = sample; @@ -1897,195 +2576,224 @@ static dr_bool32 drflac__decode_samples__fixed(drflac_bs* bs, uint32_t blockSize if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { - return DR_FALSE; + return DRFLAC_FALSE; } - return DR_TRUE; + return DRFLAC_TRUE; } -static dr_bool32 drflac__decode_samples__lpc(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples) +static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) { + drflac_uint8 i; + // Warm up samples. - for (uint8_t i = 0; i < lpcOrder; ++i) { - int32_t sample; + for (i = 0; i < lpcOrder; ++i) { + drflac_int32 sample; if (!drflac__read_int32(bs, bitsPerSample, &sample)) { - return DR_FALSE; + return DRFLAC_FALSE; } pDecodedSamples[i] = sample; } - uint8_t lpcPrecision; + drflac_uint8 lpcPrecision; if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (lpcPrecision == 15) { - return DR_FALSE; // Invalid. + return DRFLAC_FALSE; // Invalid. } lpcPrecision += 1; - int8_t lpcShift; + drflac_int8 lpcShift; if (!drflac__read_int8(bs, 5, &lpcShift)) { - return DR_FALSE; + return DRFLAC_FALSE; } - int16_t coefficients[32]; - for (uint8_t i = 0; i < lpcOrder; ++i) { - if (!drflac__read_int16(bs, lpcPrecision, coefficients + i)) { - return DR_FALSE; + drflac_int32 coefficients[32]; + for (i = 0; i < lpcOrder; ++i) { + if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) { + return DRFLAC_FALSE; } } if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) { - return DR_FALSE; + return DRFLAC_FALSE; } - return DR_TRUE; + return DRFLAC_TRUE; } -static dr_bool32 drflac__read_next_frame_header(drflac_bs* bs, uint8_t streaminfoBitsPerSample, drflac_frame_header* header) +static drflac_bool32 drflac__read_next_frame_header(drflac_bs* bs, drflac_uint8 streaminfoBitsPerSample, drflac_frame_header* header) { - assert(bs != NULL); - assert(header != NULL); + drflac_assert(bs != NULL); + drflac_assert(header != NULL); - // At the moment the sync code is as a form of basic validation. The CRC is stored, but is unused at the moment. This - // should probably be handled better in the future. + const drflac_uint32 sampleRateTable[12] = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000}; + const drflac_uint8 bitsPerSampleTable[8] = {0, 8, 12, (drflac_uint8)-1, 16, 20, 24, (drflac_uint8)-1}; // -1 = reserved. - const uint32_t sampleRateTable[12] = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000}; - const uint8_t bitsPerSampleTable[8] = {0, 8, 12, (uint8_t)-1, 16, 20, 24, (uint8_t)-1}; // -1 = reserved. - - uint16_t syncCode = 0; - if (!drflac__read_uint16(bs, 14, &syncCode)) { - return DR_FALSE; - } - - if (syncCode != 0x3FFE) { - // TODO: Try and recover by attempting to seek to and read the next frame? - return DR_FALSE; - } - - uint8_t reserved; - if (!drflac__read_uint8(bs, 1, &reserved)) { - return DR_FALSE; - } - - uint8_t blockingStrategy = 0; - if (!drflac__read_uint8(bs, 1, &blockingStrategy)) { - return DR_FALSE; - } - - - - uint8_t blockSize = 0; - if (!drflac__read_uint8(bs, 4, &blockSize)) { - return DR_FALSE; - } - - uint8_t sampleRate = 0; - if (!drflac__read_uint8(bs, 4, &sampleRate)) { - return DR_FALSE; - } - - uint8_t channelAssignment = 0; - if (!drflac__read_uint8(bs, 4, &channelAssignment)) { - return DR_FALSE; - } - - uint8_t bitsPerSample = 0; - if (!drflac__read_uint8(bs, 3, &bitsPerSample)) { - return DR_FALSE; - } - - if (!drflac__read_uint8(bs, 1, &reserved)) { - return DR_FALSE; - } - - - dr_bool32 isVariableBlockSize = blockingStrategy == 1; - if (isVariableBlockSize) { - uint64_t sampleNumber; - if (!drflac__read_utf8_coded_number(bs, &sampleNumber)) { - return DR_FALSE; + // Keep looping until we find a valid sync code. + for (;;) { + if (!drflac__find_and_seek_to_next_sync_code(bs)) { + return DRFLAC_FALSE; } - header->frameNumber = 0; - header->sampleNumber = sampleNumber; - } else { - uint64_t frameNumber = 0; - if (!drflac__read_utf8_coded_number(bs, &frameNumber)) { - return DR_FALSE; + + drflac_uint8 crc8 = 0xCE; // 0xCE = drflac_crc8(0, 0x3FFE, 14); + + drflac_uint8 reserved = 0; + if (!drflac__read_uint8(bs, 1, &reserved)) { + return DRFLAC_FALSE; } - header->frameNumber = (uint32_t)frameNumber; // <-- Safe cast. - header->sampleNumber = 0; + crc8 = drflac_crc8(crc8, reserved, 1); + + + drflac_uint8 blockingStrategy = 0; + if (!drflac__read_uint8(bs, 1, &blockingStrategy)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, blockingStrategy, 1); + + + drflac_uint8 blockSize = 0; + if (!drflac__read_uint8(bs, 4, &blockSize)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, blockSize, 4); + + + drflac_uint8 sampleRate = 0; + if (!drflac__read_uint8(bs, 4, &sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, sampleRate, 4); + + + drflac_uint8 channelAssignment = 0; + if (!drflac__read_uint8(bs, 4, &channelAssignment)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, channelAssignment, 4); + + + drflac_uint8 bitsPerSample = 0; + if (!drflac__read_uint8(bs, 3, &bitsPerSample)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, bitsPerSample, 3); + + + if (!drflac__read_uint8(bs, 1, &reserved)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, reserved, 1); + + + drflac_bool32 isVariableBlockSize = blockingStrategy == 1; + if (isVariableBlockSize) { + drflac_uint64 sampleNumber; + drflac_result result = drflac__read_utf8_coded_number(bs, &sampleNumber, &crc8); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_END_OF_STREAM) { + return DRFLAC_FALSE; + } else { + continue; + } + } + header->frameNumber = 0; + header->sampleNumber = sampleNumber; + } else { + drflac_uint64 frameNumber = 0; + drflac_result result = drflac__read_utf8_coded_number(bs, &frameNumber, &crc8); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_END_OF_STREAM) { + return DRFLAC_FALSE; + } else { + continue; + } + } + header->frameNumber = (drflac_uint32)frameNumber; // <-- Safe cast. + header->sampleNumber = 0; + } + + + if (blockSize == 1) { + header->blockSize = 192; + } else if (blockSize >= 2 && blockSize <= 5) { + header->blockSize = 576 * (1 << (blockSize - 2)); + } else if (blockSize == 6) { + if (!drflac__read_uint16(bs, 8, &header->blockSize)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->blockSize, 8); + header->blockSize += 1; + } else if (blockSize == 7) { + if (!drflac__read_uint16(bs, 16, &header->blockSize)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->blockSize, 16); + header->blockSize += 1; + } else { + header->blockSize = 256 * (1 << (blockSize - 8)); + } + + + if (sampleRate <= 11) { + header->sampleRate = sampleRateTable[sampleRate]; + } else if (sampleRate == 12) { + if (!drflac__read_uint32(bs, 8, &header->sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->sampleRate, 8); + header->sampleRate *= 1000; + } else if (sampleRate == 13) { + if (!drflac__read_uint32(bs, 16, &header->sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->sampleRate, 16); + } else if (sampleRate == 14) { + if (!drflac__read_uint32(bs, 16, &header->sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->sampleRate, 16); + header->sampleRate *= 10; + } else { + continue; // Invalid. Assume an invalid block. + } + + + header->channelAssignment = channelAssignment; + + header->bitsPerSample = bitsPerSampleTable[bitsPerSample]; + if (header->bitsPerSample == 0) { + header->bitsPerSample = streaminfoBitsPerSample; + } + + if (!drflac__read_uint8(bs, 8, &header->crc8)) { + return DRFLAC_FALSE; + } + + #ifndef DR_FLAC_NO_CRC + if (header->crc8 != crc8) { + continue; // CRC mismatch. Loop back to the top and find the next sync code. + } + #endif + return DRFLAC_TRUE; } - - - if (blockSize == 1) { - header->blockSize = 192; - } else if (blockSize >= 2 && blockSize <= 5) { - header->blockSize = 576 * (1 << (blockSize - 2)); - } else if (blockSize == 6) { - if (!drflac__read_uint16(bs, 8, &header->blockSize)) { - return DR_FALSE; - } - header->blockSize += 1; - } else if (blockSize == 7) { - if (!drflac__read_uint16(bs, 16, &header->blockSize)) { - return DR_FALSE; - } - header->blockSize += 1; - } else { - header->blockSize = 256 * (1 << (blockSize - 8)); - } - - - if (sampleRate <= 11) { - header->sampleRate = sampleRateTable[sampleRate]; - } else if (sampleRate == 12) { - if (!drflac__read_uint32(bs, 8, &header->sampleRate)) { - return DR_FALSE; - } - header->sampleRate *= 1000; - } else if (sampleRate == 13) { - if (!drflac__read_uint32(bs, 16, &header->sampleRate)) { - return DR_FALSE; - } - } else if (sampleRate == 14) { - if (!drflac__read_uint32(bs, 16, &header->sampleRate)) { - return DR_FALSE; - } - header->sampleRate *= 10; - } else { - return DR_FALSE; // Invalid. - } - - - header->channelAssignment = channelAssignment; - - header->bitsPerSample = bitsPerSampleTable[bitsPerSample]; - if (header->bitsPerSample == 0) { - header->bitsPerSample = streaminfoBitsPerSample; - } - - if (drflac__read_uint8(bs, 8, &header->crc8) != 1) { - return DR_FALSE; - } - - return DR_TRUE; } -static dr_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe) +static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe) { - uint8_t header; + drflac_uint8 header; if (!drflac__read_uint8(bs, 8, &header)) { - return DR_FALSE; + return DRFLAC_FALSE; } // First bit should always be 0. if ((header & 0x80) != 0) { - return DR_FALSE; + return DRFLAC_FALSE; } int type = (header & 0x7E) >> 1; @@ -2110,7 +2818,7 @@ static dr_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pS } if (pSubframe->subframeType == DRFLAC_SUBFRAME_RESERVED) { - return DR_FALSE; + return DRFLAC_FALSE; } // Wasted bits per sample. @@ -2118,22 +2826,22 @@ static dr_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pS if ((header & 0x01) == 1) { unsigned int wastedBitsPerSample; if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) { - return DR_FALSE; + return DRFLAC_FALSE; } pSubframe->wastedBitsPerSample = (unsigned char)wastedBitsPerSample + 1; } - return DR_TRUE; + return DRFLAC_TRUE; } -static dr_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, int32_t* pDecodedSamplesOut) +static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, drflac_int32* pDecodedSamplesOut) { - assert(bs != NULL); - assert(frame != NULL); + drflac_assert(bs != NULL); + drflac_assert(frame != NULL); drflac_subframe* pSubframe = frame->subframes + subframeIndex; if (!drflac__read_subframe_header(bs, pSubframe)) { - return DR_FALSE; + return DRFLAC_FALSE; } // Side channels require an extra bit per sample. Took a while to figure that one out... @@ -2170,20 +2878,20 @@ static dr_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int drflac__decode_samples__lpc(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->lpcOrder, pSubframe->pDecodedSamples); } break; - default: return DR_FALSE; + default: return DRFLAC_FALSE; } - return DR_TRUE; + return DRFLAC_TRUE; } -static dr_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex) +static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex) { - assert(bs != NULL); - assert(frame != NULL); + drflac_assert(bs != NULL); + drflac_assert(frame != NULL); drflac_subframe* pSubframe = frame->subframes + subframeIndex; if (!drflac__read_subframe_header(bs, pSubframe)) { - return DR_FALSE; + return DRFLAC_FALSE; } // Side channels require an extra bit per sample. Took a while to figure that one out... @@ -2197,14 +2905,13 @@ static dr_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int s // Need to handle wasted bits per sample. pSubframe->bitsPerSample -= pSubframe->wastedBitsPerSample; pSubframe->pDecodedSamples = NULL; - //pSubframe->pDecodedSamples = pFlac->pDecodedSamples + (pFlac->currentFrame.header.blockSize * subframeIndex); switch (pSubframe->subframeType) { case DRFLAC_SUBFRAME_CONSTANT: { if (!drflac__seek_bits(bs, pSubframe->bitsPerSample)) { - return DR_FALSE; + return DRFLAC_FALSE; } } break; @@ -2212,7 +2919,7 @@ static dr_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int s { unsigned int bitsToSeek = frame->header.blockSize * pSubframe->bitsPerSample; if (!drflac__seek_bits(bs, bitsToSeek)) { - return DR_FALSE; + return DRFLAC_FALSE; } } break; @@ -2220,11 +2927,11 @@ static dr_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int s { unsigned int bitsToSeek = pSubframe->lpcOrder * pSubframe->bitsPerSample; if (!drflac__seek_bits(bs, bitsToSeek)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (!drflac__read_and_seek_residual(bs, frame->header.blockSize, pSubframe->lpcOrder)) { - return DR_FALSE; + return DRFLAC_FALSE; } } break; @@ -2232,217 +2939,253 @@ static dr_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int s { unsigned int bitsToSeek = pSubframe->lpcOrder * pSubframe->bitsPerSample; if (!drflac__seek_bits(bs, bitsToSeek)) { - return DR_FALSE; + return DRFLAC_FALSE; } unsigned char lpcPrecision; if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (lpcPrecision == 15) { - return DR_FALSE; // Invalid. + return DRFLAC_FALSE; // Invalid. } lpcPrecision += 1; bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; // +5 for shift. if (!drflac__seek_bits(bs, bitsToSeek)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (!drflac__read_and_seek_residual(bs, frame->header.blockSize, pSubframe->lpcOrder)) { - return DR_FALSE; + return DRFLAC_FALSE; } } break; - default: return DR_FALSE; + default: return DRFLAC_FALSE; } - return DR_TRUE; + return DRFLAC_TRUE; } -static DRFLAC_INLINE uint8_t drflac__get_channel_count_from_channel_assignment(int8_t channelAssignment) +static DRFLAC_INLINE drflac_uint8 drflac__get_channel_count_from_channel_assignment(drflac_int8 channelAssignment) { - assert(channelAssignment <= 10); + drflac_assert(channelAssignment <= 10); - uint8_t lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2}; + drflac_uint8 lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2}; return lookup[channelAssignment]; } -static dr_bool32 drflac__decode_frame(drflac* pFlac) +static drflac_result drflac__decode_frame(drflac* pFlac) { // This function should be called while the stream is sitting on the first byte after the frame header. - memset(pFlac->currentFrame.subframes, 0, sizeof(pFlac->currentFrame.subframes)); + drflac_zero_memory(pFlac->currentFrame.subframes, sizeof(pFlac->currentFrame.subframes)); int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); - for (int i = 0; i < channelCount; ++i) - { + for (int i = 0; i < channelCount; ++i) { if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFrame, i, pFlac->pDecodedSamples + (pFlac->currentFrame.header.blockSize * i))) { - return DR_FALSE; + return DRFLAC_ERROR; } } - // At the end of the frame sits the padding and CRC. We don't use these so we can just seek past. - if (!drflac__seek_bits(&pFlac->bs, (DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7) + 16)) { - return DR_FALSE; + drflac_uint8 paddingSizeInBits = DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7; + if (paddingSizeInBits > 0) { + drflac_uint8 padding = 0; + if (!drflac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) { + return DRFLAC_END_OF_STREAM; + } } +#ifndef DR_FLAC_NO_CRC + drflac_uint16 actualCRC16 = drflac__flush_crc16(&pFlac->bs); +#endif + drflac_uint16 desiredCRC16; + if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { + return DRFLAC_END_OF_STREAM; + } + +#ifndef DR_FLAC_NO_CRC + if (actualCRC16 != desiredCRC16) { + return DRFLAC_CRC_MISMATCH; // CRC mismatch. + } +#endif pFlac->currentFrame.samplesRemaining = pFlac->currentFrame.header.blockSize * channelCount; - return DR_TRUE; + return DRFLAC_SUCCESS; } -static dr_bool32 drflac__seek_frame(drflac* pFlac) +static drflac_result drflac__seek_frame(drflac* pFlac) { int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); - for (int i = 0; i < channelCount; ++i) - { + for (int i = 0; i < channelCount; ++i) { if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFrame, i)) { - return DR_FALSE; + return DRFLAC_ERROR; } } - // Padding and CRC. - return drflac__seek_bits(&pFlac->bs, (DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7) + 16); -} - -static dr_bool32 drflac__read_and_decode_next_frame(drflac* pFlac) -{ - assert(pFlac != NULL); - - if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { - return DR_FALSE; + // Padding. + if (!drflac__seek_bits(&pFlac->bs, DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) { + return DRFLAC_ERROR; } - return drflac__decode_frame(pFlac); + // CRC. +#ifndef DR_FLAC_NO_CRC + drflac_uint16 actualCRC16 = drflac__flush_crc16(&pFlac->bs); +#endif + drflac_uint16 desiredCRC16; + if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { + return DRFLAC_END_OF_STREAM; + } + +#ifndef DR_FLAC_NO_CRC + if (actualCRC16 != desiredCRC16) { + return DRFLAC_CRC_MISMATCH; // CRC mismatch. + } +#endif + + return DRFLAC_SUCCESS; +} + +static drflac_bool32 drflac__read_and_decode_next_frame(drflac* pFlac) +{ + drflac_assert(pFlac != NULL); + + for (;;) { + if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { + return DRFLAC_FALSE; + } + + drflac_result result = drflac__decode_frame(pFlac); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_CRC_MISMATCH) { + continue; // CRC mismatch. Skip to the next frame. + } else { + return DRFLAC_FALSE; + } + } + + return DRFLAC_TRUE; + } } -static void drflac__get_current_frame_sample_range(drflac* pFlac, uint64_t* pFirstSampleInFrameOut, uint64_t* pLastSampleInFrameOut) +static void drflac__get_current_frame_sample_range(drflac* pFlac, drflac_uint64* pFirstSampleInFrameOut, drflac_uint64* pLastSampleInFrameOut) { - assert(pFlac != NULL); + drflac_assert(pFlac != NULL); unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); - uint64_t firstSampleInFrame = pFlac->currentFrame.header.sampleNumber; + drflac_uint64 firstSampleInFrame = pFlac->currentFrame.header.sampleNumber; if (firstSampleInFrame == 0) { firstSampleInFrame = pFlac->currentFrame.header.frameNumber * pFlac->maxBlockSize*channelCount; } - uint64_t lastSampleInFrame = firstSampleInFrame + (pFlac->currentFrame.header.blockSize*channelCount); + drflac_uint64 lastSampleInFrame = firstSampleInFrame + (pFlac->currentFrame.header.blockSize*channelCount); if (lastSampleInFrame > 0) { lastSampleInFrame -= 1; // Needs to be zero based. } - - if (pFirstSampleInFrameOut) { - *pFirstSampleInFrameOut = firstSampleInFrame; - } - if (pLastSampleInFrameOut) { - *pLastSampleInFrameOut = lastSampleInFrame; - } + if (pFirstSampleInFrameOut) *pFirstSampleInFrameOut = firstSampleInFrame; + if (pLastSampleInFrameOut) *pLastSampleInFrameOut = lastSampleInFrame; } -static dr_bool32 drflac__seek_to_first_frame(drflac* pFlac) +static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac) { - assert(pFlac != NULL); + drflac_assert(pFlac != NULL); - dr_bool32 result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos); + drflac_bool32 result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos); - memset(&pFlac->currentFrame, 0, sizeof(pFlac->currentFrame)); + drflac_zero_memory(&pFlac->currentFrame, sizeof(pFlac->currentFrame)); return result; } -static DRFLAC_INLINE dr_bool32 drflac__seek_to_next_frame(drflac* pFlac) +static DRFLAC_INLINE drflac_result drflac__seek_to_next_frame(drflac* pFlac) { // This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section. - assert(pFlac != NULL); + drflac_assert(pFlac != NULL); return drflac__seek_frame(pFlac); } -static dr_bool32 drflac__seek_to_frame_containing_sample(drflac* pFlac, uint64_t sampleIndex) +static drflac_bool32 drflac__seek_to_sample__brute_force(drflac* pFlac, drflac_uint64 sampleIndex) { - assert(pFlac != NULL); - + // We need to find the frame that contains the sample. To do this, we iterate over each frame and inspect it's header. If based on the + // header we can determine that the frame contains the sample, we do a full decode of that frame. if (!drflac__seek_to_first_frame(pFlac)) { - return DR_FALSE; + return DRFLAC_FALSE; } - uint64_t firstSampleInFrame = 0; - uint64_t lastSampleInFrame = 0; - for (;;) - { - // We need to read the frame's header in order to determine the range of samples it contains. + drflac_uint64 runningSampleCount = 0; + for (;;) { if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { - return DR_FALSE; + return DRFLAC_FALSE; } + drflac_uint64 firstSampleInFrame = 0; + drflac_uint64 lastSampleInFrame = 0; drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame); - if (sampleIndex >= firstSampleInFrame && sampleIndex <= lastSampleInFrame) { - break; // The sample is in this frame. - } - if (!drflac__seek_to_next_frame(pFlac)) { - return DR_FALSE; + drflac_uint64 sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; + if (sampleIndex < (runningSampleCount + sampleCountInThisFrame)) { + // The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend + // it never existed and keep iterating. + drflac_result result = drflac__decode_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + // The frame is valid. We just need to skip over some samples to ensure it's sample-exact. + drflac_uint64 samplesToDecode = (size_t)(sampleIndex - runningSampleCount); // <-- Safe cast because the maximum number of samples in a frame is 65535. + if (samplesToDecode == 0) { + return DRFLAC_TRUE; + } + return drflac_read_s32(pFlac, samplesToDecode, NULL) != 0; // <-- If this fails, something bad has happened (it should never fail). + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; // CRC mismatch. Pretend this frame never existed. + } else { + return DRFLAC_FALSE; + } + } + } else { + // It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + // frame never existed and leave the running sample count untouched. + drflac_result result = drflac__seek_to_next_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + runningSampleCount += sampleCountInThisFrame; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; // CRC mismatch. Pretend this frame never existed. + } else { + return DRFLAC_FALSE; + } + } } } - - // If we get here we should be right at the start of the frame containing the sample. - return DR_TRUE; -} - -static dr_bool32 drflac__seek_to_sample__brute_force(drflac* pFlac, uint64_t sampleIndex) -{ - if (!drflac__seek_to_frame_containing_sample(pFlac, sampleIndex)) { - return DR_FALSE; - } - - // At this point we should be sitting on the first byte of the frame containing the sample. We need to decode every sample up to (but - // not including) the sample we're seeking to. - uint64_t firstSampleInFrame = 0; - drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, NULL); - - assert(firstSampleInFrame <= sampleIndex); - size_t samplesToDecode = (size_t)(sampleIndex - firstSampleInFrame); // <-- Safe cast because the maximum number of samples in a frame is 65535. - if (samplesToDecode == 0) { - return DR_TRUE; - } - - // At this point we are just sitting on the byte after the frame header. We need to decode the frame before reading anything from it. - if (!drflac__decode_frame(pFlac)) { - return DR_FALSE; - } - - return drflac_read_s32(pFlac, samplesToDecode, NULL) != 0; } -static dr_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, uint64_t sampleIndex) +static drflac_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, drflac_uint64 sampleIndex) { - assert(pFlac != NULL); + drflac_assert(pFlac != NULL); if (pFlac->seektablePos == 0) { - return DR_FALSE; + return DRFLAC_FALSE; } if (!drflac__seek_to_byte(&pFlac->bs, pFlac->seektablePos)) { - return DR_FALSE; + return DRFLAC_FALSE; } // The number of seek points is derived from the size of the SEEKTABLE block. - uint32_t seekpointCount = pFlac->seektableSize / 18; // 18 = the size of each seek point. + drflac_uint32 seekpointCount = pFlac->seektableSize / 18; // 18 = the size of each seek point. if (seekpointCount == 0) { - return DR_FALSE; // Would this ever happen? + return DRFLAC_FALSE; // Would this ever happen? } drflac_seekpoint closestSeekpoint = {0, 0, 0}; - uint32_t seekpointsRemaining = seekpointCount; - while (seekpointsRemaining > 0) - { + drflac_uint32 seekpointsRemaining = seekpointCount; + while (seekpointsRemaining > 0) { drflac_seekpoint seekpoint; if (!drflac__read_uint64(&pFlac->bs, 64, &seekpoint.firstSample)) { break; @@ -2454,7 +3197,9 @@ static dr_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, uint64_t samp break; } - if (seekpoint.firstSample * pFlac->channels > sampleIndex) { + // Note that the seekpoint sample is based on a single channel. The input sample (sampleIndex) is based on interleaving, thus + // we need to multiple the seekpoint's sample by the channel count. + if (seekpoint.firstSample*pFlac->channels > sampleIndex) { break; } @@ -2465,53 +3210,68 @@ static dr_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, uint64_t samp // At this point we should have found the seekpoint closest to our sample. We need to seek to it using basically the same // technique as we use with the brute force method. if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos + closestSeekpoint.frameOffset)) { - return DR_FALSE; + return DRFLAC_FALSE; } - - uint64_t firstSampleInFrame = 0; - uint64_t lastSampleInFrame = 0; - for (;;) - { - // We need to read the frame's header in order to determine the range of samples it contains. + drflac_uint64 runningSampleCount = closestSeekpoint.firstSample*pFlac->channels; + for (;;) { if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { - return DR_FALSE; + return DRFLAC_FALSE; } + drflac_uint64 firstSampleInFrame = 0; + drflac_uint64 lastSampleInFrame = 0; drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame); - if (sampleIndex >= firstSampleInFrame && sampleIndex <= lastSampleInFrame) { - break; // The sample is in this frame. - } - if (!drflac__seek_to_next_frame(pFlac)) { - return DR_FALSE; + drflac_uint64 sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; + if (sampleIndex < (runningSampleCount + sampleCountInThisFrame)) { + // The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend + // it never existed and keep iterating. + drflac_result result = drflac__decode_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + // The frame is valid. We just need to skip over some samples to ensure it's sample-exact. + drflac_uint64 samplesToDecode = (size_t)(sampleIndex - runningSampleCount); // <-- Safe cast because the maximum number of samples in a frame is 65535. + if (samplesToDecode == 0) { + return DRFLAC_TRUE; + } + return drflac_read_s32(pFlac, samplesToDecode, NULL) != 0; // <-- If this fails, something bad has happened (it should never fail). + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; // CRC mismatch. Pretend this frame never existed. + } else { + return DRFLAC_FALSE; + } + } + } else { + // It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + // frame never existed and leave the running sample count untouched. + drflac_result result = drflac__seek_to_next_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + runningSampleCount += sampleCountInThisFrame; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; // CRC mismatch. Pretend this frame never existed. + } else { + return DRFLAC_FALSE; + } + } } } - - assert(firstSampleInFrame <= sampleIndex); - - // At this point we are just sitting on the byte after the frame header. We need to decode the frame before reading anything from it. - if (!drflac__decode_frame(pFlac)) { - return DR_FALSE; - } - - size_t samplesToDecode = (size_t)(sampleIndex - firstSampleInFrame); // <-- Safe cast because the maximum number of samples in a frame is 65535. - return drflac_read_s32(pFlac, samplesToDecode, NULL) == samplesToDecode; } #ifndef DR_FLAC_NO_OGG typedef struct { - uint8_t capturePattern[4]; // Should be "OggS" - uint8_t structureVersion; // Always 0. - uint8_t headerType; - uint64_t granulePosition; - uint32_t serialNumber; - uint32_t sequenceNumber; - uint32_t checksum; - uint8_t segmentCount; - uint8_t segmentTable[255]; + drflac_uint8 capturePattern[4]; // Should be "OggS" + drflac_uint8 structureVersion; // Always 0. + drflac_uint8 headerType; + drflac_uint64 granulePosition; + drflac_uint32 serialNumber; + drflac_uint32 sequenceNumber; + drflac_uint32 checksum; + drflac_uint8 segmentCount; + drflac_uint8 segmentTable[255]; } drflac_ogg_page_header; #endif @@ -2520,25 +3280,28 @@ typedef struct drflac_read_proc onRead; drflac_seek_proc onSeek; drflac_meta_proc onMeta; + drflac_container container; void* pUserData; void* pUserDataMD; - drflac_container container; - uint32_t sampleRate; - uint8_t channels; - uint8_t bitsPerSample; - uint64_t totalSampleCount; - uint16_t maxBlockSize; - uint64_t runningFilePos; - dr_bool32 hasMetadataBlocks; + drflac_uint32 sampleRate; + drflac_uint8 channels; + drflac_uint8 bitsPerSample; + drflac_uint64 totalSampleCount; + drflac_uint16 maxBlockSize; + drflac_uint64 runningFilePos; + drflac_bool32 hasStreamInfoBlock; + drflac_bool32 hasMetadataBlocks; + drflac_bs bs; // <-- A bit streamer is required for loading data during initialization. + drflac_frame_header firstFrameHeader; // <-- The header of the first frame that was read during relaxed initalization. Only set if there is no STREAMINFO block. #ifndef DR_FLAC_NO_OGG - uint32_t oggSerial; - uint64_t oggFirstBytePos; + drflac_uint32 oggSerial; + drflac_uint64 oggFirstBytePos; drflac_ogg_page_header oggBosHeader; #endif } drflac_init_info; -static DRFLAC_INLINE void drflac__decode_block_header(uint32_t blockHeader, uint8_t* isLastBlock, uint8_t* blockType, uint32_t* blockSize) +static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize) { blockHeader = drflac__be2host_32(blockHeader); *isLastBlock = (blockHeader & (0x01 << 31)) >> 31; @@ -2546,41 +3309,41 @@ static DRFLAC_INLINE void drflac__decode_block_header(uint32_t blockHeader, uint *blockSize = (blockHeader & 0xFFFFFF); } -static DRFLAC_INLINE dr_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, uint8_t* isLastBlock, uint8_t* blockType, uint32_t* blockSize) +static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize) { - uint32_t blockHeader; + drflac_uint32 blockHeader; if (onRead(pUserData, &blockHeader, 4) != 4) { - return DR_FALSE; + return DRFLAC_FALSE; } drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize); - return DR_TRUE; + return DRFLAC_TRUE; } -dr_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo) +drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo) { // min/max block size. - uint32_t blockSizes; + drflac_uint32 blockSizes; if (onRead(pUserData, &blockSizes, 4) != 4) { - return DR_FALSE; + return DRFLAC_FALSE; } // min/max frame size. - uint64_t frameSizes = 0; + drflac_uint64 frameSizes = 0; if (onRead(pUserData, &frameSizes, 6) != 6) { - return DR_FALSE; + return DRFLAC_FALSE; } // Sample rate, channels, bits per sample and total sample count. - uint64_t importantProps; + drflac_uint64 importantProps; if (onRead(pUserData, &importantProps, 8) != 8) { - return DR_FALSE; + return DRFLAC_FALSE; } // MD5 - uint8_t md5[16]; + drflac_uint8 md5[16]; if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) { - return DR_FALSE; + return DRFLAC_FALSE; } blockSizes = drflac__be2host_32(blockSizes); @@ -2589,34 +3352,33 @@ dr_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drfl pStreamInfo->minBlockSize = (blockSizes & 0xFFFF0000) >> 16; pStreamInfo->maxBlockSize = blockSizes & 0x0000FFFF; - pStreamInfo->minFrameSize = (uint32_t)((frameSizes & 0xFFFFFF0000000000ULL) >> 40ULL); - pStreamInfo->maxFrameSize = (uint32_t)((frameSizes & 0x000000FFFFFF0000ULL) >> 16ULL); - pStreamInfo->sampleRate = (uint32_t)((importantProps & 0xFFFFF00000000000ULL) >> 44ULL); - pStreamInfo->channels = (uint8_t )((importantProps & 0x00000E0000000000ULL) >> 41ULL) + 1; - pStreamInfo->bitsPerSample = (uint8_t )((importantProps & 0x000001F000000000ULL) >> 36ULL) + 1; - pStreamInfo->totalSampleCount = (importantProps & 0x0000000FFFFFFFFFULL) * pStreamInfo->channels; - memcpy(pStreamInfo->md5, md5, sizeof(md5)); + pStreamInfo->minFrameSize = (drflac_uint32)((frameSizes & (drflac_uint64)0xFFFFFF0000000000) >> 40); + pStreamInfo->maxFrameSize = (drflac_uint32)((frameSizes & (drflac_uint64)0x000000FFFFFF0000) >> 16); + pStreamInfo->sampleRate = (drflac_uint32)((importantProps & (drflac_uint64)0xFFFFF00000000000) >> 44); + pStreamInfo->channels = (drflac_uint8 )((importantProps & (drflac_uint64)0x00000E0000000000) >> 41) + 1; + pStreamInfo->bitsPerSample = (drflac_uint8 )((importantProps & (drflac_uint64)0x000001F000000000) >> 36) + 1; + pStreamInfo->totalSampleCount = (importantProps & (drflac_uint64)0x0000000FFFFFFFFF) * pStreamInfo->channels; + drflac_copy_memory(pStreamInfo->md5, md5, sizeof(md5)); - return DR_TRUE; + return DRFLAC_TRUE; } -dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac) +drflac_bool32 drflac__read_and_decode_metadata(drflac* pFlac) { - assert(pFlac != NULL); + drflac_assert(pFlac != NULL); // We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that // we'll be sitting on byte 42. - uint64_t runningFilePos = 42; - uint64_t seektablePos = 0; - uint32_t seektableSize = 0; + drflac_uint64 runningFilePos = 42; + drflac_uint64 seektablePos = 0; + drflac_uint32 seektableSize = 0; - for (;;) - { - uint8_t isLastBlock = 0; - uint8_t blockType; - uint32_t blockSize; + for (;;) { + drflac_uint8 isLastBlock = 0; + drflac_uint8 blockType; + drflac_uint32 blockSize; if (!drflac__read_and_decode_block_header(pFlac->bs.onRead, pFlac->bs.pUserData, &isLastBlock, &blockType, &blockSize)) { - return DR_FALSE; + return DRFLAC_FALSE; } runningFilePos += 4; @@ -2631,24 +3393,24 @@ dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac) case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION: { if (pFlac->onMeta) { - void* pRawData = malloc(blockSize); + void* pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { - return DR_FALSE; + return DRFLAC_FALSE; } if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - free(pRawData); - return DR_FALSE; + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - metadata.data.application.id = drflac__be2host_32(*(uint32_t*)pRawData); - metadata.data.application.pData = (const void*)((uint8_t*)pRawData + sizeof(uint32_t)); - metadata.data.application.dataSize = blockSize - sizeof(uint32_t); + metadata.data.application.id = drflac__be2host_32(*(drflac_uint32*)pRawData); + metadata.data.application.pData = (const void*)((drflac_uint8*)pRawData + sizeof(drflac_uint32)); + metadata.data.application.dataSize = blockSize - sizeof(drflac_uint32); pFlac->onMeta(pFlac->pUserDataMD, &metadata); - free(pRawData); + DRFLAC_FREE(pRawData); } } break; @@ -2658,14 +3420,14 @@ dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac) seektableSize = blockSize; if (pFlac->onMeta) { - void* pRawData = malloc(blockSize); + void* pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { - return DR_FALSE; + return DRFLAC_FALSE; } if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - free(pRawData); - return DR_FALSE; + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; @@ -2674,7 +3436,7 @@ dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac) metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData; // Endian swap. - for (uint32_t iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) { + for (drflac_uint32 iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) { drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint; pSeekpoint->firstSample = drflac__be2host_64(pSeekpoint->firstSample); pSeekpoint->frameOffset = drflac__be2host_64(pSeekpoint->frameOffset); @@ -2683,96 +3445,96 @@ dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac) pFlac->onMeta(pFlac->pUserDataMD, &metadata); - free(pRawData); + DRFLAC_FREE(pRawData); } } break; case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT: { if (pFlac->onMeta) { - void* pRawData = malloc(blockSize); + void* pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { - return DR_FALSE; + return DRFLAC_FALSE; } if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - free(pRawData); - return DR_FALSE; + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; const char* pRunningData = (const char*)pRawData; - metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(uint32_t*)pRunningData); pRunningData += 4; - metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; - metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(uint32_t*)pRunningData); pRunningData += 4; + metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; + metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.vorbis_comment.comments = pRunningData; pFlac->onMeta(pFlac->pUserDataMD, &metadata); - free(pRawData); + DRFLAC_FREE(pRawData); } } break; case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET: { if (pFlac->onMeta) { - void* pRawData = malloc(blockSize); + void* pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { - return DR_FALSE; + return DRFLAC_FALSE; } if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - free(pRawData); - return DR_FALSE; + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; const char* pRunningData = (const char*)pRawData; - memcpy(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128; - metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(uint64_t*)pRunningData); pRunningData += 4; - metadata.data.cuesheet.isCD = ((pRunningData[0] & 0x80) >> 7) != 0; pRunningData += 259; - metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1; - metadata.data.cuesheet.pTrackData = (const uint8_t*)pRunningData; + drflac_copy_memory(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128; + metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(drflac_uint64*)pRunningData); pRunningData += 4; + metadata.data.cuesheet.isCD = ((pRunningData[0] & 0x80) >> 7) != 0; pRunningData += 259; + metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1; + metadata.data.cuesheet.pTrackData = (const drflac_uint8*)pRunningData; pFlac->onMeta(pFlac->pUserDataMD, &metadata); - free(pRawData); + DRFLAC_FREE(pRawData); } } break; case DRFLAC_METADATA_BLOCK_TYPE_PICTURE: { if (pFlac->onMeta) { - void* pRawData = malloc(blockSize); + void* pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { - return DR_FALSE; + return DRFLAC_FALSE; } if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - free(pRawData); - return DR_FALSE; + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; const char* pRunningData = (const char*)pRawData; - metadata.data.picture.type = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4; - metadata.data.picture.mimeLength = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4; - metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; - metadata.data.picture.descriptionLength = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4; + metadata.data.picture.type = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.mimeLength = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; + metadata.data.picture.descriptionLength = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; metadata.data.picture.description = pRunningData; - metadata.data.picture.width = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4; - metadata.data.picture.height = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4; - metadata.data.picture.colorDepth = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4; - metadata.data.picture.indexColorCount = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4; - metadata.data.picture.pictureDataSize = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4; - metadata.data.picture.pPictureData = (const uint8_t*)pRunningData; + metadata.data.picture.width = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.height = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.colorDepth = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.indexColorCount = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.pictureDataSize = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; pFlac->onMeta(pFlac->pUserDataMD, &metadata); - free(pRawData); + DRFLAC_FREE(pRawData); } } break; @@ -2781,12 +3543,12 @@ dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac) if (pFlac->onMeta) { metadata.data.padding.unused = 0; - // Padding doesn't have anything meaningful in it, so just skip over it. + // Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) { - return DR_FALSE; + isLastBlock = DRFLAC_TRUE; // An error occured while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. + } else { + pFlac->onMeta(pFlac->pUserDataMD, &metadata); } - - pFlac->onMeta(pFlac->pUserDataMD, &metadata); } } break; @@ -2795,7 +3557,7 @@ dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac) // Invalid chunk. Just skip over this one. if (pFlac->onMeta) { if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) { - return DR_FALSE; + isLastBlock = DRFLAC_TRUE; // An error occured while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. } } } @@ -2805,29 +3567,29 @@ dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac) // It's an unknown chunk, but not necessarily invalid. There's a chance more metadata blocks might be defined later on, so we // can at the very least report the chunk to the application and let it look at the raw data. if (pFlac->onMeta) { - void* pRawData = malloc(blockSize); + void* pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { - return DR_FALSE; + return DRFLAC_FALSE; } if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - free(pRawData); - return DR_FALSE; + DRFLAC_FREE(pRawData); + return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; pFlac->onMeta(pFlac->pUserDataMD, &metadata); - free(pRawData); + DRFLAC_FREE(pRawData); } } break; } // If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above. - if (pFlac->onMeta == NULL) { + if (pFlac->onMeta == NULL && blockSize > 0) { if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) { - return DR_FALSE; + isLastBlock = DRFLAC_TRUE; } } @@ -2841,10 +3603,10 @@ dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac) pFlac->seektableSize = seektableSize; pFlac->firstFramePos = runningFilePos; - return DR_TRUE; + return DRFLAC_TRUE; } -dr_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD) +drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed) { (void)onSeek; @@ -2853,56 +3615,193 @@ dr_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc pInit->container = drflac_container_native; // The first metadata block should be the STREAMINFO block. - uint8_t isLastBlock; - uint8_t blockType; - uint32_t blockSize; + drflac_uint8 isLastBlock; + drflac_uint8 blockType; + drflac_uint32 blockSize; if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { - return DR_FALSE; // Invalid block type. First block must be the STREAMINFO block. + if (!relaxed) { + // We're opening in strict mode and the first block is not the STREAMINFO block. Error. + return DRFLAC_FALSE; + } else { + // Relaxed mode. To open from here we need to just find the first frame and set the sample rate, etc. to whatever is defined + // for that frame. + pInit->hasStreamInfoBlock = DRFLAC_FALSE; + pInit->hasMetadataBlocks = DRFLAC_FALSE; + + if (!drflac__read_next_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) { + return DRFLAC_FALSE; // Couldn't find a frame. + } + + if (pInit->firstFrameHeader.bitsPerSample == 0) { + return DRFLAC_FALSE; // Failed to initialize because the first frame depends on the STREAMINFO block, which does not exist. + } + + pInit->sampleRate = pInit->firstFrameHeader.sampleRate; + pInit->channels = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment); + pInit->bitsPerSample = pInit->firstFrameHeader.bitsPerSample; + pInit->maxBlockSize = 65535; // <-- See notes here: https://xiph.org/flac/format.html#metadata_block_streaminfo + return DRFLAC_TRUE; + } + } else { + drflac_streaminfo streaminfo; + if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) { + return DRFLAC_FALSE; + } + + pInit->hasStreamInfoBlock = DRFLAC_TRUE; + pInit->sampleRate = streaminfo.sampleRate; + pInit->channels = streaminfo.channels; + pInit->bitsPerSample = streaminfo.bitsPerSample; + pInit->totalSampleCount = streaminfo.totalSampleCount; + pInit->maxBlockSize = streaminfo.maxBlockSize; // Don't care about the min block size - only the max (used for determining the size of the memory allocation). + pInit->hasMetadataBlocks = !isLastBlock; + + if (onMeta) { + drflac_metadata metadata; + metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO; + metadata.pRawData = NULL; + metadata.rawDataSize = 0; + metadata.data.streaminfo = streaminfo; + onMeta(pUserDataMD, &metadata); + } + + return DRFLAC_TRUE; } - - - drflac_streaminfo streaminfo; - if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) { - return DR_FALSE; - } - - pInit->sampleRate = streaminfo.sampleRate; - pInit->channels = streaminfo.channels; - pInit->bitsPerSample = streaminfo.bitsPerSample; - pInit->totalSampleCount = streaminfo.totalSampleCount; - pInit->maxBlockSize = streaminfo.maxBlockSize; // Don't care about the min block size - only the max (used for determining the size of the memory allocation). - - if (onMeta) { - drflac_metadata metadata; - metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO; - metadata.pRawData = NULL; - metadata.rawDataSize = 0; - metadata.data.streaminfo = streaminfo; - onMeta(pUserDataMD, &metadata); - } - - pInit->hasMetadataBlocks = !isLastBlock; - return DR_TRUE; } #ifndef DR_FLAC_NO_OGG -static DRFLAC_INLINE dr_bool32 drflac_ogg__is_capture_pattern(uint8_t pattern[4]) +#define DRFLAC_OGG_MAX_PAGE_SIZE 65307 +#define DRFLAC_OGG_CAPTURE_PATTERN_CRC32 1605413199 // CRC-32 of "OggS". + +typedef enum +{ + drflac_ogg_recover_on_crc_mismatch, + drflac_ogg_fail_on_crc_mismatch +} drflac_ogg_crc_mismatch_recovery; + + +static drflac_uint32 drflac__crc32_table[] = { + 0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, + 0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L, + 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L, + 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL, + 0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L, + 0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L, + 0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L, + 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL, + 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L, + 0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L, + 0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L, + 0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL, + 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L, + 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L, + 0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L, + 0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL, + 0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL, + 0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L, + 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L, + 0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL, + 0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL, + 0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L, + 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L, + 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL, + 0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL, + 0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L, + 0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L, + 0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL, + 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL, + 0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L, + 0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L, + 0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL, + 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L, + 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL, + 0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL, + 0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L, + 0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L, + 0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL, + 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL, + 0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L, + 0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L, + 0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL, + 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL, + 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L, + 0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L, + 0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL, + 0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL, + 0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L, + 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L, + 0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL, + 0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L, + 0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L, + 0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L, + 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL, + 0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L, + 0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L, + 0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L, + 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL, + 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L, + 0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L, + 0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L, + 0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL, + 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L, + 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L +}; + +static DRFLAC_INLINE drflac_uint32 drflac_crc32_byte(drflac_uint32 crc32, drflac_uint8 data) +{ +#ifndef DR_FLAC_NO_CRC + return (crc32 << 8) ^ drflac__crc32_table[(drflac_uint8)((crc32 >> 24) & 0xFF) ^ data]; +#else + (void)data; + return crc32; +#endif +} + +#if 0 +static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint32(drflac_uint32 crc32, drflac_uint32 data) +{ + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 24) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 16) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 8) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 0) & 0xFF)); + return crc32; +} + +static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint64(drflac_uint32 crc32, drflac_uint64 data) +{ + crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 32) & 0xFFFFFFFF)); + crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 0) & 0xFFFFFFFF)); + return crc32; +} +#endif + +static DRFLAC_INLINE drflac_uint32 drflac_crc32_buffer(drflac_uint32 crc32, drflac_uint8* pData, drflac_uint32 dataSize) +{ + // This can be optimized. + for (drflac_uint32 i = 0; i < dataSize; ++i) { + crc32 = drflac_crc32_byte(crc32, pData[i]); + } + return crc32; +} + + +static DRFLAC_INLINE drflac_bool32 drflac_ogg__is_capture_pattern(drflac_uint8 pattern[4]) { return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S'; } -static DRFLAC_INLINE uint32_t drflac_ogg__get_page_header_size(drflac_ogg_page_header* pHeader) +static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_header_size(drflac_ogg_page_header* pHeader) { return 27 + pHeader->segmentCount; } -static DRFLAC_INLINE uint32_t drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader) +static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader) { - uint32_t pageBodySize = 0; + drflac_uint32 pageBodySize = 0; for (int i = 0; i < pHeader->segmentCount; ++i) { pageBodySize += pHeader->segmentTable[i]; } @@ -2910,49 +3809,84 @@ static DRFLAC_INLINE uint32_t drflac_ogg__get_page_body_size(drflac_ogg_page_hea return pageBodySize; } -dr_bool32 drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize) +drflac_result drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32) { - if (onRead(pUserData, &pHeader->structureVersion, 1) != 1 || pHeader->structureVersion != 0) { - return DR_FALSE; // Unknown structure version. Possibly corrupt stream. + drflac_assert(*pCRC32 == DRFLAC_OGG_CAPTURE_PATTERN_CRC32); + + drflac_uint8 data[23]; + if (onRead(pUserData, data, 23) != 23) { + return DRFLAC_END_OF_STREAM; } - if (onRead(pUserData, &pHeader->headerType, 1) != 1) { - return DR_FALSE; - } - if (onRead(pUserData, &pHeader->granulePosition, 8) != 8) { - return DR_FALSE; - } - if (onRead(pUserData, &pHeader->serialNumber, 4) != 4) { - return DR_FALSE; - } - if (onRead(pUserData, &pHeader->sequenceNumber, 4) != 4) { - return DR_FALSE; - } - if (onRead(pUserData, &pHeader->checksum, 4) != 4) { - return DR_FALSE; - } - if (onRead(pUserData, &pHeader->segmentCount, 1) != 1 || pHeader->segmentCount == 0) { - return DR_FALSE; // Should not have a segment count of 0. - } - if (onRead(pUserData, &pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) { - return DR_FALSE; + *pBytesRead += 23; + + pHeader->structureVersion = data[0]; + pHeader->headerType = data[1]; + drflac_copy_memory(&pHeader->granulePosition, &data[ 2], 8); + drflac_copy_memory(&pHeader->serialNumber, &data[10], 4); + drflac_copy_memory(&pHeader->sequenceNumber, &data[14], 4); + drflac_copy_memory(&pHeader->checksum, &data[18], 4); + pHeader->segmentCount = data[22]; + + // Calculate the CRC. Note that for the calculation the checksum part of the page needs to be set to 0. + data[18] = 0; + data[19] = 0; + data[20] = 0; + data[21] = 0; + + drflac_uint32 i; + for (i = 0; i < 23; ++i) { + *pCRC32 = drflac_crc32_byte(*pCRC32, data[i]); } - if (pHeaderSize) *pHeaderSize = (27 + pHeader->segmentCount); - return DR_TRUE; + + if (onRead(pUserData, pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) { + return DRFLAC_END_OF_STREAM; + } + *pBytesRead += pHeader->segmentCount; + + for (i = 0; i < pHeader->segmentCount; ++i) { + *pCRC32 = drflac_crc32_byte(*pCRC32, pHeader->segmentTable[i]); + } + + return DRFLAC_SUCCESS; } -dr_bool32 drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize) +drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32) { - uint8_t id[4]; + *pBytesRead = 0; + + drflac_uint8 id[4]; if (onRead(pUserData, id, 4) != 4) { - return DR_FALSE; + return DRFLAC_END_OF_STREAM; } + *pBytesRead += 4; - if (id[0] != 'O' || id[1] != 'g' || id[2] != 'g' || id[3] != 'S') { - return DR_FALSE; + // We need to read byte-by-byte until we find the OggS capture pattern. + for (;;) { + if (drflac_ogg__is_capture_pattern(id)) { + *pCRC32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; + + drflac_result result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32); + if (result == DRFLAC_SUCCESS) { + return DRFLAC_SUCCESS; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; + } else { + return result; + } + } + } else { + // The first 4 bytes did not equal the capture pattern. Read the next byte and try again. + id[0] = id[1]; + id[1] = id[2]; + id[2] = id[3]; + if (onRead(pUserData, &id[3], 1) != 1) { + return DRFLAC_END_OF_STREAM; + } + *pBytesRead += 1; + } } - - return drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pHeaderSize); } @@ -2966,12 +3900,14 @@ typedef struct drflac_read_proc onRead; // The original onRead callback from drflac_open() and family. drflac_seek_proc onSeek; // The original onSeek callback from drflac_open() and family. void* pUserData; // The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. - uint64_t currentBytePos; // The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. - uint64_t firstBytePos; // The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. - uint32_t serialNumber; // The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization. + drflac_uint64 currentBytePos; // The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. + drflac_uint64 firstBytePos; // The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. + drflac_uint32 serialNumber; // The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization. drflac_ogg_page_header bosPageHeader; // Used for seeking. drflac_ogg_page_header currentPageHeader; - uint32_t bytesRemainingInPage; + drflac_uint32 bytesRemainingInPage; + drflac_uint32 pageDataSize; + drflac_uint8 pageData[DRFLAC_OGG_MAX_PAGE_SIZE]; } drflac_oggbs; // oggbs = Ogg Bitstream static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead) @@ -2982,82 +3918,103 @@ static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, return bytesActuallyRead; } -static dr_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, uint64_t offset, drflac_seek_origin origin) +static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin) { - if (origin == drflac_seek_origin_start) - { + if (origin == drflac_seek_origin_start) { if (offset <= 0x7FFFFFFF) { if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) { - return DR_FALSE; + return DRFLAC_FALSE; } oggbs->currentBytePos = offset; - return DR_TRUE; + return DRFLAC_TRUE; } else { if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) { - return DR_FALSE; + return DRFLAC_FALSE; } oggbs->currentBytePos = offset; return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current); } - } - else - { + } else { while (offset > 0x7FFFFFFF) { if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) { - return DR_FALSE; + return DRFLAC_FALSE; } oggbs->currentBytePos += 0x7FFFFFFF; offset -= 0x7FFFFFFF; } if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { // <-- Safe cast thanks to the loop above. - return DR_FALSE; + return DRFLAC_FALSE; } oggbs->currentBytePos += offset; - return DR_TRUE; + return DRFLAC_TRUE; } } -static dr_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs) +static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_ogg_crc_mismatch_recovery recoveryMethod) { drflac_ogg_page_header header; - for (;;) - { - uint32_t headerSize; - if (!drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &headerSize)) { - return DR_FALSE; + for (;;) { + drflac_uint32 crc32 = 0; + drflac_uint32 bytesRead; + if (drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; } - oggbs->currentBytePos += headerSize; + oggbs->currentBytePos += bytesRead; - - uint32_t pageBodySize = drflac_ogg__get_page_body_size(&header); - - if (header.serialNumber == oggbs->serialNumber) { - oggbs->currentPageHeader = header; - oggbs->bytesRemainingInPage = pageBodySize; - return DR_TRUE; + drflac_uint32 pageBodySize = drflac_ogg__get_page_body_size(&header); + if (pageBodySize > DRFLAC_OGG_MAX_PAGE_SIZE) { + continue; // Invalid page size. Assume it's corrupted and just move to the next page. } - // If we get here it means the page is not a FLAC page - skip it. - if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) { // <-- Safe cast - maximum size of a page is way below that of an int. - return DR_FALSE; + if (header.serialNumber != oggbs->serialNumber) { + // It's not a FLAC page. Skip it. + if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) { + return DRFLAC_FALSE; + } + continue; } + + + // We need to read the entire page and then do a CRC check on it. If there's a CRC mismatch we need to skip this page. + if (drflac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) { + return DRFLAC_FALSE; + } + oggbs->pageDataSize = pageBodySize; + +#ifndef DR_FLAC_NO_CRC + drflac_uint32 actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize); + if (actualCRC32 != header.checksum) { + if (recoveryMethod == drflac_ogg_recover_on_crc_mismatch) { + continue; // CRC mismatch. Skip this page. + } else { + // Even though we are failing on a CRC mismatch, we still want our stream to be in a good state. Therefore we + // go to the next valid page to ensure we're in a good state, but return false to let the caller know that the + // seek did not fully complete. + drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch); + return DRFLAC_FALSE; + } + } +#endif + + oggbs->currentPageHeader = header; + oggbs->bytesRemainingInPage = pageBodySize; + return DRFLAC_TRUE; } } // Function below is unused at the moment, but I might be re-adding it later. #if 0 -static uint8_t drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, uint8_t* pBytesRemainingInSeg) +static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, drflac_uint8* pBytesRemainingInSeg) { - uint32_t bytesConsumedInPage = drflac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage; - uint8_t iSeg = 0; - uint32_t iByte = 0; - while (iByte < bytesConsumedInPage) - { - uint8_t segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; + drflac_uint32 bytesConsumedInPage = drflac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage; + drflac_uint8 iSeg = 0; + drflac_uint32 iByte = 0; + while (iByte < bytesConsumedInPage) { + drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; if (iByte + segmentSize > bytesConsumedInPage) { break; } else { @@ -3066,26 +4023,25 @@ static uint8_t drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, uint } } - *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (uint8_t)(bytesConsumedInPage - iByte); + *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (drflac_uint8)(bytesConsumedInPage - iByte); return iSeg; } -static dr_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs) +static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs) { // The current packet ends when we get to the segment with a lacing value of < 255 which is not at the end of a page. - for (;;) // <-- Loop over pages. - { - dr_bool32 atEndOfPage = DR_FALSE; + for (;;) { + drflac_bool32 atEndOfPage = DRFLAC_FALSE; - uint8_t bytesRemainingInSeg; - uint8_t iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg); + drflac_uint8 bytesRemainingInSeg; + drflac_uint8 iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg); - uint32_t bytesToEndOfPacketOrPage = bytesRemainingInSeg; - for (uint8_t iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) { - uint8_t segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; + drflac_uint32 bytesToEndOfPacketOrPage = bytesRemainingInSeg; + for (drflac_uint8 iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) { + drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; if (segmentSize < 255) { if (iSeg == oggbs->currentPageHeader.segmentCount-1) { - atEndOfPage = DR_TRUE; + atEndOfPage = DRFLAC_TRUE; } break; @@ -3095,32 +4051,29 @@ static dr_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs) } // At this point we will have found either the packet or the end of the page. If were at the end of the page we'll - // want to load the next page and keep searching for the end of the frame. + // want to load the next page and keep searching for the end of the packet. drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current); oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage; - if (atEndOfPage) - { + if (atEndOfPage) { // We're potentially at the next packet, but we need to check the next page first to be sure because the packet may // straddle pages. if (!drflac_oggbs__goto_next_page(oggbs)) { - return DR_FALSE; + return DRFLAC_FALSE; } // If it's a fresh packet it most likely means we're at the next packet. if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { - return DR_TRUE; + return DRFLAC_TRUE; } - } - else - { - // We're at the next frame. - return DR_TRUE; + } else { + // We're at the next packet. + return DRFLAC_TRUE; } } } -static dr_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs) +static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs) { // The bitstream should be sitting on the first byte just after the header of the frame. @@ -3132,76 +4085,67 @@ static dr_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs) static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead) { drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; - assert(oggbs != NULL); + drflac_assert(oggbs != NULL); - uint8_t* pRunningBufferOut = (uint8_t*)bufferOut; + drflac_uint8* pRunningBufferOut = (drflac_uint8*)bufferOut; // Reading is done page-by-page. If we've run out of bytes in the page we need to move to the next one. size_t bytesRead = 0; - while (bytesRead < bytesToRead) - { + while (bytesRead < bytesToRead) { size_t bytesRemainingToRead = bytesToRead - bytesRead; if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) { - bytesRead += oggbs->onRead(oggbs->pUserData, pRunningBufferOut, bytesRemainingToRead); - oggbs->bytesRemainingInPage -= (uint32_t)bytesRemainingToRead; + drflac_copy_memory(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), bytesRemainingToRead); + bytesRead += bytesRemainingToRead; + oggbs->bytesRemainingInPage -= (drflac_uint32)bytesRemainingToRead; break; } // If we get here it means some of the requested data is contained in the next pages. if (oggbs->bytesRemainingInPage > 0) { - size_t bytesJustRead = oggbs->onRead(oggbs->pUserData, pRunningBufferOut, oggbs->bytesRemainingInPage); - bytesRead += bytesJustRead; - pRunningBufferOut += bytesJustRead; - - if (bytesJustRead != oggbs->bytesRemainingInPage) { - break; // Ran out of data. - } + drflac_copy_memory(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), oggbs->bytesRemainingInPage); + bytesRead += oggbs->bytesRemainingInPage; + pRunningBufferOut += oggbs->bytesRemainingInPage; + oggbs->bytesRemainingInPage = 0; } - assert(bytesRemainingToRead > 0); - if (!drflac_oggbs__goto_next_page(oggbs)) { - break; // Failed to go to the next chunk. Might have simply hit the end of the stream. + drflac_assert(bytesRemainingToRead > 0); + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { + break; // Failed to go to the next page. Might have simply hit the end of the stream. } } - oggbs->currentBytePos += bytesRead; return bytesRead; } -static dr_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin) +static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin) { drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; - assert(oggbs != NULL); - assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); + drflac_assert(oggbs != NULL); + drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); // Seeking is always forward which makes things a lot simpler. if (origin == drflac_seek_origin_start) { - int startBytePos = (int)oggbs->firstBytePos + (79-42); // 79 = size of bos page; 42 = size of FLAC header data. Seek up to the first byte of the native FLAC data. - if (!drflac_oggbs__seek_physical(oggbs, startBytePos, drflac_seek_origin_start)) { - return DR_FALSE; + if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) { + return DRFLAC_FALSE; } - oggbs->currentPageHeader = oggbs->bosPageHeader; - oggbs->bytesRemainingInPage = 42; // 42 = size of the native FLAC header data. That's our start point for seeking. + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) { + return DRFLAC_FALSE; + } return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current); } - assert(origin == drflac_seek_origin_current); + drflac_assert(origin == drflac_seek_origin_current); int bytesSeeked = 0; - while (bytesSeeked < offset) - { + while (bytesSeeked < offset) { int bytesRemainingToSeek = offset - bytesSeeked; - assert(bytesRemainingToSeek >= 0); + drflac_assert(bytesRemainingToSeek >= 0); if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { - if (!drflac_oggbs__seek_physical(oggbs, bytesRemainingToSeek, drflac_seek_origin_current)) { - return DR_FALSE; - } - bytesSeeked += bytesRemainingToSeek; oggbs->bytesRemainingInPage -= bytesRemainingToSeek; break; @@ -3209,45 +4153,42 @@ static dr_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_or // If we get here it means some of the requested data is contained in the next pages. if (oggbs->bytesRemainingInPage > 0) { - if (!drflac_oggbs__seek_physical(oggbs, oggbs->bytesRemainingInPage, drflac_seek_origin_current)) { - return DR_FALSE; - } - bytesSeeked += (int)oggbs->bytesRemainingInPage; + oggbs->bytesRemainingInPage = 0; } - assert(bytesRemainingToSeek > 0); - if (!drflac_oggbs__goto_next_page(oggbs)) { - break; // Failed to go to the next chunk. Might have simply hit the end of the stream. + drflac_assert(bytesRemainingToSeek > 0); + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) { + // Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. + return DRFLAC_FALSE; } } - return DR_TRUE; + return DRFLAC_TRUE; } -dr_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, uint64_t sample) +drflac_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex) { - drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + pFlac->maxBlockSize*pFlac->channels); + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; - uint64_t originalBytePos = oggbs->currentBytePos; // For recovery. + drflac_uint64 originalBytePos = oggbs->currentBytePos; // For recovery. // First seek to the first frame. if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos)) { - return DR_FALSE; + return DRFLAC_FALSE; } oggbs->bytesRemainingInPage = 0; - uint64_t runningGranulePosition = 0; - uint64_t runningFrameBytePos = oggbs->currentBytePos; // <-- Points to the OggS identifier. - for (;;) - { - if (!drflac_oggbs__goto_next_page(oggbs)) { + drflac_uint64 runningGranulePosition = 0; + drflac_uint64 runningFrameBytePos = oggbs->currentBytePos; // <-- Points to the OggS identifier. + for (;;) { + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start); - return DR_FALSE; // Never did find that sample... + return DRFLAC_FALSE; // Never did find that sample... } - runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader); - if (oggbs->currentPageHeader.granulePosition*pFlac->channels >= sample) { + runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize; + if (oggbs->currentPageHeader.granulePosition*pFlac->channels >= sampleIndex) { break; // The sample is somewhere in the previous page. } @@ -3256,28 +4197,17 @@ dr_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, uint64_t sample) // disregard any pages that do not begin a fresh packet. if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { // <-- Is it a fresh page? if (oggbs->currentPageHeader.segmentTable[0] >= 2) { - uint8_t firstBytesInPage[2]; - if (drflac_oggbs__read_physical(oggbs, firstBytesInPage, 2) != 2) { - drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start); - return DR_FALSE; - } + drflac_uint8 firstBytesInPage[2]; + firstBytesInPage[0] = oggbs->pageData[0]; + firstBytesInPage[1] = oggbs->pageData[1]; + if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { // <-- Does the page begin with a frame's sync code? runningGranulePosition = oggbs->currentPageHeader.granulePosition*pFlac->channels; } - if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->bytesRemainingInPage-2, drflac_seek_origin_current)) { - drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start); - return DR_FALSE; - } - continue; } } - - if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->bytesRemainingInPage, drflac_seek_origin_current)) { - drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start); - return DR_FALSE; - } } @@ -3286,71 +4216,85 @@ dr_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, uint64_t sample) // a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until // we find the one containing the target sample. if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) { - return DR_FALSE; + return DRFLAC_FALSE; } - if (!drflac_oggbs__goto_next_page(oggbs)) { - return DR_FALSE; + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { + return DRFLAC_FALSE; } // At this point we'll be sitting on the first byte of the frame header of the first frame in the page. We just keep // looping over these frames until we find the one containing the sample we're after. - uint64_t firstSampleInFrame = runningGranulePosition; - for (;;) - { - // NOTE for later: When using Ogg's page/segment based seeking later on we can't use this function (or any drflac__* - // reading functions) because otherwise it will pull extra data for use in it's own internal caches which will then - // break the positioning of the read pointer for the Ogg bitstream. + drflac_uint64 runningSampleCount = runningGranulePosition; + for (;;) { + // There are two ways to find the sample and seek past irrelevant frames: + // 1) Use the native FLAC decoder. + // 2) Use Ogg's framing system. + // + // Both of these options have their own pros and cons. Using the native FLAC decoder is slower because it needs to + // do a full decode of the frame. Using Ogg's framing system is faster, but more complicated and involves some code + // duplication for the decoding of frame headers. + // + // Another thing to consider is that using the Ogg framing system will perform direct seeking of the physical Ogg + // bitstream. This is important to consider because it means we cannot read data from the drflac_bs object using the + // standard drflac__*() APIs because that will read in extra data for it's own internal caching which in turn breaks + // the positioning of the read pointer of the physical Ogg bitstream. Therefore, anything that would normally be read + // using the native FLAC decoding APIs, such as drflac__read_next_frame_header(), need to be re-implemented so as to + // avoid the use of the drflac_bs object. + // + // Considering these issues, I have decided to use the slower native FLAC decoding method for the following reasons: + // 1) Seeking is already partially accellerated using Ogg's paging system in the code block above. + // 2) Seeking in an Ogg encapsulated FLAC stream is probably quite uncommon. + // 3) Simplicity. if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { - return DR_FALSE; + return DRFLAC_FALSE; } - int channels = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); - uint64_t lastSampleInFrame = firstSampleInFrame + (pFlac->currentFrame.header.blockSize*channels); - lastSampleInFrame -= 1; // <-- Zero based. + drflac_uint64 firstSampleInFrame = 0; + drflac_uint64 lastSampleInFrame = 0; + drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame); - if (sample >= firstSampleInFrame && sample <= lastSampleInFrame) { - break; // The sample is in this frame. + drflac_uint64 sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; + if (sampleIndex < (runningSampleCount + sampleCountInThisFrame)) { + // The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend + // it never existed and keep iterating. + drflac_result result = drflac__decode_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + // The frame is valid. We just need to skip over some samples to ensure it's sample-exact. + drflac_uint64 samplesToDecode = (size_t)(sampleIndex - runningSampleCount); // <-- Safe cast because the maximum number of samples in a frame is 65535. + if (samplesToDecode == 0) { + return DRFLAC_TRUE; + } + return drflac_read_s32(pFlac, samplesToDecode, NULL) != 0; // <-- If this fails, something bad has happened (it should never fail). + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; // CRC mismatch. Pretend this frame never existed. + } else { + return DRFLAC_FALSE; + } + } + } else { + // It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + // frame never existed and leave the running sample count untouched. + drflac_result result = drflac__seek_to_next_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + runningSampleCount += sampleCountInThisFrame; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; // CRC mismatch. Pretend this frame never existed. + } else { + return DRFLAC_FALSE; + } + } } - - - // If we get here it means the sample is not in this frame so we need to move to the next one. Now the cool thing - // with Ogg is that we can efficiently seek past the frame by looking at the lacing values of each segment in - // the page. - firstSampleInFrame = lastSampleInFrame+1; - -#if 1 - // Slow way. This uses the native FLAC decoder to seek past the frame. This is slow because it needs to do a partial - // decode of the frame. Although this is how the native version works, we can use Ogg's framing system to make it - // more efficient. Leaving this here for reference and to use as a basis for debugging purposes. - if (!drflac__seek_to_next_frame(pFlac)) { - return DR_FALSE; - } -#else - // TODO: This is not yet complete. See note at the top of this loop body. - - // Fast(er) way. This uses Ogg's framing system to seek past the frame. This should be much more efficient than the - // native FLAC seeking. - if (!drflac_oggbs__seek_to_next_frame(oggbs)) { - return DR_FALSE; - } -#endif } - - assert(firstSampleInFrame <= sample); - - if (!drflac__decode_frame(pFlac)) { - return DR_FALSE; - } - - size_t samplesToDecode = (size_t)(sample - firstSampleInFrame); // <-- Safe cast because the maximum number of samples in a frame is 65535. - return drflac_read_s32(pFlac, samplesToDecode, NULL) == samplesToDecode; } -dr_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD) +drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed) { // Pre: The bit stream should be sitting just past the 4-byte OggS capture pattern. + (void)relaxed; pInit->container = drflac_container_ogg; pInit->oggFirstBytePos = 0; @@ -3360,88 +4304,85 @@ dr_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc on // any match the FLAC specification. Important to keep in mind that the stream may be multiplexed. drflac_ogg_page_header header; - uint32_t headerSize; - if (!drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &headerSize)) { - return DR_FALSE; + drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; + drflac_uint32 bytesRead = 0; + if (drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; } - pInit->runningFilePos = headerSize; + pInit->runningFilePos += bytesRead; - for (;;) - { + for (;;) { // Break if we're past the beginning of stream page. if ((header.headerType & 0x02) == 0) { - return DR_FALSE; + return DRFLAC_FALSE; } // Check if it's a FLAC header. int pageBodySize = drflac_ogg__get_page_body_size(&header); - if (pageBodySize == 51) // 51 = the lacing value of the FLAC header packet. - { + if (pageBodySize == 51) { // 51 = the lacing value of the FLAC header packet. // It could be a FLAC page... - uint32_t bytesRemainingInPage = pageBodySize; + drflac_uint32 bytesRemainingInPage = pageBodySize; - uint8_t packetType; + drflac_uint8 packetType; if (onRead(pUserData, &packetType, 1) != 1) { - return DR_FALSE; + return DRFLAC_FALSE; } bytesRemainingInPage -= 1; - if (packetType == 0x7F) - { + if (packetType == 0x7F) { // Increasingly more likely to be a FLAC page... - uint8_t sig[4]; + drflac_uint8 sig[4]; if (onRead(pUserData, sig, 4) != 4) { - return DR_FALSE; + return DRFLAC_FALSE; } bytesRemainingInPage -= 4; - if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') - { + if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') { // Almost certainly a FLAC page... - uint8_t mappingVersion[2]; + drflac_uint8 mappingVersion[2]; if (onRead(pUserData, mappingVersion, 2) != 2) { - return DR_FALSE; + return DRFLAC_FALSE; } if (mappingVersion[0] != 1) { - return DR_FALSE; // Only supporting version 1.x of the Ogg mapping. + return DRFLAC_FALSE; // Only supporting version 1.x of the Ogg mapping. } // The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to // be handling it in a generic way based on the serial number and packet types. if (!onSeek(pUserData, 2, drflac_seek_origin_current)) { - return DR_FALSE; + return DRFLAC_FALSE; } // Expecting the native FLAC signature "fLaC". if (onRead(pUserData, sig, 4) != 4) { - return DR_FALSE; + return DRFLAC_FALSE; } - if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C') - { + if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C') { // The remaining data in the page should be the STREAMINFO block. - uint8_t isLastBlock; - uint8_t blockType; - uint32_t blockSize; + drflac_uint8 isLastBlock; + drflac_uint8 blockType; + drflac_uint32 blockSize; if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) { - return DR_FALSE; + return DRFLAC_FALSE; } if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { - return DR_FALSE; // Invalid block type. First block must be the STREAMINFO block. + return DRFLAC_FALSE; // Invalid block type. First block must be the STREAMINFO block. } drflac_streaminfo streaminfo; - if (drflac__read_streaminfo(onRead, pUserData, &streaminfo)) - { + if (drflac__read_streaminfo(onRead, pUserData, &streaminfo)) { // Success! - pInit->sampleRate = streaminfo.sampleRate; - pInit->channels = streaminfo.channels; - pInit->bitsPerSample = streaminfo.bitsPerSample; - pInit->totalSampleCount = streaminfo.totalSampleCount; - pInit->maxBlockSize = streaminfo.maxBlockSize; + pInit->hasStreamInfoBlock = DRFLAC_TRUE; + pInit->sampleRate = streaminfo.sampleRate; + pInit->channels = streaminfo.channels; + pInit->bitsPerSample = streaminfo.bitsPerSample; + pInit->totalSampleCount = streaminfo.totalSampleCount; + pInit->maxBlockSize = streaminfo.maxBlockSize; + pInit->hasMetadataBlocks = !isLastBlock; if (onMeta) { drflac_metadata metadata; @@ -3457,39 +4398,29 @@ dr_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc on pInit->oggSerial = header.serialNumber; pInit->oggBosHeader = header; break; - } - else - { + } else { // Failed to read STREAMINFO block. Aww, so close... - return DR_FALSE; + return DRFLAC_FALSE; } - } - else - { + } else { // Invalid file. - return DR_FALSE; + return DRFLAC_FALSE; } - } - else - { + } else { // Not a FLAC header. Skip it. if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) { - return DR_FALSE; + return DRFLAC_FALSE; } } - } - else - { + } else { // Not a FLAC header. Seek past the entire page and move on to the next. if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) { - return DR_FALSE; + return DRFLAC_FALSE; } } - } - else - { + } else { if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) { - return DR_FALSE; + return DRFLAC_FALSE; } } @@ -3497,85 +4428,153 @@ dr_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc on // Read the header of the next page. - if (!drflac_ogg__read_page_header(onRead, pUserData, &header, &headerSize)) { - return DR_FALSE; + if (drflac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; } - pInit->runningFilePos += headerSize; + pInit->runningFilePos += bytesRead; } // If we get here it means we found a FLAC audio stream. We should be sitting on the first byte of the header of the next page. The next // packets in the FLAC logical stream contain the metadata. The only thing left to do in the initialiation phase for Ogg is to create the // Ogg bistream object. - pInit->hasMetadataBlocks = DR_TRUE; // <-- Always have at least VORBIS_COMMENT metadata block. - return DR_TRUE; + pInit->hasMetadataBlocks = DRFLAC_TRUE; // <-- Always have at least VORBIS_COMMENT metadata block. + return DRFLAC_TRUE; } #endif -dr_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD) +drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD) { if (pInit == NULL || onRead == NULL || onSeek == NULL) { - return DR_FALSE; + return DRFLAC_FALSE; } - pInit->onRead = onRead; - pInit->onSeek = onSeek; - pInit->onMeta = onMeta; - pInit->pUserData = pUserData; - pInit->pUserDataMD = pUserDataMD; + drflac_zero_memory(pInit, sizeof(*pInit)); + pInit->onRead = onRead; + pInit->onSeek = onSeek; + pInit->onMeta = onMeta; + pInit->container = container; + pInit->pUserData = pUserData; + pInit->pUserDataMD = pUserDataMD; - uint8_t id[4]; - if (onRead(pUserData, id, 4) != 4) { - return DR_FALSE; + pInit->bs.onRead = onRead; + pInit->bs.onSeek = onSeek; + pInit->bs.pUserData = pUserData; + drflac__reset_cache(&pInit->bs); + + + // If the container is explicitly defined then we can try opening in relaxed mode. + drflac_bool32 relaxed = container != drflac_container_unknown; + + drflac_uint8 id[4]; + + // Skip over any ID3 tags. + for (;;) { + if (onRead(pUserData, id, 4) != 4) { + return DRFLAC_FALSE; // Ran out of data. + } + pInit->runningFilePos += 4; + + if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') { + drflac_uint8 header[6]; + if (onRead(pUserData, header, 6) != 6) { + return DRFLAC_FALSE; // Ran out of data. + } + pInit->runningFilePos += 6; + + drflac_uint8 flags = header[1]; + drflac_uint32 headerSize; + drflac_copy_memory(&headerSize, header+2, 4); + headerSize = drflac__unsynchsafe_32(drflac__be2host_32(headerSize)); + if (flags & 0x10) { + headerSize += 10; + } + + if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) { + return DRFLAC_FALSE; // Failed to seek past the tag. + } + pInit->runningFilePos += headerSize; + } else { + break; + } } if (id[0] == 'f' && id[1] == 'L' && id[2] == 'a' && id[3] == 'C') { - return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD); + return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); } - #ifndef DR_FLAC_NO_OGG if (id[0] == 'O' && id[1] == 'g' && id[2] == 'g' && id[3] == 'S') { - return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD); + return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); } #endif + // If we get here it means we likely don't have a header. Try opening in relaxed mode, if applicable. + if (relaxed) { + if (container == drflac_container_native) { + return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + } +#ifndef DR_FLAC_NO_OGG + if (container == drflac_container_ogg) { + return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + } +#endif + } + // Unsupported container. - return DR_FALSE; + return DRFLAC_FALSE; } void drflac__init_from_info(drflac* pFlac, drflac_init_info* pInit) { - assert(pFlac != NULL); - assert(pInit != NULL); - - memset(pFlac, 0, sizeof(*pFlac)); - pFlac->bs.onRead = pInit->onRead; - pFlac->bs.onSeek = pInit->onSeek; - pFlac->bs.pUserData = pInit->pUserData; - pFlac->bs.nextL2Line = sizeof(pFlac->bs.cacheL2) / sizeof(pFlac->bs.cacheL2[0]); // <-- Initialize to this to force a client-side data retrieval right from the start. - pFlac->bs.consumedBits = sizeof(pFlac->bs.cache)*8; + drflac_assert(pFlac != NULL); + drflac_assert(pInit != NULL); + drflac_zero_memory(pFlac, sizeof(*pFlac)); + pFlac->bs = pInit->bs; pFlac->onMeta = pInit->onMeta; pFlac->pUserDataMD = pInit->pUserDataMD; pFlac->maxBlockSize = pInit->maxBlockSize; pFlac->sampleRate = pInit->sampleRate; - pFlac->channels = (uint8_t)pInit->channels; - pFlac->bitsPerSample = (uint8_t)pInit->bitsPerSample; + pFlac->channels = (drflac_uint8)pInit->channels; + pFlac->bitsPerSample = (drflac_uint8)pInit->bitsPerSample; pFlac->totalSampleCount = pInit->totalSampleCount; pFlac->container = pInit->container; } -drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD) +drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD) { +#ifndef DRFLAC_NO_CPUID + // CPU support first. + drflac__init_cpu_caps(); +#endif + drflac_init_info init; - if (!drflac__init_private(&init, onRead, onSeek, onMeta, pUserData, pUserDataMD)) { + if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) { return NULL; } - size_t allocationSize = sizeof(drflac); - allocationSize += init.maxBlockSize * init.channels * sizeof(int32_t); - //allocationSize += init.seektableSize; + // The size of the allocation for the drflac object needs to be large enough to fit the following: + // 1) The main members of the drflac structure + // 2) A block of memory large enough to store the decoded samples of the largest frame in the stream + // 3) If the container is Ogg, a drflac_oggbs object + // + // The complicated part of the allocation is making sure there's enough room the decoded samples, taking into consideration + // the different SIMD instruction sets. + drflac_uint32 allocationSize = sizeof(drflac); + // The allocation size for decoded frames depends on the number of 32-bit integers that fit inside the largest SIMD vector + // we are supporting. + drflac_uint32 wholeSIMDVectorCountPerChannel; + if ((init.maxBlockSize % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) { + wholeSIMDVectorCountPerChannel = (init.maxBlockSize / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))); + } else { + wholeSIMDVectorCountPerChannel = (init.maxBlockSize / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1; + } + + drflac_uint32 decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels; + + allocationSize += decodedSamplesAllocationSize; + allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE; // Allocate extra bytes to ensure we have enough for alignment. #ifndef DR_FLAC_NO_OGG // There's additional data required for Ogg streams. @@ -3584,13 +4583,13 @@ drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_p } #endif - drflac* pFlac = (drflac*)malloc(allocationSize); + drflac* pFlac = (drflac*)DRFLAC_MALLOC(allocationSize); drflac__init_from_info(pFlac, &init); - pFlac->pDecodedSamples = (int32_t*)pFlac->pExtraData; + pFlac->pDecodedSamples = (drflac_int32*)drflac_align((size_t)pFlac->pExtraData, DRFLAC_MAX_SIMD_VECTOR_SIZE); #ifndef DR_FLAC_NO_OGG if (init.container == drflac_container_ogg) { - drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + init.maxBlockSize*init.channels); + drflac_oggbs* oggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); oggbs->onRead = onRead; oggbs->onSeek = onSeek; oggbs->pUserData = pUserData; @@ -3604,17 +4603,42 @@ drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_p pFlac->bs.onRead = drflac__on_read_ogg; pFlac->bs.onSeek = drflac__on_seek_ogg; pFlac->bs.pUserData = (void*)oggbs; + pFlac->_oggbs = (void*)oggbs; } #endif // Decode metadata before returning. if (init.hasMetadataBlocks) { if (!drflac__read_and_decode_metadata(pFlac)) { - free(pFlac); + DRFLAC_FREE(pFlac); return NULL; } } + // If we get here, but don't have a STREAMINFO block, it means we've opened the stream in relaxed mode and need to decode + // the first frame. + if (!init.hasStreamInfoBlock) { + pFlac->currentFrame.header = init.firstFrameHeader; + do + { + drflac_result result = drflac__decode_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + break; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { + DRFLAC_FREE(pFlac); + return NULL; + } + continue; + } else { + DRFLAC_FREE(pFlac); + return NULL; + } + } + } while (1); + } + return pFlac; } @@ -3631,9 +4655,9 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData); } -static dr_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) +static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) { - assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); + drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } @@ -3662,9 +4686,14 @@ static void drflac__close_file_handle(drflac_file file) #else #include +// This doesn't seem to be defined for VC6. +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) { - assert(bytesToRead < 0xFFFFFFFF); // dr_flac will never request huge amounts of data at a time. This is a safe assertion. + drflac_assert(bytesToRead < 0xFFFFFFFF); // dr_flac will never request huge amounts of data at a time. This is a safe assertion. DWORD bytesRead; ReadFile((HANDLE)pUserData, bufferOut, (DWORD)bytesToRead, &bytesRead, NULL); @@ -3672,9 +4701,9 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt return (size_t)bytesRead; } -static dr_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) +static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) { - assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); + drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); return SetFilePointer((HANDLE)pUserData, offset, NULL, (origin == drflac_seek_origin_current) ? FILE_CURRENT : FILE_BEGIN) != INVALID_SET_FILE_POINTER; } @@ -3719,7 +4748,7 @@ drflac* drflac_open_file_with_metadata(const char* filename, drflac_meta_proc on return NULL; } - drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, (void*)file, pUserData); + drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)file, pUserData); if (pFlac == NULL) { drflac__close_file_handle(file); return pFlac; @@ -3732,8 +4761,8 @@ drflac* drflac_open_file_with_metadata(const char* filename, drflac_meta_proc on static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead) { drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; - assert(memoryStream != NULL); - assert(memoryStream->dataSize >= memoryStream->currentReadPos); + drflac_assert(memoryStream != NULL); + drflac_assert(memoryStream->dataSize >= memoryStream->currentReadPos); size_t bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos; if (bytesToRead > bytesRemaining) { @@ -3741,18 +4770,18 @@ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t by } if (bytesToRead > 0) { - memcpy(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead); + drflac_copy_memory(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead); memoryStream->currentReadPos += bytesToRead; } return bytesToRead; } -static dr_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin) +static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin) { drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; - assert(memoryStream != NULL); - assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); + drflac_assert(memoryStream != NULL); + drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); if (origin == drflac_seek_origin_current) { if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { @@ -3761,14 +4790,14 @@ static dr_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward. } } else { - if ((uint32_t)offset <= memoryStream->dataSize) { + if ((drflac_uint32)offset <= memoryStream->dataSize) { memoryStream->currentReadPos = offset; } else { memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward. } } - return DR_TRUE; + return DRFLAC_TRUE; } drflac* drflac_open_memory(const void* data, size_t dataSize) @@ -3788,7 +4817,7 @@ drflac* drflac_open_memory(const void* data, size_t dataSize) #ifndef DR_FLAC_NO_OGG if (pFlac->container == drflac_container_ogg) { - drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + pFlac->maxBlockSize*pFlac->channels); + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; oggbs->pUserData = &pFlac->memoryStream; } else @@ -3806,7 +4835,7 @@ drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drfl memoryStream.data = (const unsigned char*)data; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, &memoryStream, pUserData); + drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData); if (pFlac == NULL) { return NULL; } @@ -3817,7 +4846,7 @@ drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drfl #ifndef DR_FLAC_NO_OGG if (pFlac->container == drflac_container_ogg) { - drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + pFlac->maxBlockSize*pFlac->channels); + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; oggbs->pUserData = &pFlac->memoryStream; } else @@ -3833,12 +4862,20 @@ drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drfl drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData) { - return drflac_open_with_metadata_private(onRead, onSeek, NULL, pUserData, pUserData); + return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData); +} +drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData) +{ + return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData); } drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData) { - return drflac_open_with_metadata_private(onRead, onSeek, onMeta, pUserData, pUserData); + return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData); +} +drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData) +{ + return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData); } void drflac_close(drflac* pFlac) @@ -3857,8 +4894,8 @@ void drflac_close(drflac* pFlac) #ifndef DR_FLAC_NO_OGG // Need to clean up Ogg streams a bit differently due to the way the bit streaming is chained. if (pFlac->container == drflac_container_ogg) { - assert(pFlac->bs.onRead == drflac__on_read_ogg); - drflac_oggbs* oggbs = (drflac_oggbs*)((int32_t*)pFlac->pExtraData + pFlac->maxBlockSize*pFlac->channels); + drflac_assert(pFlac->bs.onRead == drflac__on_read_ogg); + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; if (oggbs->onRead == drflac__on_read_stdio) { drflac__close_file_handle((drflac_file)oggbs->pUserData); } @@ -3866,26 +4903,25 @@ void drflac_close(drflac* pFlac) #endif #endif - free(pFlac); + DRFLAC_FREE(pFlac); } -uint64_t drflac__read_s32__misaligned(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferOut) +drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int32* bufferOut) { unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); // We should never be calling this when the number of samples to read is >= the sample count. - assert(samplesToRead < channelCount); - assert(pFlac->currentFrame.samplesRemaining > 0 && samplesToRead <= pFlac->currentFrame.samplesRemaining); + drflac_assert(samplesToRead < channelCount); + drflac_assert(pFlac->currentFrame.samplesRemaining > 0 && samplesToRead <= pFlac->currentFrame.samplesRemaining); - uint64_t samplesRead = 0; - while (samplesToRead > 0) - { - uint64_t totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount; - uint64_t samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining; - unsigned int channelIndex = samplesReadFromFrameSoFar % channelCount; + drflac_uint64 samplesRead = 0; + while (samplesToRead > 0) { + drflac_uint64 totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount; + drflac_uint64 samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining; + drflac_uint64 channelIndex = samplesReadFromFrameSoFar % channelCount; - uint64_t nextSampleInFrame = samplesReadFromFrameSoFar / channelCount; + drflac_uint64 nextSampleInFrame = samplesReadFromFrameSoFar / channelCount; int decodedSample = 0; switch (pFlac->currentFrame.header.channelAssignment) @@ -3899,7 +4935,6 @@ uint64_t drflac__read_s32__misaligned(drflac* pFlac, uint64_t samplesToRead, int int left = pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame]; decodedSample = left - side; } - } break; case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: @@ -3911,7 +4946,6 @@ uint64_t drflac__read_s32__misaligned(drflac* pFlac, uint64_t samplesToRead, int } else { decodedSample = pFlac->currentFrame.subframes[channelIndex].pDecodedSamples[nextSampleInFrame]; } - } break; case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: @@ -3931,7 +4965,6 @@ uint64_t drflac__read_s32__misaligned(drflac* pFlac, uint64_t samplesToRead, int mid = (((unsigned int)mid) << 1) | (side & 0x01); decodedSample = (mid - side) >> 1; } - } break; case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: @@ -3956,19 +4989,15 @@ uint64_t drflac__read_s32__misaligned(drflac* pFlac, uint64_t samplesToRead, int return samplesRead; } -uint64_t drflac__seek_forward_by_samples(drflac* pFlac, uint64_t samplesToRead) +drflac_uint64 drflac__seek_forward_by_samples(drflac* pFlac, drflac_uint64 samplesToRead) { - uint64_t samplesRead = 0; - while (samplesToRead > 0) - { - if (pFlac->currentFrame.samplesRemaining == 0) - { + drflac_uint64 samplesRead = 0; + while (samplesToRead > 0) { + if (pFlac->currentFrame.samplesRemaining == 0) { if (!drflac__read_and_decode_next_frame(pFlac)) { break; // Couldn't read the next frame, so just break from the loop and return. } - } - else - { + } else { samplesRead += 1; pFlac->currentFrame.samplesRemaining -= 1; samplesToRead -= 1; @@ -3978,7 +5007,7 @@ uint64_t drflac__seek_forward_by_samples(drflac* pFlac, uint64_t samplesToRead) return samplesRead; } -uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferOut) +drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int32* bufferOut) { // Note that is allowed to be null, in which case this will be treated as something like a seek. if (pFlac == NULL || samplesToRead == 0) { @@ -3990,27 +5019,23 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferO } - uint64_t samplesRead = 0; - while (samplesToRead > 0) - { + drflac_uint64 samplesRead = 0; + while (samplesToRead > 0) { // If we've run out of samples in this frame, go to the next. - if (pFlac->currentFrame.samplesRemaining == 0) - { + if (pFlac->currentFrame.samplesRemaining == 0) { if (!drflac__read_and_decode_next_frame(pFlac)) { break; // Couldn't read the next frame, so just break from the loop and return. } - } - else - { + } else { // Here is where we grab the samples and interleave them. unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); - uint64_t totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount; - uint64_t samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining; + drflac_uint64 totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount; + drflac_uint64 samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining; - int misalignedSampleCount = samplesReadFromFrameSoFar % channelCount; + drflac_uint64 misalignedSampleCount = samplesReadFromFrameSoFar % channelCount; if (misalignedSampleCount > 0) { - uint64_t misalignedSamplesRead = drflac__read_s32__misaligned(pFlac, misalignedSampleCount, bufferOut); + drflac_uint64 misalignedSamplesRead = drflac__read_s32__misaligned(pFlac, misalignedSampleCount, bufferOut); samplesRead += misalignedSamplesRead; samplesReadFromFrameSoFar += misalignedSamplesRead; bufferOut += misalignedSamplesRead; @@ -4018,22 +5043,22 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferO } - uint64_t alignedSampleCountPerChannel = samplesToRead / channelCount; + drflac_uint64 alignedSampleCountPerChannel = samplesToRead / channelCount; if (alignedSampleCountPerChannel > pFlac->currentFrame.samplesRemaining / channelCount) { alignedSampleCountPerChannel = pFlac->currentFrame.samplesRemaining / channelCount; } - uint64_t firstAlignedSampleInFrame = samplesReadFromFrameSoFar / channelCount; + drflac_uint64 firstAlignedSampleInFrame = samplesReadFromFrameSoFar / channelCount; unsigned int unusedBitsPerSample = 32 - pFlac->bitsPerSample; switch (pFlac->currentFrame.header.channelAssignment) { case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: { - const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; - const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; + const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; - for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) { + for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { int left = pDecodedSamples0[i]; int side = pDecodedSamples1[i]; int right = left - side; @@ -4045,10 +5070,10 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferO case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: { - const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; - const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; + const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; - for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) { + for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { int side = pDecodedSamples0[i]; int right = pDecodedSamples1[i]; int left = right + side; @@ -4060,12 +5085,12 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferO case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: { - const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; - const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; + const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; - for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) { + for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { int side = pDecodedSamples1[i]; - int mid = (((uint32_t)pDecodedSamples0[i]) << 1) | (side & 0x01); + int mid = (((drflac_uint32)pDecodedSamples0[i]) << 1) | (side & 0x01); bufferOut[i*2+0] = ((mid + side) >> 1) << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); bufferOut[i*2+1] = ((mid - side) >> 1) << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); @@ -4078,10 +5103,10 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferO if (pFlac->currentFrame.header.channelAssignment == 1) // 1 = Stereo { // Stereo optimized inner loop unroll. - const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; - const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; + const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; - for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) { + for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { bufferOut[i*2+0] = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); bufferOut[i*2+1] = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); } @@ -4089,7 +5114,7 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferO else { // Generic interleaving. - for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) { + for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { for (unsigned int j = 0; j < channelCount; ++j) { bufferOut[(i*channelCount)+j] = (pFlac->currentFrame.subframes[j].pDecodedSamples[firstAlignedSampleInFrame + i]) << (unusedBitsPerSample + pFlac->currentFrame.subframes[j].wastedBitsPerSample); } @@ -4098,7 +5123,7 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferO } break; } - uint64_t alignedSamplesRead = alignedSampleCountPerChannel * channelCount; + drflac_uint64 alignedSamplesRead = alignedSampleCountPerChannel * channelCount; samplesRead += alignedSamplesRead; samplesReadFromFrameSoFar += alignedSamplesRead; bufferOut += alignedSamplesRead; @@ -4108,9 +5133,8 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferO // At this point we may still have some excess samples left to read. - if (samplesToRead > 0 && pFlac->currentFrame.samplesRemaining > 0) - { - uint64_t excessSamplesRead = 0; + if (samplesToRead > 0 && pFlac->currentFrame.samplesRemaining > 0) { + drflac_uint64 excessSamplesRead = 0; if (samplesToRead < pFlac->currentFrame.samplesRemaining) { excessSamplesRead = drflac__read_s32__misaligned(pFlac, samplesToRead, bufferOut); } else { @@ -4128,35 +5152,66 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferO return samplesRead; } -uint64_t drflac_read_s16(drflac* pFlac, uint64_t samplesToRead, int16_t* pBufferOut) +drflac_uint64 drflac_read_s16(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int16* pBufferOut) { // This reads samples in 2 passes and can probably be optimized. - uint64_t samplesRead = 0; + drflac_uint64 totalSamplesRead = 0; while (samplesToRead > 0) { - int32_t samples32[4096]; - uint64_t samplesJustRead = drflac_read_s32(pFlac, samplesToRead > 4096 ? 4096 : samplesToRead, samples32); + drflac_int32 samples32[4096]; + drflac_uint64 samplesJustRead = drflac_read_s32(pFlac, (samplesToRead > 4096) ? 4096 : samplesToRead, samples32); if (samplesJustRead == 0) { break; // Reached the end. } // s32 -> s16 - for (uint64_t i = 0; i < samplesJustRead; ++i) { - pBufferOut[i] = (int16_t)(samples32[i] >> 16); + for (drflac_uint64 i = 0; i < samplesJustRead; ++i) { + pBufferOut[i] = (drflac_int16)(samples32[i] >> 16); } - samplesRead += samplesJustRead; + totalSamplesRead += samplesJustRead; samplesToRead -= samplesJustRead; pBufferOut += samplesJustRead; } - return samplesRead; + return totalSamplesRead; } -dr_bool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex) +drflac_uint64 drflac_read_f32(drflac* pFlac, drflac_uint64 samplesToRead, float* pBufferOut) +{ + // This reads samples in 2 passes and can probably be optimized. + drflac_uint64 totalSamplesRead = 0; + + while (samplesToRead > 0) { + drflac_int32 samples32[4096]; + drflac_uint64 samplesJustRead = drflac_read_s32(pFlac, (samplesToRead > 4096) ? 4096 : samplesToRead, samples32); + if (samplesJustRead == 0) { + break; // Reached the end. + } + + // s32 -> f32 + for (drflac_uint64 i = 0; i < samplesJustRead; ++i) { + pBufferOut[i] = (float)(samples32[i] / 2147483648.0); + } + + totalSamplesRead += samplesJustRead; + samplesToRead -= samplesJustRead; + pBufferOut += samplesJustRead; + } + + return totalSamplesRead; +} + +drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex) { if (pFlac == NULL) { - return DR_FALSE; + return DRFLAC_FALSE; + } + + // If we don't know where the first frame begins then we can't seek. This will happen when the STREAMINFO block was not present + // when the decoder was opened. + if (pFlac->firstFramePos == 0) { + return DRFLAC_FALSE; } if (sampleIndex == 0) { @@ -4186,156 +5241,91 @@ dr_bool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex) } - return DR_TRUE; + return DRFLAC_TRUE; } //// High Level APIs //// -int32_t* drflac__full_decode_and_close_s32(drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, uint64_t* totalSampleCountOut) -{ - assert(pFlac != NULL); +// I couldn't figure out where SIZE_MAX was defined for VC6. If anybody knows, let me know. +#if defined(_MSC_VER) && _MSC_VER <= 1200 +#ifdef DRFLAC_64BIT +#define SIZE_MAX ((drflac_uint64)0xFFFFFFFFFFFFFFFF) +#else +#define SIZE_MAX 0xFFFFFFFF +#endif +#endif - int32_t* pSampleData = NULL; - uint64_t totalSampleCount = pFlac->totalSampleCount; - - if (totalSampleCount == 0) - { - int32_t buffer[4096]; - - size_t sampleDataBufferSize = sizeof(buffer); - pSampleData = (int32_t*)malloc(sampleDataBufferSize); - if (pSampleData == NULL) { - goto on_error; - } - - uint64_t samplesRead; - while ((samplesRead = (uint64_t)drflac_read_s32(pFlac, sizeof(buffer)/sizeof(buffer[0]), buffer)) > 0) - { - if (((totalSampleCount + samplesRead) * sizeof(int32_t)) > sampleDataBufferSize) { - sampleDataBufferSize *= 2; - int32_t* pNewSampleData = (int32_t*)realloc(pSampleData, sampleDataBufferSize); - if (pNewSampleData == NULL) { - free(pSampleData); - goto on_error; - } - - pSampleData = pNewSampleData; - } - - memcpy(pSampleData + totalSampleCount, buffer, (size_t)(samplesRead*sizeof(int32_t))); - totalSampleCount += samplesRead; - } - - // At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to - // protect those ears from random noise! - memset(pSampleData + totalSampleCount, 0, (size_t)(sampleDataBufferSize - totalSampleCount*sizeof(int32_t))); - } - else - { - uint64_t dataSize = totalSampleCount * sizeof(int32_t); - if (dataSize > SIZE_MAX) { - goto on_error; // The decoded data is too big. - } - - pSampleData = (int32_t*)malloc((size_t)dataSize); // <-- Safe cast as per the check above. - if (pSampleData == NULL) { - goto on_error; - } - - uint64_t samplesDecoded = drflac_read_s32(pFlac, pFlac->totalSampleCount, pSampleData); - if (samplesDecoded != pFlac->totalSampleCount) { - free(pSampleData); - goto on_error; // Something went wrong when decoding the FLAC stream. - } - } - - - if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; - if (channelsOut) *channelsOut = pFlac->channels; - if (totalSampleCountOut) *totalSampleCountOut = totalSampleCount; - - drflac_close(pFlac); - return pSampleData; - -on_error: - drflac_close(pFlac); - return NULL; +// Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. +#define DRFLAC_DEFINE_FULL_DECODE_AND_CLOSE(extension, type) \ +static type* drflac__full_decode_and_close_ ## extension (drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalSampleCountOut)\ +{ \ + drflac_assert(pFlac != NULL); \ + \ + type* pSampleData = NULL; \ + drflac_uint64 totalSampleCount = pFlac->totalSampleCount; \ + \ + if (totalSampleCount == 0) { \ + type buffer[4096]; \ + \ + size_t sampleDataBufferSize = sizeof(buffer); \ + pSampleData = (type*)DRFLAC_MALLOC(sampleDataBufferSize); \ + if (pSampleData == NULL) { \ + goto on_error; \ + } \ + \ + drflac_uint64 samplesRead; \ + while ((samplesRead = (drflac_uint64)drflac_read_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0]), buffer)) > 0) { \ + if (((totalSampleCount + samplesRead) * sizeof(type)) > sampleDataBufferSize) { \ + sampleDataBufferSize *= 2; \ + type* pNewSampleData = (type*)DRFLAC_REALLOC(pSampleData, sampleDataBufferSize); \ + if (pNewSampleData == NULL) { \ + DRFLAC_FREE(pSampleData); \ + goto on_error; \ + } \ + \ + pSampleData = pNewSampleData; \ + } \ + \ + drflac_copy_memory(pSampleData + totalSampleCount, buffer, (size_t)(samplesRead*sizeof(type))); \ + totalSampleCount += samplesRead; \ + } \ + \ + /* At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to \ + protect those ears from random noise! */ \ + drflac_zero_memory(pSampleData + totalSampleCount, (size_t)(sampleDataBufferSize - totalSampleCount*sizeof(type))); \ + } else { \ + drflac_uint64 dataSize = totalSampleCount * sizeof(type); \ + if (dataSize > SIZE_MAX) { \ + goto on_error; /* The decoded data is too big. */ \ + } \ + \ + pSampleData = (type*)DRFLAC_MALLOC((size_t)dataSize); /* <-- Safe cast as per the check above. */ \ + if (pSampleData == NULL) { \ + goto on_error; \ + } \ + \ + totalSampleCount = drflac_read_##extension(pFlac, pFlac->totalSampleCount, pSampleData); \ + } \ + \ + if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; \ + if (channelsOut) *channelsOut = pFlac->channels; \ + if (totalSampleCountOut) *totalSampleCountOut = totalSampleCount; \ + \ + drflac_close(pFlac); \ + return pSampleData; \ + \ +on_error: \ + drflac_close(pFlac); \ + return NULL; \ } -int16_t* drflac__full_decode_and_close_s16(drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, uint64_t* totalSampleCountOut) -{ - assert(pFlac != NULL); +DRFLAC_DEFINE_FULL_DECODE_AND_CLOSE(s32, drflac_int32) +DRFLAC_DEFINE_FULL_DECODE_AND_CLOSE(s16, drflac_int16) +DRFLAC_DEFINE_FULL_DECODE_AND_CLOSE(f32, float) - int16_t* pSampleData = NULL; - uint64_t totalSampleCount = pFlac->totalSampleCount; - - if (totalSampleCount == 0) - { - int16_t buffer[4096]; - - size_t sampleDataBufferSize = sizeof(buffer); - pSampleData = (int16_t*)malloc(sampleDataBufferSize); - if (pSampleData == NULL) { - goto on_error; - } - - uint64_t samplesRead; - while ((samplesRead = (uint64_t)drflac_read_s16(pFlac, sizeof(buffer)/sizeof(buffer[0]), buffer)) > 0) - { - if (((totalSampleCount + samplesRead) * sizeof(int16_t)) > sampleDataBufferSize) { - sampleDataBufferSize *= 2; - int16_t* pNewSampleData = (int16_t*)realloc(pSampleData, sampleDataBufferSize); - if (pNewSampleData == NULL) { - free(pSampleData); - goto on_error; - } - - pSampleData = pNewSampleData; - } - - memcpy(pSampleData + totalSampleCount, buffer, (size_t)(samplesRead*sizeof(int16_t))); - totalSampleCount += samplesRead; - } - - // At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to - // protect those ears from random noise! - memset(pSampleData + totalSampleCount, 0, (size_t)(sampleDataBufferSize - totalSampleCount*sizeof(int16_t))); - } - else - { - uint64_t dataSize = totalSampleCount * sizeof(int16_t); - if (dataSize > SIZE_MAX) { - goto on_error; // The decoded data is too big. - } - - pSampleData = (int16_t*)malloc((size_t)dataSize); // <-- Safe cast as per the check above. - if (pSampleData == NULL) { - goto on_error; - } - - uint64_t samplesDecoded = drflac_read_s16(pFlac, pFlac->totalSampleCount, pSampleData); - if (samplesDecoded != pFlac->totalSampleCount) { - free(pSampleData); - goto on_error; // Something went wrong when decoding the FLAC stream. - } - } - - - if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; - if (channelsOut) *channelsOut = pFlac->channels; - if (totalSampleCountOut) *totalSampleCountOut = totalSampleCount; - - drflac_close(pFlac); - return pSampleData; - -on_error: - drflac_close(pFlac); - return NULL; -} - -int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount) +drflac_int32* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) { // Safety. if (sampleRate) *sampleRate = 0; @@ -4350,7 +5340,7 @@ int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc on return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount); } -int16_t* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount) +drflac_int16* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) { // Safety. if (sampleRate) *sampleRate = 0; @@ -4365,8 +5355,23 @@ int16_t* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc on return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount); } +float* drflac_open_and_decode_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +{ + // Safety. + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drflac* pFlac = drflac_open(onRead, onSeek, pUserData); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_decode_and_close_f32(pFlac, channels, sampleRate, totalSampleCount); +} + #ifndef DR_FLAC_NO_STDIO -int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount) +drflac_int32* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) { if (sampleRate) *sampleRate = 0; if (channels) *channels = 0; @@ -4380,7 +5385,7 @@ int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* cha return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount); } -int16_t* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount) +drflac_int16* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) { if (sampleRate) *sampleRate = 0; if (channels) *channels = 0; @@ -4393,9 +5398,23 @@ int16_t* drflac_open_and_decode_file_s16(const char* filename, unsigned int* cha return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount); } + +float* drflac_open_and_decode_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +{ + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drflac* pFlac = drflac_open_file(filename); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_decode_and_close_f32(pFlac, channels, sampleRate, totalSampleCount); +} #endif -int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount) +drflac_int32* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) { if (sampleRate) *sampleRate = 0; if (channels) *channels = 0; @@ -4409,7 +5428,7 @@ int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, un return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount); } -int16_t* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount) +drflac_int16* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) { if (sampleRate) *sampleRate = 0; if (channels) *channels = 0; @@ -4423,15 +5442,29 @@ int16_t* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, un return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount); } +float* drflac_open_and_decode_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +{ + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drflac* pFlac = drflac_open_memory(data, dataSize); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_decode_and_close_f32(pFlac, channels, sampleRate, totalSampleCount); +} + void drflac_free(void* pSampleDataReturnedByOpenAndDecode) { - free(pSampleDataReturnedByOpenAndDecode); + DRFLAC_FREE(pSampleDataReturnedByOpenAndDecode); } -void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, uint32_t commentCount, const char* pComments) +void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const char* pComments) { if (pIter == NULL) { return; @@ -4441,7 +5474,7 @@ void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, pIter->pRunningData = pComments; } -const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, uint32_t* pCommentLengthOut) +const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut) { // Safety. if (pCommentLengthOut) *pCommentLengthOut = 0; @@ -4450,7 +5483,7 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, ui return NULL; } - uint32_t length = drflac__le2host_32(*(uint32_t*)pIter->pRunningData); + drflac_uint32 length = drflac__le2host_32(*(drflac_uint32*)pIter->pRunningData); pIter->pRunningData += 4; const char* pComment = pIter->pRunningData; @@ -4465,20 +5498,63 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, ui // REVISION HISTORY // +// v0.8d - 2017-09-22 +// - Add support for decoding streams with ID3 tags. ID3 tags are just skipped. +// +// v0.8c - 2017-09-07 +// - Fix warning on non-x86/x64 architectures. +// +// v0.8b - 2017-08-19 +// - Fix build on non-x86/x64 architectures. +// +// v0.8a - 2017-08-13 +// - A small optimization for the Clang build. +// +// v0.8 - 2017-08-12 +// - API CHANGE: Rename dr_* types to drflac_*. +// - Optimizations. This brings dr_flac back to about the same class of efficiency as the reference implementation. +// - Add support for custom implementations of malloc(), realloc(), etc. +// - Add CRC checking to Ogg encapsulated streams. +// - Fix VC++ 6 build. This is only for the C++ compiler. The C compiler is not currently supported. +// - Bug fixes. +// +// v0.7 - 2017-07-23 +// - Add support for opening a stream without a header block. To do this, use drflac_open_relaxed() / drflac_open_with_metadata_relaxed(). +// +// v0.6 - 2017-07-22 +// - Add support for recovering from invalid frames. With this change, dr_flac will simply skip over invalid frames as if they +// never existed. Frames are checked against their sync code, the CRC-8 of the frame header and the CRC-16 of the whole frame. +// +// v0.5 - 2017-07-16 +// - Fix typos. +// - Change drflac_bool* types to unsigned. +// - Add CRC checking. This makes dr_flac slower, but can be disabled with #define DR_FLAC_NO_CRC. +// +// v0.4f - 2017-03-10 +// - Fix a couple of bugs with the bitstreaming code. +// +// v0.4e - 2017-02-17 +// - Fix some warnings. +// +// v0.4d - 2016-12-26 +// - Add support for 32-bit floating-point PCM decoding. +// - Use drflac_int*/drflac_uint* sized types to improve compiler support. +// - Minor improvements to documentation. +// // v0.4c - 2016-12-26 // - Add support for signed 16-bit integer PCM decoding. // // v0.4b - 2016-10-23 -// - A minor change to dr_bool8 and dr_bool32 types. +// - A minor change to drflac_bool8 and drflac_bool32 types. // // v0.4a - 2016-10-11 -// - Rename drBool32 to dr_bool32 for styling consistency. +// - Rename drBool32 to drflac_bool32 for styling consistency. // // v0.4 - 2016-09-29 // - API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type. -// - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32() +// - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32(). // - API CHANGE: Swap the order of "channels" and "sampleRate" parameters in drflac_open_and_decode*(). Rationale for this is to -// keep it consistent with dr_audio. +// keep it consistent with drflac_audio. // // v0.3f - 2016-09-21 // - Fix a warning with GCC. @@ -4531,11 +5607,6 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, ui // - Initial versioned release. -// TODO -// - Add support for initializing the decoder without a header STREAMINFO block. -// - Test CUESHEET metadata blocks. - - /* This is free and unencumbered software released into the public domain. diff --git a/src/external/dr_wav.h b/src/external/dr_wav.h new file mode 100644 index 00000000..536df8f3 --- /dev/null +++ b/src/external/dr_wav.h @@ -0,0 +1,3455 @@ +// WAV audio loader and writer. Public domain. See "unlicense" statement at the end of this file. +// dr_wav - v0.7a - 2017-11-17 +// +// David Reid - mackron@gmail.com + +// USAGE +// +// This is a single-file library. To use it, do something like the following in one .c file. +// #define DR_WAV_IMPLEMENTATION +// #include "dr_wav.h" +// +// You can then #include this file in other parts of the program as you would with any other header file. Do something +// like the following to read audio data: +// +// drwav wav; +// if (!drwav_init_file(&wav, "my_song.wav")) { +// // Error opening WAV file. +// } +// +// drwav_int32* pDecodedInterleavedSamples = malloc(wav.totalSampleCount * sizeof(drwav_int32)); +// size_t numberOfSamplesActuallyDecoded = drwav_read_s32(&wav, wav.totalSampleCount, pDecodedInterleavedSamples); +// +// ... +// +// drwav_uninit(&wav); +// +// You can also use drwav_open() to allocate and initialize the loader for you: +// +// drwav* pWav = drwav_open_file("my_song.wav"); +// if (pWav == NULL) { +// // Error opening WAV file. +// } +// +// ... +// +// drwav_close(pWav); +// +// If you just want to quickly open and read the audio data in a single operation you can do something like this: +// +// unsigned int channels; +// unsigned int sampleRate; +// drwav_uint64 totalSampleCount; +// float* pSampleData = drwav_open_and_read_file_s32("my_song.wav", &channels, &sampleRate, &totalSampleCount); +// if (pSampleData == NULL) { +// // Error opening and reading WAV file. +// } +// +// ... +// +// drwav_free(pSampleData); +// +// The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in +// this case), but you can still output the audio data in it's internal format (see notes below for supported formats): +// +// size_t samplesRead = drwav_read(&wav, wav.totalSampleCount, pDecodedInterleavedSamples); +// +// You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for +// a particular data format: +// +// size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer); +// +// +// dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work +// without any manual intervention. +// +// +// dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at +// drwav_open_write(), drwav_open_file_write(), etc. Use drwav_write() to write samples, or drwav_write_raw() to write +// raw data in the "data" chunk. +// +// drwav_data_format format; +// format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64. +// format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes. +// format.channels = 2; +// format.sampleRate = 44100; +// format.bitsPerSample = 16; +// drwav* pWav = drwav_open_file_write("data/recording.wav", &format); +// +// ... +// +// drwav_uint64 samplesWritten = drwav_write(pWav, sampleCount, pSamples); +// +// +// +// OPTIONS +// #define these options before including this file. +// +// #define DR_WAV_NO_CONVERSION_API +// Disables conversion APIs such as drwav_read_f32() and drwav_s16_to_f32(). +// +// #define DR_WAV_NO_STDIO +// Disables drwav_open_file(), drwav_open_file_write(), etc. +// +// +// +// QUICK NOTES +// - Samples are always interleaved. +// - The default read function does not do any data conversion. Use drwav_read_f32() to read and convert audio data +// to IEEE 32-bit floating point samples, drwav_read_s32() to read samples as signed 32-bit PCM and drwav_read_s16() +// to read samples as signed 16-bit PCM. Tested and supported internal formats include the following: +// - Unsigned 8-bit PCM +// - Signed 12-bit PCM +// - Signed 16-bit PCM +// - Signed 24-bit PCM +// - Signed 32-bit PCM +// - IEEE 32-bit floating point. +// - IEEE 64-bit floating point. +// - A-law and u-law +// - Microsoft ADPCM +// - IMA ADPCM (DVI, format code 0x11) +// - dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format. + + +#ifndef dr_wav_h +#define dr_wav_h + +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +typedef signed char drwav_int8; +typedef unsigned char drwav_uint8; +typedef signed short drwav_int16; +typedef unsigned short drwav_uint16; +typedef signed int drwav_int32; +typedef unsigned int drwav_uint32; +typedef signed __int64 drwav_int64; +typedef unsigned __int64 drwav_uint64; +#else +#include +typedef int8_t drwav_int8; +typedef uint8_t drwav_uint8; +typedef int16_t drwav_int16; +typedef uint16_t drwav_uint16; +typedef int32_t drwav_int32; +typedef uint32_t drwav_uint32; +typedef int64_t drwav_int64; +typedef uint64_t drwav_uint64; +#endif +typedef drwav_uint8 drwav_bool8; +typedef drwav_uint32 drwav_bool32; +#define DRWAV_TRUE 1 +#define DRWAV_FALSE 0 + +#ifdef __cplusplus +extern "C" { +#endif + +// Common data formats. +#define DR_WAVE_FORMAT_PCM 0x1 +#define DR_WAVE_FORMAT_ADPCM 0x2 +#define DR_WAVE_FORMAT_IEEE_FLOAT 0x3 +#define DR_WAVE_FORMAT_ALAW 0x6 +#define DR_WAVE_FORMAT_MULAW 0x7 +#define DR_WAVE_FORMAT_DVI_ADPCM 0x11 +#define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE + +typedef enum +{ + drwav_seek_origin_start, + drwav_seek_origin_current +} drwav_seek_origin; + +typedef enum +{ + drwav_container_riff, + drwav_container_w64 +} drwav_container; + +// Callback for when data is read. Return value is the number of bytes actually read. +// +// pUserData [in] The user data that was passed to drwav_init(), drwav_open() and family. +// pBufferOut [out] The output buffer. +// bytesToRead [in] The number of bytes to read. +// +// Returns the number of bytes actually read. +// +// A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until +// either the entire bytesToRead is filled or you have reached the end of the stream. +typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); + +// Callback for when data is written. Returns value is the number of bytes actually written. +// +// pUserData [in] The user data that was passed to drwav_init_write(), drwav_open_write() and family. +// pData [out] A pointer to the data to write. +// bytesToWrite [in] The number of bytes to write. +// +// Returns the number of bytes actually written. +// +// If the return value differs from bytesToWrite, it indicates an error. +typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); + +// Callback for when data needs to be seeked. +// +// pUserData [in] The user data that was passed to drwav_init(), drwav_open() and family. +// offset [in] The number of bytes to move, relative to the origin. Will never be negative. +// origin [in] The origin of the seek - the current position or the start of the stream. +// +// Returns whether or not the seek was successful. +// +// Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which +// will be either drwav_seek_origin_start or drwav_seek_origin_current. +typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin); + +// Structure for internal use. Only used for loaders opened with drwav_open_memory(). +typedef struct +{ + const drwav_uint8* data; + size_t dataSize; + size_t currentReadPos; +} drwav__memory_stream; + +// Structure for internal use. Only used for writers opened with drwav_open_memory_write(). +typedef struct +{ + void** ppData; + size_t* pDataSize; + size_t dataSize; + size_t dataCapacity; + size_t currentWritePos; +} drwav__memory_stream_write; + +typedef struct +{ + drwav_container container; // RIFF, W64. + drwav_uint32 format; // DR_WAVE_FORMAT_* + drwav_uint32 channels; + drwav_uint32 sampleRate; + drwav_uint32 bitsPerSample; +} drwav_data_format; + +typedef struct +{ + // The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications + // that require support for data formats not natively supported by dr_wav. + drwav_uint16 formatTag; + + // The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. + drwav_uint16 channels; + + // The sample rate. Usually set to something like 44100. + drwav_uint32 sampleRate; + + // Average bytes per second. You probably don't need this, but it's left here for informational purposes. + drwav_uint32 avgBytesPerSec; + + // Block align. This is equal to the number of channels * bytes per sample. + drwav_uint16 blockAlign; + + // Bit's per sample. + drwav_uint16 bitsPerSample; + + // The size of the extended data. Only used internally for validation, but left here for informational purposes. + drwav_uint16 extendedSize; + + // The number of valid bits per sample. When is equal to WAVE_FORMAT_EXTENSIBLE, + // is always rounded up to the nearest multiple of 8. This variable contains information about exactly how + // many bits a valid per sample. Mainly used for informational purposes. + drwav_uint16 validBitsPerSample; + + // The channel mask. Not used at the moment. + drwav_uint32 channelMask; + + // The sub-format, exactly as specified by the wave file. + drwav_uint8 subFormat[16]; +} drwav_fmt; + +typedef struct +{ + // A pointer to the function to call when more data is needed. + drwav_read_proc onRead; + + // A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. + drwav_write_proc onWrite; + + // A pointer to the function to call when the wav file needs to be seeked. + drwav_seek_proc onSeek; + + // The user data to pass to callbacks. + void* pUserData; + + + // Whether or not the WAV file is formatted as a standard RIFF file or W64. + drwav_container container; + + + // Structure containing format information exactly as specified by the wav file. + drwav_fmt fmt; + + // The sample rate. Will be set to something like 44100. + drwav_uint32 sampleRate; + + // The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. + drwav_uint16 channels; + + // The bits per sample. Will be set to somthing like 16, 24, etc. + drwav_uint16 bitsPerSample; + + // The number of bytes per sample. + drwav_uint16 bytesPerSample; + + // Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). + drwav_uint16 translatedFormatTag; + + // The total number of samples making up the audio data. Use * to calculate + // the required size of a buffer to hold the entire audio data. + drwav_uint64 totalSampleCount; + + + // The size in bytes of the data chunk. + drwav_uint64 dataChunkDataSize; + + // The position in the stream of the first byte of the data chunk. This is used for seeking. + drwav_uint64 dataChunkDataPos; + + // The number of bytes remaining in the data chunk. + drwav_uint64 bytesRemaining; + + + // A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_open_memory(). + drwav__memory_stream memoryStream; + drwav__memory_stream_write memoryStreamWrite; + + // Generic data for compressed formats. This data is shared across all block-compressed formats. + struct + { + drwav_uint64 iCurrentSample; // The index of the next sample that will be read by drwav_read_*(). This is used with "totalSampleCount" to ensure we don't read excess samples at the end of the last block. + } compressed; + + // Microsoft ADPCM specific data. + struct + { + drwav_uint32 bytesRemainingInBlock; + drwav_uint16 predictor[2]; + drwav_int32 delta[2]; + drwav_int32 cachedSamples[4]; // Samples are stored in this cache during decoding. + drwav_uint32 cachedSampleCount; + drwav_int32 prevSamples[2][2]; // The previous 2 samples for each channel (2 channels at most). + } msadpcm; + + // IMA ADPCM specific data. + struct + { + drwav_uint32 bytesRemainingInBlock; + drwav_int32 predictor[2]; + drwav_int32 stepIndex[2]; + drwav_int32 cachedSamples[16]; // Samples are stored in this cache during decoding. + drwav_uint32 cachedSampleCount; + } ima; +} drwav; + + +// Initializes a pre-allocated drwav object. +// +// onRead [in] The function to call when data needs to be read from the client. +// onSeek [in] The function to call when the read position of the client data needs to move. +// pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. +// +// Returns true if successful; false otherwise. +// +// Close the loader with drwav_uninit(). +// +// This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() +// to open the stream from a file or from a block of memory respectively. +// +// If you want dr_wav to manage the memory allocation for you, consider using drwav_open() instead. This will allocate +// a drwav object on the heap and return a pointer to it. +// +// See also: drwav_init_file(), drwav_init_memory(), drwav_uninit() +drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData); + +// Initializes a pre-allocated drwav object for writing. +// +// onWrite [in] The function to call when data needs to be written. +// onSeek [in] The function to call when the write position needs to move. +// pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek. +// +// Returns true if successful; false otherwise. +// +// Close the writer with drwav_uninit(). +// +// This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() +// to open the stream from a file or from a block of memory respectively. +// +// If you want dr_wav to manage the memory allocation for you, consider using drwav_open() instead. This will allocate +// a drwav object on the heap and return a pointer to it. +// +// See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit() +drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData); + +// Uninitializes the given drwav object. +// +// Use this only for objects initialized with drwav_init(). +void drwav_uninit(drwav* pWav); + + +// Opens a wav file using the given callbacks. +// +// onRead [in] The function to call when data needs to be read from the client. +// onSeek [in] The function to call when the read position of the client data needs to move. +// pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. +// +// Returns null on error. +// +// Close the loader with drwav_close(). +// +// This is the lowest level function for opening a WAV file. You can also use drwav_open_file() and drwav_open_memory() +// to open the stream from a file or from a block of memory respectively. +// +// This is different from drwav_init() in that it will allocate the drwav object for you via DRWAV_MALLOC() before +// initializing it. +// +// See also: drwav_open_file(), drwav_open_memory(), drwav_close() +drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData); + +// Opens a wav file for writing using the given callbacks. +// +// onWrite [in] The function to call when data needs to be written. +// onSeek [in] The function to call when the write position needs to move. +// pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek. +// +// Returns null on error. +// +// Close the loader with drwav_close(). +// +// This is the lowest level function for opening a WAV file. You can also use drwav_open_file_write() and drwav_open_memory_write() +// to open the stream from a file or from a block of memory respectively. +// +// This is different from drwav_init_write() in that it will allocate the drwav object for you via DRWAV_MALLOC() before +// initializing it. +// +// See also: drwav_open_file_write(), drwav_open_memory_write(), drwav_close() +drwav* drwav_open_write(const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData); + +// Uninitializes and deletes the the given drwav object. +// +// Use this only for objects created with drwav_open(). +void drwav_close(drwav* pWav); + + +// Reads raw audio data. +// +// This is the lowest level function for reading audio data. It simply reads the given number of +// bytes of the raw internal sample data. +// +// Consider using drwav_read_s16(), drwav_read_s32() or drwav_read_f32() for reading sample data in +// a consistent format. +// +// Returns the number of bytes actually read. +size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut); + +// Reads a chunk of audio data in the native internal format. +// +// This is typically the most efficient way to retrieve audio data, but it does not do any format +// conversions which means you'll need to convert the data manually if required. +// +// If the return value is less than it means the end of the file has been reached or +// you have requested more samples than can possibly fit in the output buffer. +// +// This function will only work when sample data is of a fixed size and uncompressed. If you are +// using a compressed format consider using drwav_read_raw() or drwav_read_s16/s32/f32/etc(). +drwav_uint64 drwav_read(drwav* pWav, drwav_uint64 samplesToRead, void* pBufferOut); + +// Seeks to the given sample. +// +// Returns true if successful; false otherwise. +drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample); + + +// Writes raw audio data. +// +// Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error. +size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData); + +// Writes audio data based on sample counts. +// +// Returns the number of samples written. +drwav_uint64 drwav_write(drwav* pWav, drwav_uint64 samplesToWrite, const void* pData); + + + +//// Convertion Utilities //// +#ifndef DR_WAV_NO_CONVERSION_API + +// Reads a chunk of audio data and converts it to signed 16-bit PCM samples. +// +// Returns the number of samples actually read. +// +// If the return value is less than it means the end of the file has been reached. +drwav_uint64 drwav_read_s16(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); + +// Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. +void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + +// Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. +void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + +// Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. +void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount); + +// Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. +void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount); + +// Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. +void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount); + +// Low-level function for converting A-law samples to signed 16-bit PCM samples. +void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + +// Low-level function for converting u-law samples to signed 16-bit PCM samples. +void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + + +// Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples. +// +// Returns the number of samples actually read. +// +// If the return value is less than it means the end of the file has been reached. +drwav_uint64 drwav_read_f32(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut); + +// Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. +void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + +// Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. +void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount); + +// Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. +void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + +// Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. +void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount); + +// Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. +void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount); + +// Low-level function for converting A-law samples to IEEE 32-bit floating point samples. +void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + +// Low-level function for converting u-law samples to IEEE 32-bit floating point samples. +void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + + +// Reads a chunk of audio data and converts it to signed 32-bit PCM samples. +// +// Returns the number of samples actually read. +// +// If the return value is less than it means the end of the file has been reached. +drwav_uint64 drwav_read_s32(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut); + +// Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. +void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +// Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. +void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount); + +// Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. +void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +// Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. +void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount); + +// Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. +void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount); + +// Low-level function for converting A-law samples to signed 32-bit PCM samples. +void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +// Low-level function for converting u-law samples to signed 32-bit PCM samples. +void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +#endif //DR_WAV_NO_CONVERSION_API + + +//// High-Level Convenience Helpers //// + +#ifndef DR_WAV_NO_STDIO + +// Helper for initializing a wave file using stdio. +// +// This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav +// objects because the operating system may restrict the number of file handles an application can have open at +// any given time. +drwav_bool32 drwav_init_file(drwav* pWav, const char* filename); + +// Helper for initializing a wave file for writing using stdio. +// +// This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav +// objects because the operating system may restrict the number of file handles an application can have open at +// any given time. +drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat); + +// Helper for opening a wave file using stdio. +// +// This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav +// objects because the operating system may restrict the number of file handles an application can have open at +// any given time. +drwav* drwav_open_file(const char* filename); + +// Helper for opening a wave file for writing using stdio. +// +// This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav +// objects because the operating system may restrict the number of file handles an application can have open at +// any given time. +drwav* drwav_open_file_write(const char* filename, const drwav_data_format* pFormat); + +#endif //DR_WAV_NO_STDIO + +// Helper for initializing a loader from a pre-allocated memory buffer. +// +// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for +// the lifetime of the drwav object. +// +// The buffer should contain the contents of the entire wave file, not just the sample data. +drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize); + +// Helper for initializing a writer which outputs data to a memory buffer. +// +// dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). +// +// The buffer will remain allocated even after drwav_uninit() is called. Indeed, the buffer should not be +// considered valid until after drwav_uninit() has been called anyway. +drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat); + +// Helper for opening a loader from a pre-allocated memory buffer. +// +// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for +// the lifetime of the drwav object. +// +// The buffer should contain the contents of the entire wave file, not just the sample data. +drwav* drwav_open_memory(const void* data, size_t dataSize); + +// Helper for opening a writer which outputs data to a memory buffer. +// +// dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). +// +// The buffer will remain allocated even after drwav_close() is called. Indeed, the buffer should not be +// considered valid until after drwav_close() has been called anyway. +drwav* drwav_open_memory_write(void** ppData, size_t* pDataSize, const drwav_data_format* pFormat); + + +#ifndef DR_WAV_NO_CONVERSION_API +// Opens and reads a wav file in a single operation. +drwav_int16* drwav_open_and_read_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); +float* drwav_open_and_read_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); +drwav_int32* drwav_open_and_read_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); +#ifndef DR_WAV_NO_STDIO +// Opens an decodes a wav file in a single operation. +drwav_int16* drwav_open_and_read_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); +float* drwav_open_and_read_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); +drwav_int32* drwav_open_and_read_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); +#endif + +// Opens an decodes a wav file from a block of memory in a single operation. +drwav_int16* drwav_open_and_read_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); +float* drwav_open_and_read_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); +drwav_int32* drwav_open_and_read_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); +#endif + +// Frees data that was allocated internally by dr_wav. +void drwav_free(void* pDataReturnedByOpenAndRead); + +#ifdef __cplusplus +} +#endif +#endif // dr_wav_h + + +///////////////////////////////////////////////////// +// +// IMPLEMENTATION +// +///////////////////////////////////////////////////// + +#ifdef DR_WAV_IMPLEMENTATION +#include +#include // For memcpy(), memset() +#include // For INT_MAX + +#ifndef DR_WAV_NO_STDIO +#include +#endif + +// Standard library stuff. +#ifndef DRWAV_ASSERT +#include +#define DRWAV_ASSERT(expression) assert(expression) +#endif +#ifndef DRWAV_MALLOC +#define DRWAV_MALLOC(sz) malloc((sz)) +#endif +#ifndef DRWAV_REALLOC +#define DRWAV_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef DRWAV_FREE +#define DRWAV_FREE(p) free((p)) +#endif +#ifndef DRWAV_COPY_MEMORY +#define DRWAV_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#endif +#ifndef DRWAV_ZERO_MEMORY +#define DRWAV_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +#endif + +#define drwav_countof(x) (sizeof(x) / sizeof(x[0])) +#define drwav_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) +#define drwav_min(a, b) (((a) < (b)) ? (a) : (b)) +#define drwav_max(a, b) (((a) > (b)) ? (a) : (b)) +#define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x)))) + +#define drwav_assert DRWAV_ASSERT +#define drwav_copy_memory DRWAV_COPY_MEMORY +#define drwav_zero_memory DRWAV_ZERO_MEMORY + + +#define DRWAV_MAX_SIMD_VECTOR_SIZE 64 // 64 for AVX-512 in the future. + +#ifdef _MSC_VER +#define DRWAV_INLINE __forceinline +#else +#ifdef __GNUC__ +#define DRWAV_INLINE inline __attribute__((always_inline)) +#else +#define DRWAV_INLINE inline +#endif +#endif + +// I couldn't figure out where SIZE_MAX was defined for VC6. If anybody knows, let me know. +#if defined(_MSC_VER) && _MSC_VER <= 1200 + #if defined(_WIN64) + #define SIZE_MAX ((drwav_uint64)0xFFFFFFFFFFFFFFFF) + #else + #define SIZE_MAX 0xFFFFFFFF + #endif +#endif + +static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; // 66666972-912E-11CF-A5D6-28DB04C10000 +static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 65766177-ACF3-11D3-8CD1-00C04F8EDB8A +static const drwav_uint8 drwavGUID_W64_JUNK[16] = {0x6A,0x75,0x6E,0x6B, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 6B6E756A-ACF3-11D3-8CD1-00C04F8EDB8A +static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A +static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 74636166-ACF3-11D3-8CD1-00C04F8EDB8A +static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 61746164-ACF3-11D3-8CD1-00C04F8EDB8A + +static DRWAV_INLINE drwav_bool32 drwav__guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]) +{ + const drwav_uint32* a32 = (const drwav_uint32*)a; + const drwav_uint32* b32 = (const drwav_uint32*)b; + + return + a32[0] == b32[0] && + a32[1] == b32[1] && + a32[2] == b32[2] && + a32[3] == b32[3]; +} + +static DRWAV_INLINE drwav_bool32 drwav__fourcc_equal(const unsigned char* a, const char* b) +{ + return + a[0] == b[0] && + a[1] == b[1] && + a[2] == b[2] && + a[3] == b[3]; +} + + + +static DRWAV_INLINE int drwav__is_little_endian() +{ + int n = 1; + return (*(char*)&n) == 1; +} + +static DRWAV_INLINE unsigned short drwav__bytes_to_u16(const unsigned char* data) +{ + if (drwav__is_little_endian()) { + return (data[0] << 0) | (data[1] << 8); + } else { + return (data[1] << 0) | (data[0] << 8); + } +} + +static DRWAV_INLINE short drwav__bytes_to_s16(const unsigned char* data) +{ + return (short)drwav__bytes_to_u16(data); +} + +static DRWAV_INLINE unsigned int drwav__bytes_to_u32(const unsigned char* data) +{ + if (drwav__is_little_endian()) { + return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + } else { + return (data[3] << 0) | (data[2] << 8) | (data[1] << 16) | (data[0] << 24); + } +} + +static DRWAV_INLINE drwav_uint64 drwav__bytes_to_u64(const unsigned char* data) +{ + if (drwav__is_little_endian()) { + return + ((drwav_uint64)data[0] << 0) | ((drwav_uint64)data[1] << 8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) | + ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56); + } else { + return + ((drwav_uint64)data[7] << 0) | ((drwav_uint64)data[6] << 8) | ((drwav_uint64)data[5] << 16) | ((drwav_uint64)data[4] << 24) | + ((drwav_uint64)data[3] << 32) | ((drwav_uint64)data[2] << 40) | ((drwav_uint64)data[1] << 48) | ((drwav_uint64)data[0] << 56); + } +} + +static DRWAV_INLINE void drwav__bytes_to_guid(const unsigned char* data, drwav_uint8* guid) +{ + for (int i = 0; i < 16; ++i) { + guid[i] = data[i]; + } +} + + +static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag) +{ + return + formatTag == DR_WAVE_FORMAT_ADPCM || + formatTag == DR_WAVE_FORMAT_DVI_ADPCM; +} + + +typedef struct +{ + union + { + drwav_uint8 fourcc[4]; + drwav_uint8 guid[16]; + } id; + + // The size in bytes of the chunk. + drwav_uint64 sizeInBytes; + + // RIFF = 2 byte alignment. + // W64 = 8 byte alignment. + unsigned int paddingSize; + +} drwav__chunk_header; + +static drwav_bool32 drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav__chunk_header* pHeaderOut) +{ + if (container == drwav_container_riff) { + if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) { + return DRWAV_FALSE; + } + + unsigned char sizeInBytes[4]; + if (onRead(pUserData, sizeInBytes, 4) != 4) { + return DRWAV_FALSE; + } + + pHeaderOut->sizeInBytes = drwav__bytes_to_u32(sizeInBytes); + pHeaderOut->paddingSize = (unsigned int)(pHeaderOut->sizeInBytes % 2); + *pRunningBytesReadOut += 8; + } else { + if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) { + return DRWAV_FALSE; + } + + unsigned char sizeInBytes[8]; + if (onRead(pUserData, sizeInBytes, 8) != 8) { + return DRWAV_FALSE; + } + + pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24; // <-- Subtract 24 because w64 includes the size of the header. + pHeaderOut->paddingSize = (unsigned int)(pHeaderOut->sizeInBytes % 8); + pRunningBytesReadOut += 24; + } + + return DRWAV_TRUE; +} + +static drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) +{ + drwav_uint64 bytesRemainingToSeek = offset; + while (bytesRemainingToSeek > 0) { + if (bytesRemainingToSeek > 0x7FFFFFFF) { + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + bytesRemainingToSeek -= 0x7FFFFFFF; + } else { + if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + bytesRemainingToSeek = 0; + } + } + + return DRWAV_TRUE; +} + + +static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut) +{ + drwav__chunk_header header; + if (!drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header)) { + return DRWAV_FALSE; + } + + + // Skip junk chunks. + if ((container == drwav_container_riff && drwav__fourcc_equal(header.id.fourcc, "JUNK")) || (container == drwav_container_w64 && drwav__guid_equal(header.id.guid, drwavGUID_W64_JUNK))) { + if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize; + + return drwav__read_fmt(onRead, onSeek, pUserData, container, pRunningBytesReadOut, fmtOut); + } + + + // Validation. + if (container == drwav_container_riff) { + if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) { + return DRWAV_FALSE; + } + } else { + if (!drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT)) { + return DRWAV_FALSE; + } + } + + + unsigned char fmt[16]; + if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += sizeof(fmt); + + fmtOut->formatTag = drwav__bytes_to_u16(fmt + 0); + fmtOut->channels = drwav__bytes_to_u16(fmt + 2); + fmtOut->sampleRate = drwav__bytes_to_u32(fmt + 4); + fmtOut->avgBytesPerSec = drwav__bytes_to_u32(fmt + 8); + fmtOut->blockAlign = drwav__bytes_to_u16(fmt + 12); + fmtOut->bitsPerSample = drwav__bytes_to_u16(fmt + 14); + + fmtOut->extendedSize = 0; + fmtOut->validBitsPerSample = 0; + fmtOut->channelMask = 0; + memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat)); + + if (header.sizeInBytes > 16) { + unsigned char fmt_cbSize[2]; + if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) { + return DRWAV_FALSE; // Expecting more data. + } + *pRunningBytesReadOut += sizeof(fmt_cbSize); + + int bytesReadSoFar = 18; + + fmtOut->extendedSize = drwav__bytes_to_u16(fmt_cbSize); + if (fmtOut->extendedSize > 0) { + // Simple validation. + if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + if (fmtOut->extendedSize != 22) { + return DRWAV_FALSE; + } + } + + if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + unsigned char fmtext[22]; + if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) { + return DRWAV_FALSE; // Expecting more data. + } + + fmtOut->validBitsPerSample = drwav__bytes_to_u16(fmtext + 0); + fmtOut->channelMask = drwav__bytes_to_u32(fmtext + 2); + drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat); + } else { + if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + } + *pRunningBytesReadOut += fmtOut->extendedSize; + + bytesReadSoFar += fmtOut->extendedSize; + } + + // Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. + if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar); + } + + if (header.paddingSize > 0) { + if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += header.paddingSize; + } + + return DRWAV_TRUE; +} + + +#ifndef DR_WAV_NO_STDIO +static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) +{ + return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData); +} + +static size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite) +{ + return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData); +} + +static drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin) +{ + return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; +} + +drwav_bool32 drwav_init_file(drwav* pWav, const char* filename) +{ + FILE* pFile; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (fopen_s(&pFile, filename, "rb") != 0) { + return DRWAV_FALSE; + } +#else + pFile = fopen(filename, "rb"); + if (pFile == NULL) { + return DRWAV_FALSE; + } +#endif + + return drwav_init(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile); +} + +drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat) +{ + FILE* pFile; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (fopen_s(&pFile, filename, "wb") != 0) { + return DRWAV_FALSE; + } +#else + pFile = fopen(filename, "wb"); + if (pFile == NULL) { + return DRWAV_FALSE; + } +#endif + + return drwav_init_write(pWav, pFormat, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile); +} + +drwav* drwav_open_file(const char* filename) +{ + FILE* pFile; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (fopen_s(&pFile, filename, "rb") != 0) { + return NULL; + } +#else + pFile = fopen(filename, "rb"); + if (pFile == NULL) { + return NULL; + } +#endif + + drwav* pWav = drwav_open(drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile); + if (pWav == NULL) { + fclose(pFile); + return NULL; + } + + return pWav; +} + +drwav* drwav_open_file_write(const char* filename, const drwav_data_format* pFormat) +{ + FILE* pFile; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (fopen_s(&pFile, filename, "wb") != 0) { + return NULL; + } +#else + pFile = fopen(filename, "wb"); + if (pFile == NULL) { + return NULL; + } +#endif + + drwav* pWav = drwav_open_write(pFormat, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile); + if (pWav == NULL) { + fclose(pFile); + return NULL; + } + + return pWav; +} +#endif //DR_WAV_NO_STDIO + + +static size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) +{ + drwav__memory_stream* memory = (drwav__memory_stream*)pUserData; + drwav_assert(memory != NULL); + drwav_assert(memory->dataSize >= memory->currentReadPos); + + size_t bytesRemaining = memory->dataSize - memory->currentReadPos; + if (bytesToRead > bytesRemaining) { + bytesToRead = bytesRemaining; + } + + if (bytesToRead > 0) { + DRWAV_COPY_MEMORY(pBufferOut, memory->data + memory->currentReadPos, bytesToRead); + memory->currentReadPos += bytesToRead; + } + + return bytesToRead; +} + +static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin) +{ + drwav__memory_stream* memory = (drwav__memory_stream*)pUserData; + drwav_assert(memory != NULL); + + if (origin == drwav_seek_origin_current) { + if (offset > 0) { + if (memory->currentReadPos + offset > memory->dataSize) { + offset = (int)(memory->dataSize - memory->currentReadPos); // Trying to seek too far forward. + } + } else { + if (memory->currentReadPos < (size_t)-offset) { + offset = -(int)memory->currentReadPos; // Trying to seek too far backwards. + } + } + + // This will never underflow thanks to the clamps above. + memory->currentReadPos += offset; + } else { + if ((drwav_uint32)offset <= memory->dataSize) { + memory->currentReadPos = offset; + } else { + memory->currentReadPos = memory->dataSize; // Trying to seek too far forward. + } + } + + return DRWAV_TRUE; +} + +static size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) +{ + drwav__memory_stream_write* memory = (drwav__memory_stream_write*)pUserData; + drwav_assert(memory != NULL); + drwav_assert(memory->dataCapacity >= memory->currentWritePos); + + size_t bytesRemaining = memory->dataCapacity - memory->currentWritePos; + if (bytesRemaining < bytesToWrite) { + // Need to reallocate. + size_t newDataCapacity = (memory->dataCapacity == 0) ? 256 : memory->dataCapacity * 2; + + // If doubling wasn't enough, just make it the minimum required size to write the data. + if ((newDataCapacity - memory->currentWritePos) < bytesToWrite) { + newDataCapacity = memory->currentWritePos + bytesToWrite; + } + + void* pNewData = DRWAV_REALLOC(*memory->ppData, newDataCapacity); + if (pNewData == NULL) { + return 0; + } + + *memory->ppData = pNewData; + memory->dataCapacity = newDataCapacity; + } + + drwav_uint8* pDataOut = (drwav_uint8*)(*memory->ppData); + DRWAV_COPY_MEMORY(pDataOut + memory->currentWritePos, pDataIn, bytesToWrite); + + memory->currentWritePos += bytesToWrite; + if (memory->dataSize < memory->currentWritePos) { + memory->dataSize = memory->currentWritePos; + } + + *memory->pDataSize = memory->dataSize; + + return bytesToWrite; +} + +static drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin) +{ + drwav__memory_stream_write* memory = (drwav__memory_stream_write*)pUserData; + drwav_assert(memory != NULL); + + if (origin == drwav_seek_origin_current) { + if (offset > 0) { + if (memory->currentWritePos + offset > memory->dataSize) { + offset = (int)(memory->dataSize - memory->currentWritePos); // Trying to seek too far forward. + } + } else { + if (memory->currentWritePos < (size_t)-offset) { + offset = -(int)memory->currentWritePos; // Trying to seek too far backwards. + } + } + + // This will never underflow thanks to the clamps above. + memory->currentWritePos += offset; + } else { + if ((drwav_uint32)offset <= memory->dataSize) { + memory->currentWritePos = offset; + } else { + memory->currentWritePos = memory->dataSize; // Trying to seek too far forward. + } + } + + return DRWAV_TRUE; +} + +drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize) +{ + if (data == NULL || dataSize == 0) { + return DRWAV_FALSE; + } + + drwav__memory_stream memoryStream; + drwav_zero_memory(&memoryStream, sizeof(memoryStream)); + memoryStream.data = (const unsigned char*)data; + memoryStream.dataSize = dataSize; + memoryStream.currentReadPos = 0; + + if (!drwav_init(pWav, drwav__on_read_memory, drwav__on_seek_memory, (void*)&memoryStream)) { + return DRWAV_FALSE; + } + + pWav->memoryStream = memoryStream; + pWav->pUserData = &pWav->memoryStream; + return DRWAV_TRUE; +} + +drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat) +{ + if (ppData == NULL) { + return DRWAV_FALSE; + } + + *ppData = NULL; // Important because we're using realloc()! + *pDataSize = 0; + + drwav__memory_stream_write memoryStreamWrite; + drwav_zero_memory(&memoryStreamWrite, sizeof(memoryStreamWrite)); + memoryStreamWrite.ppData = ppData; + memoryStreamWrite.pDataSize = pDataSize; + memoryStreamWrite.dataSize = 0; + memoryStreamWrite.dataCapacity = 0; + memoryStreamWrite.currentWritePos = 0; + + if (!drwav_init_write(pWav, pFormat, drwav__on_write_memory, drwav__on_seek_memory_write, (void*)&memoryStreamWrite)) { + return DRWAV_FALSE; + } + + pWav->memoryStreamWrite = memoryStreamWrite; + pWav->pUserData = &pWav->memoryStreamWrite; + return DRWAV_TRUE; +} + +drwav* drwav_open_memory(const void* data, size_t dataSize) +{ + if (data == NULL || dataSize == 0) { + return NULL; + } + + drwav__memory_stream memoryStream; + drwav_zero_memory(&memoryStream, sizeof(memoryStream)); + memoryStream.data = (const unsigned char*)data; + memoryStream.dataSize = dataSize; + memoryStream.currentReadPos = 0; + + drwav* pWav = drwav_open(drwav__on_read_memory, drwav__on_seek_memory, (void*)&memoryStream); + if (pWav == NULL) { + return NULL; + } + + pWav->memoryStream = memoryStream; + pWav->pUserData = &pWav->memoryStream; + return pWav; +} + +drwav* drwav_open_memory_write(void** ppData, size_t* pDataSize, const drwav_data_format* pFormat) +{ + if (ppData == NULL) { + return NULL; + } + + *ppData = NULL; // Important because we're using realloc()! + *pDataSize = 0; + + drwav__memory_stream_write memoryStreamWrite; + drwav_zero_memory(&memoryStreamWrite, sizeof(memoryStreamWrite)); + memoryStreamWrite.ppData = ppData; + memoryStreamWrite.pDataSize = pDataSize; + memoryStreamWrite.dataSize = 0; + memoryStreamWrite.dataCapacity = 0; + memoryStreamWrite.currentWritePos = 0; + + drwav* pWav = drwav_open_write(pFormat, drwav__on_write_memory, drwav__on_seek_memory_write, (void*)&memoryStreamWrite); + if (pWav == NULL) { + return NULL; + } + + pWav->memoryStreamWrite = memoryStreamWrite; + pWav->pUserData = &pWav->memoryStreamWrite; + return pWav; +} + + +drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData) +{ + if (onRead == NULL || onSeek == NULL) { + return DRWAV_FALSE; + } + + drwav_zero_memory(pWav, sizeof(*pWav)); + + + // The first 4 bytes should be the RIFF identifier. + unsigned char riff[4]; + if (onRead(pUserData, riff, sizeof(riff)) != sizeof(riff)) { + return DRWAV_FALSE; // Failed to read data. + } + + // The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for + // w64 it will start with "riff". + if (drwav__fourcc_equal(riff, "RIFF")) { + pWav->container = drwav_container_riff; + } else if (drwav__fourcc_equal(riff, "riff")) { + pWav->container = drwav_container_w64; + + // Check the rest of the GUID for validity. + drwav_uint8 riff2[12]; + if (onRead(pUserData, riff2, sizeof(riff2)) != sizeof(riff2)) { + return DRWAV_FALSE; + } + + for (int i = 0; i < 12; ++i) { + if (riff2[i] != drwavGUID_W64_RIFF[i+4]) { + return DRWAV_FALSE; + } + } + } else { + return DRWAV_FALSE; // Unknown or unsupported container. + } + + + if (pWav->container == drwav_container_riff) { + // RIFF/WAVE + unsigned char chunkSizeBytes[4]; + if (onRead(pUserData, chunkSizeBytes, sizeof(chunkSizeBytes)) != sizeof(chunkSizeBytes)) { + return DRWAV_FALSE; + } + + unsigned int chunkSize = drwav__bytes_to_u32(chunkSizeBytes); + if (chunkSize < 36) { + return DRWAV_FALSE; // Chunk size should always be at least 36 bytes. + } + + unsigned char wave[4]; + if (onRead(pUserData, wave, sizeof(wave)) != sizeof(wave)) { + return DRWAV_FALSE; + } + + if (!drwav__fourcc_equal(wave, "WAVE")) { + return DRWAV_FALSE; // Expecting "WAVE". + } + + pWav->dataChunkDataPos = 4 + sizeof(chunkSizeBytes) + sizeof(wave); + } else { + // W64 + unsigned char chunkSize[8]; + if (onRead(pUserData, chunkSize, sizeof(chunkSize)) != sizeof(chunkSize)) { + return DRWAV_FALSE; + } + + if (drwav__bytes_to_u64(chunkSize) < 80) { + return DRWAV_FALSE; + } + + drwav_uint8 wave[16]; + if (onRead(pUserData, wave, sizeof(wave)) != sizeof(wave)) { + return DRWAV_FALSE; + } + + if (!drwav__guid_equal(wave, drwavGUID_W64_WAVE)) { + return DRWAV_FALSE; + } + + pWav->dataChunkDataPos = 16 + sizeof(chunkSize) + sizeof(wave); + } + + + // The next 24 bytes should be the "fmt " chunk. + drwav_fmt fmt; + if (!drwav__read_fmt(onRead, onSeek, pUserData, pWav->container, &pWav->dataChunkDataPos, &fmt)) { + return DRWAV_FALSE; // Failed to read the "fmt " chunk. + } + + + // Translate the internal format. + unsigned short translatedFormatTag = fmt.formatTag; + if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0); + } + + + drwav_uint64 sampleCountFromFactChunk = 0; + + // The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. + drwav_uint64 dataSize; + for (;;) + { + drwav__chunk_header header; + if (!drwav__read_chunk_header(onRead, pUserData, pWav->container, &pWav->dataChunkDataPos, &header)) { + return DRWAV_FALSE; + } + + dataSize = header.sizeInBytes; + if (pWav->container == drwav_container_riff) { + if (drwav__fourcc_equal(header.id.fourcc, "data")) { + break; + } + } else { + if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) { + break; + } + } + + // Optional. Get the total sample count from the FACT chunk. This is useful for compressed formats. + if (pWav->container == drwav_container_riff) { + if (drwav__fourcc_equal(header.id.fourcc, "fact")) { + drwav_uint32 sampleCount; + if (onRead(pUserData, &sampleCount, 4) != 4) { + return DRWAV_FALSE; + } + pWav->dataChunkDataPos += 4; + dataSize -= 4; + + // The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this + // for Microsoft ADPCM formats. + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + sampleCountFromFactChunk = sampleCount; + } else { + sampleCountFromFactChunk = 0; + } + } + } else { + if (drwav__guid_equal(header.id.guid, drwavGUID_W64_FACT)) { + if (onRead(pUserData, &sampleCountFromFactChunk, 8) != 8) { + return DRWAV_FALSE; + } + pWav->dataChunkDataPos += 4; + dataSize -= 8; + } + } + + // If we get here it means we didn't find the "data" chunk. Seek past it. + + // Make sure we seek past the padding. + dataSize += header.paddingSize; + drwav__seek_forward(onSeek, dataSize, pUserData); + pWav->dataChunkDataPos += dataSize; + } + + // At this point we should be sitting on the first byte of the raw audio data. + + pWav->onRead = onRead; + pWav->onSeek = onSeek; + pWav->pUserData = pUserData; + pWav->fmt = fmt; + pWav->sampleRate = fmt.sampleRate; + pWav->channels = fmt.channels; + pWav->bitsPerSample = fmt.bitsPerSample; + pWav->bytesPerSample = (unsigned int)(fmt.blockAlign / fmt.channels); + pWav->bytesRemaining = dataSize; + pWav->translatedFormatTag = translatedFormatTag; + pWav->dataChunkDataSize = dataSize; + + if (sampleCountFromFactChunk != 0) { + pWav->totalSampleCount = sampleCountFromFactChunk * fmt.channels; + } else { + pWav->totalSampleCount = dataSize / pWav->bytesPerSample; + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + drwav_uint64 blockCount = dataSize / fmt.blockAlign; + pWav->totalSampleCount = (blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2; // x2 because two samples per byte. + } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + drwav_uint64 blockCount = dataSize / fmt.blockAlign; + pWav->totalSampleCount = ((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels); + } + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + pWav->bytesPerSample = 0; + } + +#ifdef DR_WAV_LIBSNDFILE_COMPAT + // I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website), + // it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count + // from the number of blocks, however this results in the inclusion of the extra silent samples at the end of the last block. The correct + // way to know the total sample count is to inspect the "fact" chunk which should always be present for compressed formats, and should + // always include the sample count. This little block of code below is only used to emulate the libsndfile logic so I can properly run my + // correctness tests against libsndfile and is disabled by default. + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + drwav_uint64 blockCount = dataSize / fmt.blockAlign; + pWav->totalSampleCount = (blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2; // x2 because two samples per byte. + } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + drwav_uint64 blockCount = dataSize / fmt.blockAlign; + pWav->totalSampleCount = ((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels); + } +#endif + + return DRWAV_TRUE; +} + +drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData) +{ + if (onWrite == NULL || onSeek == NULL) { + return DRWAV_FALSE; + } + + // Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. + if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) { + return DRWAV_FALSE; + } + if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) { + return DRWAV_FALSE; + } + + + drwav_zero_memory(pWav, sizeof(*pWav)); + pWav->onWrite = onWrite; + pWav->onSeek = onSeek; + pWav->pUserData = pUserData; + pWav->fmt.formatTag = (drwav_uint16)pFormat->format; + pWav->fmt.channels = (drwav_uint16)pFormat->channels; + pWav->fmt.sampleRate = pFormat->sampleRate; + pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) >> 3); + pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) >> 3); + pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; + pWav->fmt.extendedSize = 0; + + size_t runningPos = 0; + + // "RIFF" chunk. + drwav_uint64 chunkSizeRIFF = 0; + if (pFormat->container == drwav_container_riff) { + runningPos += pWav->onWrite(pUserData, "RIFF", 4); + runningPos += pWav->onWrite(pUserData, &chunkSizeRIFF, 4); + runningPos += pWav->onWrite(pUserData, "WAVE", 4); + } else { + runningPos += pWav->onWrite(pUserData, drwavGUID_W64_RIFF, 16); + runningPos += pWav->onWrite(pUserData, &chunkSizeRIFF, 8); + runningPos += pWav->onWrite(pUserData, drwavGUID_W64_WAVE, 16); + } + + // "fmt " chunk. + drwav_uint64 chunkSizeFMT; + if (pFormat->container == drwav_container_riff) { + chunkSizeFMT = 16; + runningPos += pWav->onWrite(pUserData, "fmt ", 4); + runningPos += pWav->onWrite(pUserData, &chunkSizeFMT, 4); + } else { + chunkSizeFMT = 40; + runningPos += pWav->onWrite(pUserData, drwavGUID_W64_FMT, 16); + runningPos += pWav->onWrite(pUserData, &chunkSizeFMT, 8); + } + + runningPos += pWav->onWrite(pUserData, &pWav->fmt.formatTag, 2); + runningPos += pWav->onWrite(pUserData, &pWav->fmt.channels, 2); + runningPos += pWav->onWrite(pUserData, &pWav->fmt.sampleRate, 4); + runningPos += pWav->onWrite(pUserData, &pWav->fmt.avgBytesPerSec, 4); + runningPos += pWav->onWrite(pUserData, &pWav->fmt.blockAlign, 2); + runningPos += pWav->onWrite(pUserData, &pWav->fmt.bitsPerSample, 2); + + pWav->dataChunkDataPos = runningPos; + pWav->dataChunkDataSize = 0; + + // "data" chunk. + drwav_uint64 chunkSizeDATA = 0; + if (pFormat->container == drwav_container_riff) { + runningPos += pWav->onWrite(pUserData, "data", 4); + runningPos += pWav->onWrite(pUserData, &chunkSizeDATA, 4); + } else { + runningPos += pWav->onWrite(pUserData, drwavGUID_W64_DATA, 16); + runningPos += pWav->onWrite(pUserData, &chunkSizeDATA, 8); + } + + + // Simple validation. + if (pFormat->container == drwav_container_riff) { + if (runningPos != 20 + chunkSizeFMT + 8) { + return DRWAV_FALSE; + } + } else { + if (runningPos != 40 + chunkSizeFMT + 24) { + return DRWAV_FALSE; + } + } + + + + // Set some properties for the client's convenience. + pWav->container = pFormat->container; + pWav->channels = (drwav_uint16)pFormat->channels; + pWav->sampleRate = pFormat->sampleRate; + pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; + pWav->bytesPerSample = (drwav_uint16)(pFormat->bitsPerSample >> 3); + pWav->translatedFormatTag = (drwav_uint16)pFormat->format; + + return DRWAV_TRUE; +} + +void drwav_uninit(drwav* pWav) +{ + if (pWav == NULL) { + return; + } + + // If the drwav object was opened in write mode we'll need to finialize a few things: + // - Make sure the "data" chunk is aligned to 16-bits + // - Set the size of the "data" chunk. + if (pWav->onWrite != NULL) { + // Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. + drwav_uint32 paddingSize = 0; + if (pWav->container == drwav_container_riff) { + paddingSize = (drwav_uint32)(pWav->dataChunkDataSize % 2); + } else { + paddingSize = (drwav_uint32)(pWav->dataChunkDataSize % 8); + } + + if (paddingSize > 0) { + drwav_uint64 paddingData = 0; + pWav->onWrite(pWav->pUserData, &paddingData, paddingSize); + } + + + // Chunk sizes. + if (pWav->onSeek) { + if (pWav->container == drwav_container_riff) { + // The "RIFF" chunk size. + if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) { + drwav_uint32 riffChunkSize = 36; + if (pWav->dataChunkDataSize <= (0xFFFFFFFF - 36)) { + riffChunkSize = 36 + (drwav_uint32)pWav->dataChunkDataSize; + } else { + riffChunkSize = 0xFFFFFFFF; + } + + pWav->onWrite(pWav->pUserData, &riffChunkSize, 4); + } + + // the "data" chunk size. + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 4, drwav_seek_origin_start)) { + drwav_uint32 dataChunkSize = 0; + if (pWav->dataChunkDataSize <= 0xFFFFFFFF) { + dataChunkSize = (drwav_uint32)pWav->dataChunkDataSize; + } else { + dataChunkSize = 0xFFFFFFFF; + } + + pWav->onWrite(pWav->pUserData, &dataChunkSize, 4); + } + } else { + // The "RIFF" chunk size. + if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) { + drwav_uint64 riffChunkSize = 80 + 24 + pWav->dataChunkDataSize; + pWav->onWrite(pWav->pUserData, &riffChunkSize, 8); + } + + // The "data" chunk size. + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 16, drwav_seek_origin_start)) { + drwav_uint64 dataChunkSize = 24 + pWav->dataChunkDataSize; // +24 because W64 includes the size of the GUID and size fields. + pWav->onWrite(pWav->pUserData, &dataChunkSize, 8); + } + } + } + } + +#ifndef DR_WAV_NO_STDIO + // If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file() + // was used by looking at the onRead and onSeek callbacks. + if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) { + fclose((FILE*)pWav->pUserData); + } +#endif +} + + +drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData) +{ + drwav* pWav = (drwav*)DRWAV_MALLOC(sizeof(*pWav)); + if (pWav == NULL) { + return NULL; + } + + if (!drwav_init(pWav, onRead, onSeek, pUserData)) { + DRWAV_FREE(pWav); + return NULL; + } + + return pWav; +} + +drwav* drwav_open_write(const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData) +{ + drwav* pWav = (drwav*)DRWAV_MALLOC(sizeof(*pWav)); + if (pWav == NULL) { + return NULL; + } + + if (!drwav_init_write(pWav, pFormat, onWrite, onSeek, pUserData)) { + DRWAV_FREE(pWav); + return NULL; + } + + return pWav; +} + +void drwav_close(drwav* pWav) +{ + drwav_uninit(pWav); + DRWAV_FREE(pWav); +} + + +size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) +{ + if (pWav == NULL || bytesToRead == 0 || pBufferOut == NULL) { + return 0; + } + + if (bytesToRead > pWav->bytesRemaining) { + bytesToRead = (size_t)pWav->bytesRemaining; + } + + size_t bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); + + pWav->bytesRemaining -= bytesRead; + return bytesRead; +} + +drwav_uint64 drwav_read(drwav* pWav, drwav_uint64 samplesToRead, void* pBufferOut) +{ + if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) { + return 0; + } + + // Cannot use this function for compressed formats. + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + return 0; + } + + // Don't try to read more samples than can potentially fit in the output buffer. + if (samplesToRead * pWav->bytesPerSample > SIZE_MAX) { + samplesToRead = SIZE_MAX / pWav->bytesPerSample; + } + + size_t bytesRead = drwav_read_raw(pWav, (size_t)(samplesToRead * pWav->bytesPerSample), pBufferOut); + return bytesRead / pWav->bytesPerSample; +} + +drwav_bool32 drwav_seek_to_first_sample(drwav* pWav) +{ + if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) { + return DRWAV_FALSE; + } + + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + pWav->compressed.iCurrentSample = 0; + } + + pWav->bytesRemaining = pWav->dataChunkDataSize; + return DRWAV_TRUE; +} + +drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample) +{ + // Seeking should be compatible with wave files > 2GB. + + if (pWav == NULL || pWav->onSeek == NULL) { + return DRWAV_FALSE; + } + + // If there are no samples, just return DRWAV_TRUE without doing anything. + if (pWav->totalSampleCount == 0) { + return DRWAV_TRUE; + } + + // Make sure the sample is clamped. + if (sample >= pWav->totalSampleCount) { + sample = pWav->totalSampleCount - 1; + } + + + // For compressed formats we just use a slow generic seek. If we are seeking forward we just seek forward. If we are going backwards we need + // to seek back to the start. + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + // TODO: This can be optimized. + if (sample > pWav->compressed.iCurrentSample) { + // Seeking forward - just move from the current position. + drwav_uint64 offset = sample - pWav->compressed.iCurrentSample; + + drwav_int16 devnull[2048]; + while (offset > 0) { + drwav_uint64 samplesToRead = sample; + if (samplesToRead > 2048) { + samplesToRead = 2048; + } + + drwav_uint64 samplesRead = drwav_read_s16(pWav, samplesToRead, devnull); + if (samplesRead != samplesToRead) { + return DRWAV_FALSE; + } + + offset -= samplesRead; + } + } else { + // Seeking backwards. Just use the fallback. + goto fallback; + } + } else { + drwav_uint64 totalSizeInBytes = pWav->totalSampleCount * pWav->bytesPerSample; + drwav_assert(totalSizeInBytes >= pWav->bytesRemaining); + + drwav_uint64 currentBytePos = totalSizeInBytes - pWav->bytesRemaining; + drwav_uint64 targetBytePos = sample * pWav->bytesPerSample; + + drwav_uint64 offset; + if (currentBytePos < targetBytePos) { + // Offset forwards. + offset = (targetBytePos - currentBytePos); + } else { + // Offset backwards. + if (!drwav_seek_to_first_sample(pWav)) { + return DRWAV_FALSE; + } + offset = targetBytePos; + } + + while (offset > 0) { + int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset); + if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + + pWav->bytesRemaining -= offset32; + offset -= offset32; + } + } + + return DRWAV_TRUE; + +fallback: + // This is a generic seek implementation that just continuously reads samples into a temporary buffer. This should work for all supported + // formats, but it is not efficient. This should be used as a fall back. + if (!drwav_seek_to_first_sample(pWav)) { + return DRWAV_FALSE; + } + + drwav_int16 devnull[2048]; + while (sample > 0) { + drwav_uint64 samplesToRead = sample; + if (samplesToRead > 2048) { + samplesToRead = 2048; + } + + drwav_uint64 samplesRead = drwav_read_s16(pWav, samplesToRead, devnull); + if (samplesRead != samplesToRead) { + return DRWAV_FALSE; + } + + sample -= samplesRead; + } + + return DRWAV_TRUE; +} + + +size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData) +{ + if (pWav == NULL || bytesToWrite == 0 || pData == NULL) { + return 0; + } + + size_t bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite); + pWav->dataChunkDataSize += bytesWritten; + + return bytesWritten; +} + +drwav_uint64 drwav_write(drwav* pWav, drwav_uint64 samplesToWrite, const void* pData) +{ + if (pWav == NULL || samplesToWrite == 0 || pData == NULL) { + return 0; + } + + drwav_uint64 bytesToWrite = ((samplesToWrite * pWav->bitsPerSample) / 8); + if (bytesToWrite > SIZE_MAX) { + return 0; + } + + size_t bytesWritten = drwav_write_raw(pWav, (size_t)bytesToWrite, pData); + return ((drwav_uint64)bytesWritten * 8) / pWav->bitsPerSample; +} + + +#ifndef DR_WAV_NO_CONVERSION_API +static unsigned short g_drwavAlawTable[256] = { + 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, + 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, + 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, + 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00, + 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58, + 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58, + 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960, + 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0, + 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80, + 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40, + 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00, + 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500, + 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8, + 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8, + 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, + 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 +}; + +static unsigned short g_drwavMulawTable[256] = { + 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, + 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, + 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, + 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844, + 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64, + 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74, + 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C, + 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000, + 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C, + 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C, + 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC, + 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC, + 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C, + 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C, + 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084, + 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 +}; + +static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn) +{ + return (short)g_drwavAlawTable[sampleIn]; +} + +static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) +{ + return (short)g_drwavMulawTable[sampleIn]; +} + + + +static void drwav__pcm_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) +{ + // Special case for 8-bit sample data because it's treated as unsigned. + if (bytesPerSample == 1) { + drwav_u8_to_s16(pOut, pIn, totalSampleCount); + return; + } + + + // Slightly more optimal implementation for common formats. + if (bytesPerSample == 2) { + for (unsigned int i = 0; i < totalSampleCount; ++i) { + *pOut++ = ((drwav_int16*)pIn)[i]; + } + return; + } + if (bytesPerSample == 3) { + drwav_s24_to_s16(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 4) { + drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount); + return; + } + + + // Generic, slow converter. + for (unsigned int i = 0; i < totalSampleCount; ++i) { + unsigned short sample = 0; + unsigned short shift = (8 - bytesPerSample) * 8; + for (unsigned short j = 0; j < bytesPerSample && j < 2; ++j) { + sample |= (unsigned short)(pIn[j]) << shift; + shift += 8; + } + + pIn += bytesPerSample; + *pOut++ = sample; + } +} + +static void drwav__ieee_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) +{ + if (bytesPerSample == 4) { + drwav_f32_to_s16(pOut, (float*)pIn, totalSampleCount); + return; + } else { + drwav_f64_to_s16(pOut, (double*)pIn, totalSampleCount); + return; + } +} + +drwav_uint64 drwav_read_s16__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +{ + // Fast path. + if (pWav->bytesPerSample == 2) { + return drwav_read(pWav, samplesToRead, pBufferOut); + } + + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +{ + drwav_assert(pWav != NULL); + drwav_assert(samplesToRead > 0); + drwav_assert(pBufferOut != NULL); + + // TODO: Lots of room for optimization here. + + drwav_uint64 totalSamplesRead = 0; + + while (samplesToRead > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { + // If there are no cached samples we need to load a new block. + if (pWav->msadpcm.cachedSampleCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) { + if (pWav->channels == 1) { + // Mono. + drwav_uint8 header[7]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalSamplesRead; + } + pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + pWav->msadpcm.predictor[0] = header[0]; + pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 1); + pWav->msadpcm.prevSamples[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 3); + pWav->msadpcm.prevSamples[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 5); + pWav->msadpcm.cachedSamples[2] = pWav->msadpcm.prevSamples[0][0]; + pWav->msadpcm.cachedSamples[3] = pWav->msadpcm.prevSamples[0][1]; + pWav->msadpcm.cachedSampleCount = 2; + } else { + // Stereo. + drwav_uint8 header[14]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalSamplesRead; + } + pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + pWav->msadpcm.predictor[0] = header[0]; + pWav->msadpcm.predictor[1] = header[1]; + pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 2); + pWav->msadpcm.delta[1] = drwav__bytes_to_s16(header + 4); + pWav->msadpcm.prevSamples[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 6); + pWav->msadpcm.prevSamples[1][1] = (drwav_int32)drwav__bytes_to_s16(header + 8); + pWav->msadpcm.prevSamples[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 10); + pWav->msadpcm.prevSamples[1][0] = (drwav_int32)drwav__bytes_to_s16(header + 12); + + pWav->msadpcm.cachedSamples[0] = pWav->msadpcm.prevSamples[0][0]; + pWav->msadpcm.cachedSamples[1] = pWav->msadpcm.prevSamples[1][0]; + pWav->msadpcm.cachedSamples[2] = pWav->msadpcm.prevSamples[0][1]; + pWav->msadpcm.cachedSamples[3] = pWav->msadpcm.prevSamples[1][1]; + pWav->msadpcm.cachedSampleCount = 4; + } + } + + // Output anything that's cached. + while (samplesToRead > 0 && pWav->msadpcm.cachedSampleCount > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { + pBufferOut[0] = (drwav_int16)pWav->msadpcm.cachedSamples[drwav_countof(pWav->msadpcm.cachedSamples) - pWav->msadpcm.cachedSampleCount]; + pWav->msadpcm.cachedSampleCount -= 1; + + pBufferOut += 1; + samplesToRead -= 1; + totalSamplesRead += 1; + pWav->compressed.iCurrentSample += 1; + } + + if (samplesToRead == 0) { + return totalSamplesRead; + } + + + // If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next + // loop iteration which will trigger the loading of a new block. + if (pWav->msadpcm.cachedSampleCount == 0) { + if (pWav->msadpcm.bytesRemainingInBlock == 0) { + continue; + } else { + drwav_uint8 nibbles; + if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) { + return totalSamplesRead; + } + pWav->msadpcm.bytesRemainingInBlock -= 1; + + // TODO: Optimize away these if statements. + drwav_int32 nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; } + drwav_int32 nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; } + + static drwav_int32 adaptationTable[] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 + }; + static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; + static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; + + if (pWav->channels == 1) { + // Mono. + drwav_int32 newSample0; + newSample0 = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + newSample0 += nibble0 * pWav->msadpcm.delta[0]; + newSample0 = drwav_clamp(newSample0, -32768, 32767); + + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + + pWav->msadpcm.prevSamples[0][0] = pWav->msadpcm.prevSamples[0][1]; + pWav->msadpcm.prevSamples[0][1] = newSample0; + + + drwav_int32 newSample1; + newSample1 = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + newSample1 += nibble1 * pWav->msadpcm.delta[0]; + newSample1 = drwav_clamp(newSample1, -32768, 32767); + + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + + pWav->msadpcm.prevSamples[0][0] = pWav->msadpcm.prevSamples[0][1]; + pWav->msadpcm.prevSamples[0][1] = newSample1; + + + pWav->msadpcm.cachedSamples[2] = newSample0; + pWav->msadpcm.cachedSamples[3] = newSample1; + pWav->msadpcm.cachedSampleCount = 2; + } else { + // Stereo. + + // Left. + drwav_int32 newSample0; + newSample0 = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + newSample0 += nibble0 * pWav->msadpcm.delta[0]; + newSample0 = drwav_clamp(newSample0, -32768, 32767); + + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + + pWav->msadpcm.prevSamples[0][0] = pWav->msadpcm.prevSamples[0][1]; + pWav->msadpcm.prevSamples[0][1] = newSample0; + + + // Right. + drwav_int32 newSample1; + newSample1 = ((pWav->msadpcm.prevSamples[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevSamples[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8; + newSample1 += nibble1 * pWav->msadpcm.delta[1]; + newSample1 = drwav_clamp(newSample1, -32768, 32767); + + pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8; + if (pWav->msadpcm.delta[1] < 16) { + pWav->msadpcm.delta[1] = 16; + } + + pWav->msadpcm.prevSamples[1][0] = pWav->msadpcm.prevSamples[1][1]; + pWav->msadpcm.prevSamples[1][1] = newSample1; + + pWav->msadpcm.cachedSamples[2] = newSample0; + pWav->msadpcm.cachedSamples[3] = newSample1; + pWav->msadpcm.cachedSampleCount = 2; + } + } + } + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +{ + drwav_assert(pWav != NULL); + drwav_assert(samplesToRead > 0); + drwav_assert(pBufferOut != NULL); + + // TODO: Lots of room for optimization here. + + drwav_uint64 totalSamplesRead = 0; + + while (samplesToRead > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { + // If there are no cached samples we need to load a new block. + if (pWav->ima.cachedSampleCount == 0 && pWav->ima.bytesRemainingInBlock == 0) { + if (pWav->channels == 1) { + // Mono. + drwav_uint8 header[4]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalSamplesRead; + } + pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0); + pWav->ima.stepIndex[0] = header[2]; + pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - 1] = pWav->ima.predictor[0]; + pWav->ima.cachedSampleCount = 1; + } else { + // Stereo. + drwav_uint8 header[8]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalSamplesRead; + } + pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0); + pWav->ima.stepIndex[0] = header[2]; + pWav->ima.predictor[1] = drwav__bytes_to_s16(header + 4); + pWav->ima.stepIndex[1] = header[6]; + + pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - 2] = pWav->ima.predictor[0]; + pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - 1] = pWav->ima.predictor[1]; + pWav->ima.cachedSampleCount = 2; + } + } + + // Output anything that's cached. + while (samplesToRead > 0 && pWav->ima.cachedSampleCount > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { + pBufferOut[0] = (drwav_int16)pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - pWav->ima.cachedSampleCount]; + pWav->ima.cachedSampleCount -= 1; + + pBufferOut += 1; + samplesToRead -= 1; + totalSamplesRead += 1; + pWav->compressed.iCurrentSample += 1; + } + + if (samplesToRead == 0) { + return totalSamplesRead; + } + + // If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next + // loop iteration which will trigger the loading of a new block. + if (pWav->ima.cachedSampleCount == 0) { + if (pWav->ima.bytesRemainingInBlock == 0) { + continue; + } else { + static drwav_int32 indexTable[16] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 + }; + + static drwav_int32 stepTable[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 + }; + + // From what I can tell with stereo streams, it looks like every 4 bytes (8 samples) is for one channel. So it goes 4 bytes for the + // left channel, 4 bytes for the right channel. + pWav->ima.cachedSampleCount = 8 * pWav->channels; + for (drwav_uint32 iChannel = 0; iChannel < pWav->channels; ++iChannel) { + drwav_uint8 nibbles[4]; + if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) { + return totalSamplesRead; + } + pWav->ima.bytesRemainingInBlock -= 4; + + for (drwav_uint32 iByte = 0; iByte < 4; ++iByte) { + drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0); + drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4); + + drwav_int32 step = stepTable[pWav->ima.stepIndex[iChannel]]; + drwav_int32 predictor = pWav->ima.predictor[iChannel]; + + drwav_int32 diff = step >> 3; + if (nibble0 & 1) diff += step >> 2; + if (nibble0 & 2) diff += step >> 1; + if (nibble0 & 4) diff += step; + if (nibble0 & 8) diff = -diff; + + predictor = drwav_clamp(predictor + diff, -32768, 32767); + pWav->ima.predictor[iChannel] = predictor; + pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1); + pWav->ima.cachedSamples[(drwav_countof(pWav->ima.cachedSamples) - pWav->ima.cachedSampleCount) + (iByte*2+0)*pWav->channels + iChannel] = predictor; + + + step = stepTable[pWav->ima.stepIndex[iChannel]]; + predictor = pWav->ima.predictor[iChannel]; + + diff = step >> 3; + if (nibble1 & 1) diff += step >> 2; + if (nibble1 & 2) diff += step >> 1; + if (nibble1 & 4) diff += step; + if (nibble1 & 8) diff = -diff; + + predictor = drwav_clamp(predictor + diff, -32768, 32767); + pWav->ima.predictor[iChannel] = predictor; + pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1); + pWav->ima.cachedSamples[(drwav_countof(pWav->ima.cachedSamples) - pWav->ima.cachedSampleCount) + (iByte*2+1)*pWav->channels + iChannel] = predictor; + } + } + } + } + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s16__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s16__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s16__mulaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s16(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +{ + if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) { + return 0; + } + + // Don't try to read more samples than can potentially fit in the output buffer. + if (samplesToRead * sizeof(drwav_int16) > SIZE_MAX) { + samplesToRead = SIZE_MAX / sizeof(drwav_int16); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_s16__pcm(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_s16__msadpcm(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_s16__ieee(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_s16__alaw(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_s16__mulaw(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_s16__ima(pWav, samplesToRead, pBufferOut); + } + + return 0; +} + +void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + int r; + for (size_t i = 0; i < sampleCount; ++i) { + int x = pIn[i]; + r = x - 128; + r = r << 8; + pOut[i] = (short)r; + } +} + +void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + int r; + for (size_t i = 0; i < sampleCount; ++i) { + int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8; + r = x >> 8; + pOut[i] = (short)r; + } +} + +void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount) +{ + int r; + for (size_t i = 0; i < sampleCount; ++i) { + int x = pIn[i]; + r = x >> 16; + pOut[i] = (short)r; + } +} + +void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount) +{ + int r; + for (size_t i = 0; i < sampleCount; ++i) { + float x = pIn[i]; + float c; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + c = c + 1; + r = (int)(c * 32767.5f); + r = r - 32768; + pOut[i] = (short)r; + } +} + +void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount) +{ + int r; + for (size_t i = 0; i < sampleCount; ++i) { + double x = pIn[i]; + double c; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + c = c + 1; + r = (int)(c * 32767.5); + r = r - 32768; + pOut[i] = (short)r; + } +} + +void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + for (size_t i = 0; i < sampleCount; ++i) { + pOut[i] = drwav__alaw_to_s16(pIn[i]); + } +} + +void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + for (size_t i = 0; i < sampleCount; ++i) { + pOut[i] = drwav__mulaw_to_s16(pIn[i]); + } +} + + + +static void drwav__pcm_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned short bytesPerSample) +{ + // Special case for 8-bit sample data because it's treated as unsigned. + if (bytesPerSample == 1) { + drwav_u8_to_f32(pOut, pIn, sampleCount); + return; + } + + // Slightly more optimal implementation for common formats. + if (bytesPerSample == 2) { + drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount); + return; + } + if (bytesPerSample == 3) { + drwav_s24_to_f32(pOut, pIn, sampleCount); + return; + } + if (bytesPerSample == 4) { + drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount); + return; + } + + // Generic, slow converter. + for (unsigned int i = 0; i < sampleCount; ++i) { + unsigned int sample = 0; + unsigned int shift = (8 - bytesPerSample) * 8; + for (unsigned short j = 0; j < bytesPerSample && j < 4; ++j) { + sample |= (unsigned int)(pIn[j]) << shift; + shift += 8; + } + + pIn += bytesPerSample; + *pOut++ = (float)((int)sample / 2147483648.0); + } +} + +static void drwav__ieee_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned short bytesPerSample) +{ + if (bytesPerSample == 4) { + for (unsigned int i = 0; i < sampleCount; ++i) { + *pOut++ = ((float*)pIn)[i]; + } + return; + } else { + drwav_f64_to_f32(pOut, (double*)pIn, sampleCount); + return; + } +} + + +drwav_uint64 drwav_read_f32__pcm(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +{ + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); + pBufferOut += samplesRead; + + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_f32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +{ + // We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't + // want to duplicate that code. + drwav_uint64 totalSamplesRead = 0; + drwav_int16 samples16[2048]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16); + if (samplesRead == 0) { + break; + } + + drwav_s16_to_f32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_f32__ima(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +{ + // We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't + // want to duplicate that code. + drwav_uint64 totalSamplesRead = 0; + drwav_int16 samples16[2048]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16); + if (samplesRead == 0) { + break; + } + + drwav_s16_to_f32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_f32__ieee(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +{ + // Fast path. + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bytesPerSample == 4) { + return drwav_read(pWav, samplesToRead, pBufferOut); + } + + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_f32__alaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +{ + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_f32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +{ + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_f32(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +{ + if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) { + return 0; + } + + // Don't try to read more samples than can potentially fit in the output buffer. + if (samplesToRead * sizeof(float) > SIZE_MAX) { + samplesToRead = SIZE_MAX / sizeof(float); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_f32__pcm(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_f32__msadpcm(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_f32__ieee(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_f32__alaw(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_f32__mulaw(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_f32__ima(pWav, samplesToRead, pBufferOut); + } + + return 0; +} + +void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + +#ifdef DR_WAV_LIBSNDFILE_COMPAT + // It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears + // libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note + // the divisor of 256 vs 255). I use libsndfile as a benchmark for testing, so I'm therefore leaving this block here just for my automated + // correctness testing. This is disabled by default. + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = (pIn[i] / 256.0f) * 2 - 1; + } +#else + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = (pIn[i] / 255.0f) * 2 - 1; + } +#endif +} + +void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = pIn[i] / 32768.0f; + } +} + +void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + unsigned int s0 = pIn[i*3 + 0]; + unsigned int s1 = pIn[i*3 + 1]; + unsigned int s2 = pIn[i*3 + 2]; + + int sample32 = (int)((s0 << 8) | (s1 << 16) | (s2 << 24)); + *pOut++ = (float)(sample32 / 2147483648.0); + } +} + +void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = (float)(pIn[i] / 2147483648.0); + } +} + +void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = (float)pIn[i]; + } +} + +void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f; + } +} + +void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f; + } +} + + + +static void drwav__pcm_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) +{ + // Special case for 8-bit sample data because it's treated as unsigned. + if (bytesPerSample == 1) { + drwav_u8_to_s32(pOut, pIn, totalSampleCount); + return; + } + + // Slightly more optimal implementation for common formats. + if (bytesPerSample == 2) { + drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount); + return; + } + if (bytesPerSample == 3) { + drwav_s24_to_s32(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 4) { + for (unsigned int i = 0; i < totalSampleCount; ++i) { + *pOut++ = ((drwav_int32*)pIn)[i]; + } + return; + } + + // Generic, slow converter. + for (unsigned int i = 0; i < totalSampleCount; ++i) { + unsigned int sample = 0; + unsigned int shift = (8 - bytesPerSample) * 8; + for (unsigned short j = 0; j < bytesPerSample && j < 4; ++j) { + sample |= (unsigned int)(pIn[j]) << shift; + shift += 8; + } + + pIn += bytesPerSample; + *pOut++ = sample; + } +} + +static void drwav__ieee_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) +{ + if (bytesPerSample == 4) { + drwav_f32_to_s32(pOut, (float*)pIn, totalSampleCount); + return; + } else { + drwav_f64_to_s32(pOut, (double*)pIn, totalSampleCount); + return; + } +} + + +drwav_uint64 drwav_read_s32__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +{ + // Fast path. + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bytesPerSample == 4) { + return drwav_read(pWav, samplesToRead, pBufferOut); + } + + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +{ + // We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't + // want to duplicate that code. + drwav_uint64 totalSamplesRead = 0; + drwav_int16 samples16[2048]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16); + if (samplesRead == 0) { + break; + } + + drwav_s16_to_s32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s32__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +{ + // We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't + // want to duplicate that code. + drwav_uint64 totalSamplesRead = 0; + drwav_int16 samples16[2048]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16); + if (samplesRead == 0) { + break; + } + + drwav_s16_to_s32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s32__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s32__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + +drwav_uint64 drwav_read_s32(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +{ + if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) { + return 0; + } + + // Don't try to read more samples than can potentially fit in the output buffer. + if (samplesToRead * sizeof(drwav_int32) > SIZE_MAX) { + samplesToRead = SIZE_MAX / sizeof(drwav_int32); + } + + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_s32__pcm(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_s32__msadpcm(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_s32__ieee(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_s32__alaw(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_s32__mulaw(pWav, samplesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_s32__ima(pWav, samplesToRead, pBufferOut); + } + + return 0; +} + +void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = ((int)pIn[i] - 128) << 24; + } +} + +void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = pIn[i] << 16; + } +} + +void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + unsigned int s0 = pIn[i*3 + 0]; + unsigned int s1 = pIn[i*3 + 1]; + unsigned int s2 = pIn[i*3 + 2]; + + drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24)); + *pOut++ = sample32; + } +} + +void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); + } +} + +void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); + } +} + +void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i = 0; i < sampleCount; ++i) { + *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16; + } +} + +void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + if (pOut == NULL || pIn == NULL) { + return; + } + + for (size_t i= 0; i < sampleCount; ++i) { + *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16; + } +} + + + +drwav_int16* drwav__read_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + drwav_assert(pWav != NULL); + + drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(drwav_int16); + if (sampleDataSize > SIZE_MAX) { + drwav_uninit(pWav); + return NULL; // File's too big. + } + + drwav_int16* pSampleData = (drwav_int16*)DRWAV_MALLOC((size_t)sampleDataSize); // <-- Safe cast due to the check above. + if (pSampleData == NULL) { + drwav_uninit(pWav); + return NULL; // Failed to allocate memory. + } + + drwav_uint64 samplesRead = drwav_read_s16(pWav, (size_t)pWav->totalSampleCount, pSampleData); + if (samplesRead != pWav->totalSampleCount) { + DRWAV_FREE(pSampleData); + drwav_uninit(pWav); + return NULL; // There was an error reading the samples. + } + + drwav_uninit(pWav); + + if (sampleRate) *sampleRate = pWav->sampleRate; + if (channels) *channels = pWav->channels; + if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount; + return pSampleData; +} + +float* drwav__read_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + drwav_assert(pWav != NULL); + + drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(float); + if (sampleDataSize > SIZE_MAX) { + drwav_uninit(pWav); + return NULL; // File's too big. + } + + float* pSampleData = (float*)DRWAV_MALLOC((size_t)sampleDataSize); // <-- Safe cast due to the check above. + if (pSampleData == NULL) { + drwav_uninit(pWav); + return NULL; // Failed to allocate memory. + } + + drwav_uint64 samplesRead = drwav_read_f32(pWav, (size_t)pWav->totalSampleCount, pSampleData); + if (samplesRead != pWav->totalSampleCount) { + DRWAV_FREE(pSampleData); + drwav_uninit(pWav); + return NULL; // There was an error reading the samples. + } + + drwav_uninit(pWav); + + if (sampleRate) *sampleRate = pWav->sampleRate; + if (channels) *channels = pWav->channels; + if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount; + return pSampleData; +} + +drwav_int32* drwav__read_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + drwav_assert(pWav != NULL); + + drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(drwav_int32); + if (sampleDataSize > SIZE_MAX) { + drwav_uninit(pWav); + return NULL; // File's too big. + } + + drwav_int32* pSampleData = (drwav_int32*)DRWAV_MALLOC((size_t)sampleDataSize); // <-- Safe cast due to the check above. + if (pSampleData == NULL) { + drwav_uninit(pWav); + return NULL; // Failed to allocate memory. + } + + drwav_uint64 samplesRead = drwav_read_s32(pWav, (size_t)pWav->totalSampleCount, pSampleData); + if (samplesRead != pWav->totalSampleCount) { + DRWAV_FREE(pSampleData); + drwav_uninit(pWav); + return NULL; // There was an error reading the samples. + } + + drwav_uninit(pWav); + + if (sampleRate) *sampleRate = pWav->sampleRate; + if (channels) *channels = pWav->channels; + if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount; + return pSampleData; +} + + +drwav_int16* drwav_open_and_read_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drwav wav; + if (!drwav_init(&wav, onRead, onSeek, pUserData)) { + return NULL; + } + + return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount); +} + +float* drwav_open_and_read_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drwav wav; + if (!drwav_init(&wav, onRead, onSeek, pUserData)) { + return NULL; + } + + return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount); +} + +drwav_int32* drwav_open_and_read_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drwav wav; + if (!drwav_init(&wav, onRead, onSeek, pUserData)) { + return NULL; + } + + return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount); +} + +#ifndef DR_WAV_NO_STDIO +drwav_int16* drwav_open_and_read_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drwav wav; + if (!drwav_init_file(&wav, filename)) { + return NULL; + } + + return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount); +} + +float* drwav_open_and_read_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drwav wav; + if (!drwav_init_file(&wav, filename)) { + return NULL; + } + + return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount); +} + +drwav_int32* drwav_open_and_read_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drwav wav; + if (!drwav_init_file(&wav, filename)) { + return NULL; + } + + return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount); +} +#endif + +drwav_int16* drwav_open_and_read_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drwav wav; + if (!drwav_init_memory(&wav, data, dataSize)) { + return NULL; + } + + return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount); +} + +float* drwav_open_and_read_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drwav wav; + if (!drwav_init_memory(&wav, data, dataSize)) { + return NULL; + } + + return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount); +} + +drwav_int32* drwav_open_and_read_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +{ + if (sampleRate) *sampleRate = 0; + if (channels) *channels = 0; + if (totalSampleCount) *totalSampleCount = 0; + + drwav wav; + if (!drwav_init_memory(&wav, data, dataSize)) { + return NULL; + } + + return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount); +} +#endif //DR_WAV_NO_CONVERSION_API + + +void drwav_free(void* pDataReturnedByOpenAndRead) +{ + DRWAV_FREE(pDataReturnedByOpenAndRead); +} + +#endif //DR_WAV_IMPLEMENTATION + + +// REVISION HISTORY +// +// v0.7a - 2017-11-17 +// - Fix some GCC warnings. +// +// v0.7 - 2017-11-04 +// - Add writing APIs. +// +// v0.6 - 2017-08-16 +// - API CHANGE: Rename dr_* types to drwav_*. +// - Add support for custom implementations of malloc(), realloc(), etc. +// - Add support for Microsoft ADPCM. +// - Add support for IMA ADPCM (DVI, format code 0x11). +// - Optimizations to drwav_read_s16(). +// - Bug fixes. +// +// v0.5g - 2017-07-16 +// - Change underlying type for booleans to unsigned. +// +// v0.5f - 2017-04-04 +// - Fix a minor bug with drwav_open_and_read_s16() and family. +// +// v0.5e - 2016-12-29 +// - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this. +// - Minor fixes to documentation. +// +// v0.5d - 2016-12-28 +// - Use drwav_int*/drwav_uint* sized types to improve compiler support. +// +// v0.5c - 2016-11-11 +// - Properly handle JUNK chunks that come before the FMT chunk. +// +// v0.5b - 2016-10-23 +// - A minor change to drwav_bool8 and drwav_bool32 types. +// +// v0.5a - 2016-10-11 +// - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering. +// - Improve A-law and mu-law efficiency. +// +// v0.5 - 2016-09-29 +// - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to +// keep it consistent with dr_audio and drwav_flac. +// +// v0.4b - 2016-09-18 +// - Fixed a typo in documentation. +// +// v0.4a - 2016-09-18 +// - Fixed a typo. +// - Change date format to ISO 8601 (YYYY-MM-DD) +// +// v0.4 - 2016-07-13 +// - API CHANGE. Make onSeek consistent with drwav_flac. +// - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with drwav_flac. +// - Added support for Sony Wave64. +// +// v0.3a - 2016-05-28 +// - API CHANGE. Return drwav_bool32 instead of int in onSeek callback. +// - Fixed a memory leak. +// +// v0.3 - 2016-05-22 +// - Lots of API changes for consistency. +// +// v0.2a - 2016-05-16 +// - Fixed Linux/GCC build. +// +// v0.2 - 2016-05-11 +// - Added support for reading data as signed 32-bit PCM for consistency with drwav_flac. +// +// v0.1a - 2016-05-07 +// - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize. +// +// v0.1 - 2016-05-04 +// - Initial versioned release. + + +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +*/ From 3b5a26099e0cde67084481eb6048058578b30a0c Mon Sep 17 00:00:00 2001 From: Ray San Date: Tue, 5 Dec 2017 14:01:35 +0100 Subject: [PATCH 065/139] Removed OpenAL Soft dependency on building OpenAL Soft backend is still available in audio module, I'm thinking if exposing it for building in some way or just left it there for advance users to switch to it manually in case of necessity... --- examples/Makefile | 55 +- release/libs/win32/mingw32/libraylib.a | Bin 671510 -> 958986 bytes src/CMakeLists.txt | 3 +- src/Makefile | 44 +- src/core.c | 30 +- src/external/include/AL/al.h | 656 -------------------- src/external/include/AL/alc.h | 237 -------- src/external/include/AL/alext.h | 466 --------------- src/external/include/AL/efx-creative.h | 3 - src/external/include/AL/efx-presets.h | 402 ------------- src/external/include/AL/efx.h | 761 ------------------------ src/external/include/AL_COPYING | 484 --------------- src/rglfw.c | 2 +- templates/advance_game/Makefile | 36 +- templates/advance_game/Makefile.Android | 4 +- 15 files changed, 65 insertions(+), 3118 deletions(-) delete mode 100644 src/external/include/AL/al.h delete mode 100644 src/external/include/AL/alc.h delete mode 100644 src/external/include/AL/alext.h delete mode 100644 src/external/include/AL/efx-creative.h delete mode 100644 src/external/include/AL/efx-presets.h delete mode 100644 src/external/include/AL/efx.h delete mode 100644 src/external/include/AL_COPYING diff --git a/examples/Makefile b/examples/Makefile index c5629090..44fd6ac3 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2017 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. @@ -33,15 +33,8 @@ ifeq ($(PLATFORM),PLATFORM_RPI) RAYLIB_PATH ?= /home/pi/raylib endif -# Library type used for raylib and OpenAL Soft: STATIC (.a) or SHARED (.so/.dll) -# NOTE: Libraries should be provided in the selected form +# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) RAYLIB_LIBTYPE ?= STATIC -OPENAL_LIBTYPE ?= STATIC - -# On PLATFORM_WEB force OpenAL Soft shared library -ifeq ($(PLATFORM),PLATFORM_WEB) - OPENAL_LIBTYPE = SHARED -endif # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -66,6 +59,12 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif endif endif +ifeq ($(PLATFORM),PLATFORM_RPI) + UNAMEOS=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX + endif +endif ifeq ($(PLATFORM),PLATFORM_RPI) # RPI cross-compiler @@ -140,7 +139,7 @@ endif # Define compiler flags: # -O1 defines optimization level -# -Og enable debugging +# -g enable debugging # -s strip unnecessary data from build # -Wall turns on most, but not all, compiler warnings # -std=c99 defines C language mode (standard C from 1999 revision) @@ -148,7 +147,7 @@ endif # -fgnu89-inline declaring inline functions support (GCC optimized) # -Wno-missing-braces ignore invalid warning (GCC bug 53119) # -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec -CFLAGS += -O1 -s -Wall -std=c99 -D_DEFAULT_SOURCE -fgnu89-inline -Wno-missing-braces +CFLAGS += -O1 -Wall -std=c99 -D_DEFAULT_SOURCE -fgnu89-inline -Wno-missing-braces # Additional flags for compiler (if desired) #CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes @@ -176,7 +175,7 @@ endif # Define include paths for required headers # NOTE: Several external required libraries (stb and others) -INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/release/include -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external +INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external # Define additional directories containing required header files ifeq ($(PLATFORM),PLATFORM_RPI) @@ -205,38 +204,28 @@ endif ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) # Libraries for Windows desktop compiling - # NOTE: GLFW3 and OpenAL Soft libraries should be installed - LDLIBS = -lraylib -lglfw3 -lopengl32 -lgdi32 - - # Define required flags and libs for OpenAL Soft STATIC/SHARED usage - # NOTE: ALLIBS flag only required for raylib Win32 SHARED library building - ifeq ($(OPENAL_LIBTYPE),STATIC) - LDLIBS += -lopenal32 -lwinmm - CFLAGS += -DAL_LIBTYPE_STATIC -Wl,-allow-multiple-definition - else - LDLIBS += -lopenal32dll - endif + LDLIBS = -lraylib -lopengl32 -lgdi32 # Required for physac examples LDLIBS += -static -lpthread endif ifeq ($(PLATFORM_OS),LINUX) # Libraries for Debian GNU/Linux desktop compiling - # NOTE: Required packages: libglfw3-dev libopenal-dev libegl1-mesa-dev - LDLIBS = -lraylib -lglfw3 -lGL -lopenal -lm -lpthread -ldl + # NOTE: Required packages: libegl1-mesa-dev + LDLIBS = -lraylib -lGL -lm -lpthread -ldl # On XWindow requires also below libraries LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor endif ifeq ($(PLATFORM_OS),OSX) # Libraries for OSX 10.9 desktop compiling - # NOTE: Required packages: libglfw3-dev libopenal-dev libegl1-mesa-dev - LDLIBS = -lraylib -lglfw -framework OpenGL -framework OpenAL -framework Cocoa + # NOTE: Required packages: libopenal-dev libegl1-mesa-dev + LDLIBS = -lraylib -framework OpenGL -framework OpenAL -framework Cocoa endif ifeq ($(PLATFORM_OS),FREEBSD) # Libraries for FreeBSD desktop compiling - # NOTE: Required packages: glfw openal-soft mesa-libs - LDLIBS = -lraylib -lglfw -lGL -lopenal -lpthread -lm + # NOTE: Required packages: mesa-libs + LDLIBS = -lraylib -lGL -lpthread -lm # On XWindow requires also below libraries LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor @@ -244,8 +233,8 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif ifeq ($(PLATFORM),PLATFORM_RPI) # Libraries for Raspberry Pi compiling - # NOTE: Required packages: libopenal1 - LDLIBS = -lraylib -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -lopenal + # NOTE: Required packages: libasound2-dev (ALSA) + LDLIBS = -lraylib -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -ldl endif ifeq ($(PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling @@ -363,10 +352,6 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) find . -type f -perm +ugo+x -delete rm -f *.o endif - ifeq ($(PLATFORM_OS),FREEBSD) - find . -type f -perm +ugo+x -delete - rm -f *.o - endif endif ifeq ($(PLATFORM),PLATFORM_RPI) find . -type f -executable -delete diff --git a/release/libs/win32/mingw32/libraylib.a b/release/libs/win32/mingw32/libraylib.a index da618b7b3cab1efb0fa4a4e06054663b297e0f3c..a597fb452f8b2240c1dbfd4ab38b9a666d341e61 100644 GIT binary patch literal 958986 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�EL! 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

65B_^K{f5Gq@ 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 W`|u`ZT3T9OVcPJ*eCyrI%KrnXLzlq- literal 671510 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

ihRvqcXB{X0$#(;=cmHKjv7pP7_9-s+w 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

yKvKVXjP7Jq#pod*sp$(qPnk%o9YC7}dJjly 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 G1pfza*p>DG diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cb8af48d..819dd1a4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,7 +27,6 @@ set_property(CACHE OPENGL_VERSION PROPERTY STRINGS "3.3" "2.1" "1.1" "ES 2.0") ### Config options ### include_directories(external/glfw/include) -include_directories(external/openal/include) # For use with AppVeyor on Windows # Translate the config options to what raylib wants if(${PLATFORM} MATCHES "Desktop") @@ -84,7 +83,9 @@ endif() # Get the sources together file(GLOB raylib_sources *.c) file(GLOB stb_vorbis external/stb_vorbis.c) +file(GLOB mini_al external/mini_al.c) set(sources ${raylib_sources} ${stb_vorbis}) +set(sources ${raylib_sources} ${mini_al}) # Which platform? if(${PLATFORM} MATCHES "PLATFORM_DESKTOP") diff --git a/src/Makefile b/src/Makefile index 2408f0f1..83aec5dd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,7 +4,7 @@ # # Platforms supported: # PLATFORM_DESKTOP: Windows (Win32, Win64) -# PLATFORM_DESKTOP: Linux +# PLATFORM_DESKTOP: Linux (32 and 64 bit) # PLATFORM_DESKTOP: OSX/macOS # PLATFORM_DESKTOP: FreeBSD # PLATFORM_ANDROID: Android (ARM, ARM64) @@ -14,7 +14,7 @@ # Many thanks to Milan Nikolic (@gen2brain) for implementing Android platform pipeline. # Many thanks to Emanuele Petriglia for his contribution on GNU/Linux pipeline. # -# Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +# Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. # In no event will the authors be held liable for any damages arising from @@ -43,17 +43,10 @@ # Define required raylib variables PLATFORM ?= PLATFORM_DESKTOP -RAYLIB_PATH ?= .. +RAYLIB_PATH = .. -# Library type used for raylib and OpenAL Soft: STATIC (.a) or SHARED (.so/.dll) -# NOTE: OpenAL Soft library should be provided in the selected form +# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) RAYLIB_LIBTYPE ?= STATIC -OPENAL_LIBTYPE ?= STATIC - -# On PLATFORM_WEB force OpenAL Soft shared library -ifeq ($(PLATFORM),PLATFORM_WEB) - OPENAL_LIBTYPE = SHARED -endif # Use cross-compiler for PLATFORM_RPI ifeq ($(PLATFORM),PLATFORM_RPI) @@ -269,14 +262,9 @@ ifeq ($(RAYLIB_LIBTYPE),SHARED) CFLAGS += -fPIC -DBUILD_LIBTYPE_SHARED endif -# Define required compilation flags for OpenAL Soft STATIC lib -ifeq ($(OPENAL_LIBTYPE),STATIC) - ALFLAGS = -DAL_LIBTYPE_STATIC -Wl,-allow-multiple-definition -endif - # Define include paths for required headers # NOTE: Several external required libraries (stb and others) -INCLUDE_PATHS = -I. -Iexternal -Iexternal/include -Iexternal/glfw/include +INCLUDE_PATHS = -I. -Iexternal -Iexternal/glfw/include ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),FREEBSD) @@ -310,7 +298,7 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID) # Library paths containing required libs LDFLAGS += -L. -Lsrc -L$(RAYLIB_RELEASE_PATH) - LDLIBS = -lopenal -llog -landroid -lEGL -lGLESv2 -lOpenSLES -latomic -lc -lm + LDLIBS = -llog -landroid -lEGL -lGLESv2 -lOpenSLES -latomic -lc -lm endif # Define all object files required with a wildcard @@ -327,6 +315,7 @@ OBJS = core.o \ text.o \ models.o \ audio.o \ + mini_al.o \ stb_vorbis.o \ utils.o @@ -357,16 +346,14 @@ ifeq ($(PLATFORM),PLATFORM_WEB) @echo "raylib library generated (libraylib.bc)!" else ifeq ($(RAYLIB_LIBTYPE),SHARED) - # NOTE: If using OpenAL Soft as static library, all its dependencies must be also linked in the shared library ifeq ($(PLATFORM_OS),WINDOWS) - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/raylib.dll $(OBJS) -L$(RAYLIB_RELEASE_PATH) -lgdi32 -lopenal32 -lwinmm -Wl,--out-implib,$(RAYLIB_RELEASE_PATH)/libraylibdll.a + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/raylib.dll $(OBJS) -L$(RAYLIB_RELEASE_PATH) -static-libgcc -lopengl32 -lgdi32 -Wl,--out-implib,$(RAYLIB_RELEASE_PATH)/libraylibdll.a @echo "raylib dynamic library (raylib.dll) and import library (libraylibdll.a) generated!" - @echo "expected OpenAL Soft static library linking" endif ifeq ($(PLATFORM_OS),LINUX) # Compile raylib to shared library version for GNU/Linux. # WARNING: you should type "make clean" before doing this target - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lGL -lopenal -lm -lpthread -ldl + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lGL -lm -lpthread -ldl @echo "raylib shared library generated (libraylib.so)!" endif ifeq ($(PLATFORM_OS),OSX) @@ -376,7 +363,7 @@ else endif ifeq ($(PLATFORM_OS),FREEBSD) # WARNING: you should type "gmake clean" before doing this target - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lGL -lopenal -lpthread + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lGL -lpthread @echo "raylib shared library generated (libraylib.so)!" endif ifeq ($(PLATFORM),PLATFORM_ANDROID) @@ -388,11 +375,6 @@ else @echo raylib library release path is $(RAYLIB_RELEASE_PATH) $(AR) rcs $(RAYLIB_RELEASE_PATH)/libraylib.a $(OBJS) @echo "raylib static library generated (libraylib.a)!" - ifeq ($(OPENAL_LIBTYPE),STATIC) - @echo "expected OpenAL Soft static library linking" - else - @echo "expected OpenAL Soft shared library linking" - endif endif endif @@ -428,7 +410,11 @@ models.o : models.c raylib.h rlgl.h raymath.h # Compile audio module audio.o : audio.c raylib.h - $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) $(ALFLAGS) + $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) + +# Compile mini_al audio library +mini_al.o : external/mini_al.c external/mini_al.h + $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) # Compile stb_vorbis library stb_vorbis.o: external/stb_vorbis.c external/stb_vorbis.h diff --git a/src/core.c b/src/core.c index b3dde142..cf8f0258 100644 --- a/src/core.c +++ b/src/core.c @@ -2,19 +2,20 @@ * * raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms * -* PLATFORMS SUPPORTED: -* - Windows (Win32, Win64) -* - Linux (tested on Ubuntu) -* - FreeBSD -* - OSX/macOS -* - Android (ARM, ARM64) -* - Raspberry Pi (Raspbian) -* - HTML5 (Chrome, Firefox) +* PLATFORMS SUPPORTED: +* PLATFORM_DESKTOP: Windows (Win32, Win64) +* PLATFORM_DESKTOP: Linux (32 and 64 bit) +* PLATFORM_DESKTOP: OSX/macOS +* PLATFORM_DESKTOP: FreeBSD +* PLATFORM_ANDROID: Android (ARM, ARM64) +* PLATFORM_RPI: Raspberry Pi (Raspbian) +* PLATFORM_WEB: HTML5 (Chrome, Firefox) +* PLATFORM_UWP: Universal Windows Platform * * CONFIGURATION: * * #define PLATFORM_DESKTOP -* Windowing and input system configured for desktop platforms: Windows, Linux, OSX, FreeBSD (managed by GLFW3 library) +* Windowing and input system configured for desktop platforms: Windows, Linux, OSX, FreeBSD * NOTE: Oculus Rift CV1 requires PLATFORM_DESKTOP for mirror rendering - View [rlgl] module to enable it * * #define PLATFORM_ANDROID @@ -22,8 +23,8 @@ * NOTE: OpenGL ES 2.0 is required and graphic device is managed by EGL * * #define PLATFORM_RPI -* Windowing and input system configured for Raspberry Pi (tested on Raspbian), graphic device is managed by EGL -* and inputs are processed is raw mode, reading from /dev/input/ +* Windowing and input system configured for Raspberry Pi i native mode (no X.org required, tested on Raspbian), +* graphic device is managed by EGL and inputs are processed is raw mode, reading from /dev/input/ * * #define PLATFORM_WEB * Windowing and input system configured for HTML5 (run on browser), code converted from C to asm.js @@ -49,15 +50,15 @@ * Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() * * DEPENDENCIES: -* GLFW3 - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX) -* raymath - 3D math functionality (Vector3, Matrix, Quaternion) +* rglfw - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX. FreeBSD) +* raymath - 3D math functionality (Vector2, Vector3, Matrix, Quaternion) * camera - Multiple 3D camera modes (free, orbital, 1st person, 3rd person) * gestures - Gestures system for touch-ready devices (or simulated from mouse inputs) * * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -152,7 +153,6 @@ //#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version! #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) - // NOTE: Those functions require linking with winmm library __stdcall unsigned int timeBeginPeriod(unsigned int uPeriod); __stdcall unsigned int timeEndPeriod(unsigned int uPeriod); #endif diff --git a/src/external/include/AL/al.h b/src/external/include/AL/al.h deleted file mode 100644 index 413b3833..00000000 --- a/src/external/include/AL/al.h +++ /dev/null @@ -1,656 +0,0 @@ -#ifndef AL_AL_H -#define AL_AL_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#ifndef AL_API - #if defined(AL_LIBTYPE_STATIC) - #define AL_API - #elif defined(_WIN32) - #define AL_API __declspec(dllimport) - #else - #define AL_API extern - #endif -#endif - -#if defined(_WIN32) - #define AL_APIENTRY __cdecl -#else - #define AL_APIENTRY -#endif - - -/** Deprecated macro. */ -#define OPENAL -#define ALAPI AL_API -#define ALAPIENTRY AL_APIENTRY -#define AL_INVALID (-1) -#define AL_ILLEGAL_ENUM AL_INVALID_ENUM -#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION - -/** Supported AL version. */ -#define AL_VERSION_1_0 -#define AL_VERSION_1_1 - -/** 8-bit boolean */ -typedef char ALboolean; - -/** character */ -typedef char ALchar; - -/** signed 8-bit 2's complement integer */ -typedef signed char ALbyte; - -/** unsigned 8-bit integer */ -typedef unsigned char ALubyte; - -/** signed 16-bit 2's complement integer */ -typedef short ALshort; - -/** unsigned 16-bit integer */ -typedef unsigned short ALushort; - -/** signed 32-bit 2's complement integer */ -typedef int ALint; - -/** unsigned 32-bit integer */ -typedef unsigned int ALuint; - -/** non-negative 32-bit binary integer size */ -typedef int ALsizei; - -/** enumerated 32-bit value */ -typedef int ALenum; - -/** 32-bit IEEE754 floating-point */ -typedef float ALfloat; - -/** 64-bit IEEE754 floating-point */ -typedef double ALdouble; - -/** void type (for opaque pointers only) */ -typedef void ALvoid; - - -/* Enumerant values begin at column 50. No tabs. */ - -/** "no distance model" or "no buffer" */ -#define AL_NONE 0 - -/** Boolean False. */ -#define AL_FALSE 0 - -/** Boolean True. */ -#define AL_TRUE 1 - - -/** - * Relative source. - * Type: ALboolean - * Range: [AL_TRUE, AL_FALSE] - * Default: AL_FALSE - * - * Specifies if the Source has relative coordinates. - */ -#define AL_SOURCE_RELATIVE 0x202 - - -/** - * Inner cone angle, in degrees. - * Type: ALint, ALfloat - * Range: [0 - 360] - * Default: 360 - * - * The angle covered by the inner cone, where the source will not attenuate. - */ -#define AL_CONE_INNER_ANGLE 0x1001 - -/** - * Outer cone angle, in degrees. - * Range: [0 - 360] - * Default: 360 - * - * The angle covered by the outer cone, where the source will be fully - * attenuated. - */ -#define AL_CONE_OUTER_ANGLE 0x1002 - -/** - * Source pitch. - * Type: ALfloat - * Range: [0.5 - 2.0] - * Default: 1.0 - * - * A multiplier for the frequency (sample rate) of the source's buffer. - */ -#define AL_PITCH 0x1003 - -/** - * Source or listener position. - * Type: ALfloat[3], ALint[3] - * Default: {0, 0, 0} - * - * The source or listener location in three dimensional space. - * - * OpenAL, like OpenGL, uses a right handed coordinate system, where in a - * frontal default view X (thumb) points right, Y points up (index finger), and - * Z points towards the viewer/camera (middle finger). - * - * To switch from a left handed coordinate system, flip the sign on the Z - * coordinate. - */ -#define AL_POSITION 0x1004 - -/** - * Source direction. - * Type: ALfloat[3], ALint[3] - * Default: {0, 0, 0} - * - * Specifies the current direction in local space. - * A zero-length vector specifies an omni-directional source (cone is ignored). - */ -#define AL_DIRECTION 0x1005 - -/** - * Source or listener velocity. - * Type: ALfloat[3], ALint[3] - * Default: {0, 0, 0} - * - * Specifies the current velocity in local space. - */ -#define AL_VELOCITY 0x1006 - -/** - * Source looping. - * Type: ALboolean - * Range: [AL_TRUE, AL_FALSE] - * Default: AL_FALSE - * - * Specifies whether source is looping. - */ -#define AL_LOOPING 0x1007 - -/** - * Source buffer. - * Type: ALuint - * Range: any valid Buffer. - * - * Specifies the buffer to provide sound samples. - */ -#define AL_BUFFER 0x1009 - -/** - * Source or listener gain. - * Type: ALfloat - * Range: [0.0 - ] - * - * A value of 1.0 means unattenuated. Each division by 2 equals an attenuation - * of about -6dB. Each multiplicaton by 2 equals an amplification of about - * +6dB. - * - * A value of 0.0 is meaningless with respect to a logarithmic scale; it is - * silent. - */ -#define AL_GAIN 0x100A - -/** - * Minimum source gain. - * Type: ALfloat - * Range: [0.0 - 1.0] - * - * The minimum gain allowed for a source, after distance and cone attenation is - * applied (if applicable). - */ -#define AL_MIN_GAIN 0x100D - -/** - * Maximum source gain. - * Type: ALfloat - * Range: [0.0 - 1.0] - * - * The maximum gain allowed for a source, after distance and cone attenation is - * applied (if applicable). - */ -#define AL_MAX_GAIN 0x100E - -/** - * Listener orientation. - * Type: ALfloat[6] - * Default: {0.0, 0.0, -1.0, 0.0, 1.0, 0.0} - * - * Effectively two three dimensional vectors. The first vector is the front (or - * "at") and the second is the top (or "up"). - * - * Both vectors are in local space. - */ -#define AL_ORIENTATION 0x100F - -/** - * Source state (query only). - * Type: ALint - * Range: [AL_INITIAL, AL_PLAYING, AL_PAUSED, AL_STOPPED] - */ -#define AL_SOURCE_STATE 0x1010 - -/** Source state value. */ -#define AL_INITIAL 0x1011 -#define AL_PLAYING 0x1012 -#define AL_PAUSED 0x1013 -#define AL_STOPPED 0x1014 - -/** - * Source Buffer Queue size (query only). - * Type: ALint - * - * The number of buffers queued using alSourceQueueBuffers, minus the buffers - * removed with alSourceUnqueueBuffers. - */ -#define AL_BUFFERS_QUEUED 0x1015 - -/** - * Source Buffer Queue processed count (query only). - * Type: ALint - * - * The number of queued buffers that have been fully processed, and can be - * removed with alSourceUnqueueBuffers. - * - * Looping sources will never fully process buffers because they will be set to - * play again for when the source loops. - */ -#define AL_BUFFERS_PROCESSED 0x1016 - -/** - * Source reference distance. - * Type: ALfloat - * Range: [0.0 - ] - * Default: 1.0 - * - * The distance in units that no attenuation occurs. - * - * At 0.0, no distance attenuation ever occurs on non-linear attenuation models. - */ -#define AL_REFERENCE_DISTANCE 0x1020 - -/** - * Source rolloff factor. - * Type: ALfloat - * Range: [0.0 - ] - * Default: 1.0 - * - * Multiplier to exaggerate or diminish distance attenuation. - * - * At 0.0, no distance attenuation ever occurs. - */ -#define AL_ROLLOFF_FACTOR 0x1021 - -/** - * Outer cone gain. - * Type: ALfloat - * Range: [0.0 - 1.0] - * Default: 0.0 - * - * The gain attenuation applied when the listener is outside of the source's - * outer cone. - */ -#define AL_CONE_OUTER_GAIN 0x1022 - -/** - * Source maximum distance. - * Type: ALfloat - * Range: [0.0 - ] - * Default: +inf - * - * The distance above which the source is not attenuated any further with a - * clamped distance model, or where attenuation reaches 0.0 gain for linear - * distance models with a default rolloff factor. - */ -#define AL_MAX_DISTANCE 0x1023 - -/** Source buffer position, in seconds */ -#define AL_SEC_OFFSET 0x1024 -/** Source buffer position, in sample frames */ -#define AL_SAMPLE_OFFSET 0x1025 -/** Source buffer position, in bytes */ -#define AL_BYTE_OFFSET 0x1026 - -/** - * Source type (query only). - * Type: ALint - * Range: [AL_STATIC, AL_STREAMING, AL_UNDETERMINED] - * - * A Source is Static if a Buffer has been attached using AL_BUFFER. - * - * A Source is Streaming if one or more Buffers have been attached using - * alSourceQueueBuffers. - * - * A Source is Undetermined when it has the NULL buffer attached using - * AL_BUFFER. - */ -#define AL_SOURCE_TYPE 0x1027 - -/** Source type value. */ -#define AL_STATIC 0x1028 -#define AL_STREAMING 0x1029 -#define AL_UNDETERMINED 0x1030 - -/** Buffer format specifier. */ -#define AL_FORMAT_MONO8 0x1100 -#define AL_FORMAT_MONO16 0x1101 -#define AL_FORMAT_STEREO8 0x1102 -#define AL_FORMAT_STEREO16 0x1103 - -/** Buffer frequency (query only). */ -#define AL_FREQUENCY 0x2001 -/** Buffer bits per sample (query only). */ -#define AL_BITS 0x2002 -/** Buffer channel count (query only). */ -#define AL_CHANNELS 0x2003 -/** Buffer data size (query only). */ -#define AL_SIZE 0x2004 - -/** - * Buffer state. - * - * Not for public use. - */ -#define AL_UNUSED 0x2010 -#define AL_PENDING 0x2011 -#define AL_PROCESSED 0x2012 - - -/** No error. */ -#define AL_NO_ERROR 0 - -/** Invalid name paramater passed to AL call. */ -#define AL_INVALID_NAME 0xA001 - -/** Invalid enum parameter passed to AL call. */ -#define AL_INVALID_ENUM 0xA002 - -/** Invalid value parameter passed to AL call. */ -#define AL_INVALID_VALUE 0xA003 - -/** Illegal AL call. */ -#define AL_INVALID_OPERATION 0xA004 - -/** Not enough memory. */ -#define AL_OUT_OF_MEMORY 0xA005 - - -/** Context string: Vendor ID. */ -#define AL_VENDOR 0xB001 -/** Context string: Version. */ -#define AL_VERSION 0xB002 -/** Context string: Renderer ID. */ -#define AL_RENDERER 0xB003 -/** Context string: Space-separated extension list. */ -#define AL_EXTENSIONS 0xB004 - - -/** - * Doppler scale. - * Type: ALfloat - * Range: [0.0 - ] - * Default: 1.0 - * - * Scale for source and listener velocities. - */ -#define AL_DOPPLER_FACTOR 0xC000 -AL_API void AL_APIENTRY alDopplerFactor(ALfloat value); - -/** - * Doppler velocity (deprecated). - * - * A multiplier applied to the Speed of Sound. - */ -#define AL_DOPPLER_VELOCITY 0xC001 -AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value); - -/** - * Speed of Sound, in units per second. - * Type: ALfloat - * Range: [0.0001 - ] - * Default: 343.3 - * - * The speed at which sound waves are assumed to travel, when calculating the - * doppler effect. - */ -#define AL_SPEED_OF_SOUND 0xC003 -AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value); - -/** - * Distance attenuation model. - * Type: ALint - * Range: [AL_NONE, AL_INVERSE_DISTANCE, AL_INVERSE_DISTANCE_CLAMPED, - * AL_LINEAR_DISTANCE, AL_LINEAR_DISTANCE_CLAMPED, - * AL_EXPONENT_DISTANCE, AL_EXPONENT_DISTANCE_CLAMPED] - * Default: AL_INVERSE_DISTANCE_CLAMPED - * - * The model by which sources attenuate with distance. - * - * None - No distance attenuation. - * Inverse - Doubling the distance halves the source gain. - * Linear - Linear gain scaling between the reference and max distances. - * Exponent - Exponential gain dropoff. - * - * Clamped variations work like the non-clamped counterparts, except the - * distance calculated is clamped between the reference and max distances. - */ -#define AL_DISTANCE_MODEL 0xD000 -AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel); - -/** Distance model value. */ -#define AL_INVERSE_DISTANCE 0xD001 -#define AL_INVERSE_DISTANCE_CLAMPED 0xD002 -#define AL_LINEAR_DISTANCE 0xD003 -#define AL_LINEAR_DISTANCE_CLAMPED 0xD004 -#define AL_EXPONENT_DISTANCE 0xD005 -#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006 - -/** Renderer State management. */ -AL_API void AL_APIENTRY alEnable(ALenum capability); -AL_API void AL_APIENTRY alDisable(ALenum capability); -AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability); - -/** State retrieval. */ -AL_API const ALchar* AL_APIENTRY alGetString(ALenum param); -AL_API void AL_APIENTRY alGetBooleanv(ALenum param, ALboolean *values); -AL_API void AL_APIENTRY alGetIntegerv(ALenum param, ALint *values); -AL_API void AL_APIENTRY alGetFloatv(ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetDoublev(ALenum param, ALdouble *values); -AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum param); -AL_API ALint AL_APIENTRY alGetInteger(ALenum param); -AL_API ALfloat AL_APIENTRY alGetFloat(ALenum param); -AL_API ALdouble AL_APIENTRY alGetDouble(ALenum param); - -/** - * Error retrieval. - * - * Obtain the first error generated in the AL context since the last check. - */ -AL_API ALenum AL_APIENTRY alGetError(void); - -/** - * Extension support. - * - * Query for the presence of an extension, and obtain any appropriate function - * pointers and enum values. - */ -AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extname); -AL_API void* AL_APIENTRY alGetProcAddress(const ALchar *fname); -AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *ename); - - -/** Set Listener parameters */ -AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value); -AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values); -AL_API void AL_APIENTRY alListeneri(ALenum param, ALint value); -AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3); -AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values); - -/** Get Listener parameters */ -AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value); -AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetListeneri(ALenum param, ALint *value); -AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3); -AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint *values); - - -/** Create Source objects. */ -AL_API void AL_APIENTRY alGenSources(ALsizei n, ALuint *sources); -/** Delete Source objects. */ -AL_API void AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources); -/** Verify a handle is a valid Source. */ -AL_API ALboolean AL_APIENTRY alIsSource(ALuint source); - -/** Set Source parameters. */ -AL_API void AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value); -AL_API void AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -AL_API void AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values); -AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value); -AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); -AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values); - -/** Get Source parameters. */ -AL_API void AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value); -AL_API void AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -AL_API void AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value); -AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); -AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values); - - -/** Play, replay, or resume (if paused) a list of Sources */ -AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources); -/** Stop a list of Sources */ -AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources); -/** Rewind a list of Sources */ -AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources); -/** Pause a list of Sources */ -AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources); - -/** Play, replay, or resume a Source */ -AL_API void AL_APIENTRY alSourcePlay(ALuint source); -/** Stop a Source */ -AL_API void AL_APIENTRY alSourceStop(ALuint source); -/** Rewind a Source (set playback postiton to beginning) */ -AL_API void AL_APIENTRY alSourceRewind(ALuint source); -/** Pause a Source */ -AL_API void AL_APIENTRY alSourcePause(ALuint source); - -/** Queue buffers onto a source */ -AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers); -/** Unqueue processed buffers from a source */ -AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers); - - -/** Create Buffer objects */ -AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers); -/** Delete Buffer objects */ -AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers); -/** Verify a handle is a valid Buffer */ -AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer); - -/** Specifies the data to be copied into a buffer */ -AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq); - -/** Set Buffer parameters, */ -AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value); -AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values); -AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value); -AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); -AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values); - -/** Get Buffer parameters. */ -AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value); -AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value); -AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); -AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values); - -/** Pointer-to-function type, useful for dynamically getting AL entry points. */ -typedef void (AL_APIENTRY *LPALENABLE)(ALenum capability); -typedef void (AL_APIENTRY *LPALDISABLE)(ALenum capability); -typedef ALboolean (AL_APIENTRY *LPALISENABLED)(ALenum capability); -typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)(ALenum param); -typedef void (AL_APIENTRY *LPALGETBOOLEANV)(ALenum param, ALboolean *values); -typedef void (AL_APIENTRY *LPALGETINTEGERV)(ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALGETFLOATV)(ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETDOUBLEV)(ALenum param, ALdouble *values); -typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)(ALenum param); -typedef ALint (AL_APIENTRY *LPALGETINTEGER)(ALenum param); -typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)(ALenum param); -typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)(ALenum param); -typedef ALenum (AL_APIENTRY *LPALGETERROR)(void); -typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar *extname); -typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)(const ALchar *fname); -typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)(const ALchar *ename); -typedef void (AL_APIENTRY *LPALLISTENERF)(ALenum param, ALfloat value); -typedef void (AL_APIENTRY *LPALLISTENER3F)(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -typedef void (AL_APIENTRY *LPALLISTENERFV)(ALenum param, const ALfloat *values); -typedef void (AL_APIENTRY *LPALLISTENERI)(ALenum param, ALint value); -typedef void (AL_APIENTRY *LPALLISTENER3I)(ALenum param, ALint value1, ALint value2, ALint value3); -typedef void (AL_APIENTRY *LPALLISTENERIV)(ALenum param, const ALint *values); -typedef void (AL_APIENTRY *LPALGETLISTENERF)(ALenum param, ALfloat *value); -typedef void (AL_APIENTRY *LPALGETLISTENER3F)(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -typedef void (AL_APIENTRY *LPALGETLISTENERFV)(ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETLISTENERI)(ALenum param, ALint *value); -typedef void (AL_APIENTRY *LPALGETLISTENER3I)(ALenum param, ALint *value1, ALint *value2, ALint *value3); -typedef void (AL_APIENTRY *LPALGETLISTENERIV)(ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALGENSOURCES)(ALsizei n, ALuint *sources); -typedef void (AL_APIENTRY *LPALDELETESOURCES)(ALsizei n, const ALuint *sources); -typedef ALboolean (AL_APIENTRY *LPALISSOURCE)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEF)(ALuint source, ALenum param, ALfloat value); -typedef void (AL_APIENTRY *LPALSOURCE3F)(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -typedef void (AL_APIENTRY *LPALSOURCEFV)(ALuint source, ALenum param, const ALfloat *values); -typedef void (AL_APIENTRY *LPALSOURCEI)(ALuint source, ALenum param, ALint value); -typedef void (AL_APIENTRY *LPALSOURCE3I)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); -typedef void (AL_APIENTRY *LPALSOURCEIV)(ALuint source, ALenum param, const ALint *values); -typedef void (AL_APIENTRY *LPALGETSOURCEF)(ALuint source, ALenum param, ALfloat *value); -typedef void (AL_APIENTRY *LPALGETSOURCE3F)(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -typedef void (AL_APIENTRY *LPALGETSOURCEFV)(ALuint source, ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETSOURCEI)(ALuint source, ALenum param, ALint *value); -typedef void (AL_APIENTRY *LPALGETSOURCE3I)(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); -typedef void (AL_APIENTRY *LPALGETSOURCEIV)(ALuint source, ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALSOURCEPLAYV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCESTOPV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCEREWINDV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCEPLAY)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCESTOP)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEREWIND)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEPAUSE)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint source, ALsizei nb, const ALuint *buffers); -typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALsizei nb, ALuint *buffers); -typedef void (AL_APIENTRY *LPALGENBUFFERS)(ALsizei n, ALuint *buffers); -typedef void (AL_APIENTRY *LPALDELETEBUFFERS)(ALsizei n, const ALuint *buffers); -typedef ALboolean (AL_APIENTRY *LPALISBUFFER)(ALuint buffer); -typedef void (AL_APIENTRY *LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq); -typedef void (AL_APIENTRY *LPALBUFFERF)(ALuint buffer, ALenum param, ALfloat value); -typedef void (AL_APIENTRY *LPALBUFFER3F)(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -typedef void (AL_APIENTRY *LPALBUFFERFV)(ALuint buffer, ALenum param, const ALfloat *values); -typedef void (AL_APIENTRY *LPALBUFFERI)(ALuint buffer, ALenum param, ALint value); -typedef void (AL_APIENTRY *LPALBUFFER3I)(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); -typedef void (AL_APIENTRY *LPALBUFFERIV)(ALuint buffer, ALenum param, const ALint *values); -typedef void (AL_APIENTRY *LPALGETBUFFERF)(ALuint buffer, ALenum param, ALfloat *value); -typedef void (AL_APIENTRY *LPALGETBUFFER3F)(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -typedef void (AL_APIENTRY *LPALGETBUFFERFV)(ALuint buffer, ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETBUFFERI)(ALuint buffer, ALenum param, ALint *value); -typedef void (AL_APIENTRY *LPALGETBUFFER3I)(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); -typedef void (AL_APIENTRY *LPALGETBUFFERIV)(ALuint buffer, ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)(ALfloat value); -typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)(ALfloat value); -typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)(ALfloat value); -typedef void (AL_APIENTRY *LPALDISTANCEMODEL)(ALenum distanceModel); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -#endif /* AL_AL_H */ diff --git a/src/external/include/AL/alc.h b/src/external/include/AL/alc.h deleted file mode 100644 index 294e8b33..00000000 --- a/src/external/include/AL/alc.h +++ /dev/null @@ -1,237 +0,0 @@ -#ifndef AL_ALC_H -#define AL_ALC_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#ifndef ALC_API - #if defined(AL_LIBTYPE_STATIC) - #define ALC_API - #elif defined(_WIN32) - #define ALC_API __declspec(dllimport) - #else - #define ALC_API extern - #endif -#endif - -#if defined(_WIN32) - #define ALC_APIENTRY __cdecl -#else - #define ALC_APIENTRY -#endif - - -/** Deprecated macro. */ -#define ALCAPI ALC_API -#define ALCAPIENTRY ALC_APIENTRY -#define ALC_INVALID 0 - -/** Supported ALC version? */ -#define ALC_VERSION_0_1 1 - -/** Opaque device handle */ -typedef struct ALCdevice_struct ALCdevice; -/** Opaque context handle */ -typedef struct ALCcontext_struct ALCcontext; - -/** 8-bit boolean */ -typedef char ALCboolean; - -/** character */ -typedef char ALCchar; - -/** signed 8-bit 2's complement integer */ -typedef signed char ALCbyte; - -/** unsigned 8-bit integer */ -typedef unsigned char ALCubyte; - -/** signed 16-bit 2's complement integer */ -typedef short ALCshort; - -/** unsigned 16-bit integer */ -typedef unsigned short ALCushort; - -/** signed 32-bit 2's complement integer */ -typedef int ALCint; - -/** unsigned 32-bit integer */ -typedef unsigned int ALCuint; - -/** non-negative 32-bit binary integer size */ -typedef int ALCsizei; - -/** enumerated 32-bit value */ -typedef int ALCenum; - -/** 32-bit IEEE754 floating-point */ -typedef float ALCfloat; - -/** 64-bit IEEE754 floating-point */ -typedef double ALCdouble; - -/** void type (for opaque pointers only) */ -typedef void ALCvoid; - - -/* Enumerant values begin at column 50. No tabs. */ - -/** Boolean False. */ -#define ALC_FALSE 0 - -/** Boolean True. */ -#define ALC_TRUE 1 - -/** Context attribute: Hz. */ -#define ALC_FREQUENCY 0x1007 - -/** Context attribute: Hz. */ -#define ALC_REFRESH 0x1008 - -/** Context attribute: AL_TRUE or AL_FALSE. */ -#define ALC_SYNC 0x1009 - -/** Context attribute: requested Mono (3D) Sources. */ -#define ALC_MONO_SOURCES 0x1010 - -/** Context attribute: requested Stereo Sources. */ -#define ALC_STEREO_SOURCES 0x1011 - -/** No error. */ -#define ALC_NO_ERROR 0 - -/** Invalid device handle. */ -#define ALC_INVALID_DEVICE 0xA001 - -/** Invalid context handle. */ -#define ALC_INVALID_CONTEXT 0xA002 - -/** Invalid enum parameter passed to an ALC call. */ -#define ALC_INVALID_ENUM 0xA003 - -/** Invalid value parameter passed to an ALC call. */ -#define ALC_INVALID_VALUE 0xA004 - -/** Out of memory. */ -#define ALC_OUT_OF_MEMORY 0xA005 - - -/** Runtime ALC version. */ -#define ALC_MAJOR_VERSION 0x1000 -#define ALC_MINOR_VERSION 0x1001 - -/** Context attribute list properties. */ -#define ALC_ATTRIBUTES_SIZE 0x1002 -#define ALC_ALL_ATTRIBUTES 0x1003 - -/** String for the default device specifier. */ -#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 -/** - * String for the given device's specifier. - * - * If device handle is NULL, it is instead a null-char separated list of - * strings of known device specifiers (list ends with an empty string). - */ -#define ALC_DEVICE_SPECIFIER 0x1005 -/** String for space-separated list of ALC extensions. */ -#define ALC_EXTENSIONS 0x1006 - - -/** Capture extension */ -#define ALC_EXT_CAPTURE 1 -/** - * String for the given capture device's specifier. - * - * If device handle is NULL, it is instead a null-char separated list of - * strings of known capture device specifiers (list ends with an empty string). - */ -#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 -/** String for the default capture device specifier. */ -#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 -/** Number of sample frames available for capture. */ -#define ALC_CAPTURE_SAMPLES 0x312 - - -/** Enumerate All extension */ -#define ALC_ENUMERATE_ALL_EXT 1 -/** String for the default extended device specifier. */ -#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 -/** - * String for the given extended device's specifier. - * - * If device handle is NULL, it is instead a null-char separated list of - * strings of known extended device specifiers (list ends with an empty string). - */ -#define ALC_ALL_DEVICES_SPECIFIER 0x1013 - - -/** Context management. */ -ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint* attrlist); -ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context); -ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context); -ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context); -ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context); -ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void); -ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context); - -/** Device management. */ -ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename); -ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device); - - -/** - * Error support. - * - * Obtain the most recent Device error. - */ -ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device); - -/** - * Extension support. - * - * Query for the presence of an extension, and obtain any appropriate - * function pointers and enum values. - */ -ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname); -ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname); -ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname); - -/** Query function. */ -ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param); -ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); - -/** Capture function. */ -ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); -ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device); -ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device); -ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device); -ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); - -/** Pointer-to-function type, useful for dynamically getting ALC entry points. */ -typedef ALCcontext* (ALC_APIENTRY *LPALCCREATECONTEXT)(ALCdevice *device, const ALCint *attrlist); -typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)(ALCcontext *context); -typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)(ALCcontext *context); -typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)(ALCcontext *context); -typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)(ALCcontext *context); -typedef ALCcontext* (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)(void); -typedef ALCdevice* (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)(ALCcontext *context); -typedef ALCdevice* (ALC_APIENTRY *LPALCOPENDEVICE)(const ALCchar *devicename); -typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)(ALCdevice *device); -typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)(ALCdevice *device); -typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname); -typedef void* (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname); -typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname); -typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)(ALCdevice *device, ALCenum param); -typedef void (ALC_APIENTRY *LPALCGETINTEGERV)(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); -typedef ALCdevice* (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); -typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)(ALCdevice *device); -typedef void (ALC_APIENTRY *LPALCCAPTURESTART)(ALCdevice *device); -typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)(ALCdevice *device); -typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); - -#if defined(__cplusplus) -} -#endif - -#endif /* AL_ALC_H */ diff --git a/src/external/include/AL/alext.h b/src/external/include/AL/alext.h deleted file mode 100644 index 4b9a1553..00000000 --- a/src/external/include/AL/alext.h +++ /dev/null @@ -1,466 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2008 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#ifndef AL_ALEXT_H -#define AL_ALEXT_H - -#include -/* Define int64_t and uint64_t types */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#include -#elif defined(_WIN32) && defined(__GNUC__) -#include -#elif defined(_WIN32) -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -/* Fallback if nothing above works */ -#include -#endif - -#include "alc.h" -#include "al.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef AL_LOKI_IMA_ADPCM_format -#define AL_LOKI_IMA_ADPCM_format 1 -#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 -#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 -#endif - -#ifndef AL_LOKI_WAVE_format -#define AL_LOKI_WAVE_format 1 -#define AL_FORMAT_WAVE_EXT 0x10002 -#endif - -#ifndef AL_EXT_vorbis -#define AL_EXT_vorbis 1 -#define AL_FORMAT_VORBIS_EXT 0x10003 -#endif - -#ifndef AL_LOKI_quadriphonic -#define AL_LOKI_quadriphonic 1 -#define AL_FORMAT_QUAD8_LOKI 0x10004 -#define AL_FORMAT_QUAD16_LOKI 0x10005 -#endif - -#ifndef AL_EXT_float32 -#define AL_EXT_float32 1 -#define AL_FORMAT_MONO_FLOAT32 0x10010 -#define AL_FORMAT_STEREO_FLOAT32 0x10011 -#endif - -#ifndef AL_EXT_double -#define AL_EXT_double 1 -#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 -#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013 -#endif - -#ifndef AL_EXT_MULAW -#define AL_EXT_MULAW 1 -#define AL_FORMAT_MONO_MULAW_EXT 0x10014 -#define AL_FORMAT_STEREO_MULAW_EXT 0x10015 -#endif - -#ifndef AL_EXT_ALAW -#define AL_EXT_ALAW 1 -#define AL_FORMAT_MONO_ALAW_EXT 0x10016 -#define AL_FORMAT_STEREO_ALAW_EXT 0x10017 -#endif - -#ifndef ALC_LOKI_audio_channel -#define ALC_LOKI_audio_channel 1 -#define ALC_CHAN_MAIN_LOKI 0x500001 -#define ALC_CHAN_PCM_LOKI 0x500002 -#define ALC_CHAN_CD_LOKI 0x500003 -#endif - -#ifndef AL_EXT_MCFORMATS -#define AL_EXT_MCFORMATS 1 -#define AL_FORMAT_QUAD8 0x1204 -#define AL_FORMAT_QUAD16 0x1205 -#define AL_FORMAT_QUAD32 0x1206 -#define AL_FORMAT_REAR8 0x1207 -#define AL_FORMAT_REAR16 0x1208 -#define AL_FORMAT_REAR32 0x1209 -#define AL_FORMAT_51CHN8 0x120A -#define AL_FORMAT_51CHN16 0x120B -#define AL_FORMAT_51CHN32 0x120C -#define AL_FORMAT_61CHN8 0x120D -#define AL_FORMAT_61CHN16 0x120E -#define AL_FORMAT_61CHN32 0x120F -#define AL_FORMAT_71CHN8 0x1210 -#define AL_FORMAT_71CHN16 0x1211 -#define AL_FORMAT_71CHN32 0x1212 -#endif - -#ifndef AL_EXT_MULAW_MCFORMATS -#define AL_EXT_MULAW_MCFORMATS 1 -#define AL_FORMAT_MONO_MULAW 0x10014 -#define AL_FORMAT_STEREO_MULAW 0x10015 -#define AL_FORMAT_QUAD_MULAW 0x10021 -#define AL_FORMAT_REAR_MULAW 0x10022 -#define AL_FORMAT_51CHN_MULAW 0x10023 -#define AL_FORMAT_61CHN_MULAW 0x10024 -#define AL_FORMAT_71CHN_MULAW 0x10025 -#endif - -#ifndef AL_EXT_IMA4 -#define AL_EXT_IMA4 1 -#define AL_FORMAT_MONO_IMA4 0x1300 -#define AL_FORMAT_STEREO_IMA4 0x1301 -#endif - -#ifndef AL_EXT_STATIC_BUFFER -#define AL_EXT_STATIC_BUFFER 1 -typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei); -#ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq); -#endif -#endif - -#ifndef ALC_EXT_EFX -#define ALC_EXT_EFX 1 -#include "efx.h" -#endif - -#ifndef ALC_EXT_disconnect -#define ALC_EXT_disconnect 1 -#define ALC_CONNECTED 0x313 -#endif - -#ifndef ALC_EXT_thread_local_context -#define ALC_EXT_thread_local_context 1 -typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context); -typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context); -ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); -#endif -#endif - -#ifndef AL_EXT_source_distance_model -#define AL_EXT_source_distance_model 1 -#define AL_SOURCE_DISTANCE_MODEL 0x200 -#endif - -#ifndef AL_SOFT_buffer_sub_data -#define AL_SOFT_buffer_sub_data 1 -#define AL_BYTE_RW_OFFSETS_SOFT 0x1031 -#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032 -typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); -#ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); -#endif -#endif - -#ifndef AL_SOFT_loop_points -#define AL_SOFT_loop_points 1 -#define AL_LOOP_POINTS_SOFT 0x2015 -#endif - -#ifndef AL_EXT_FOLDBACK -#define AL_EXT_FOLDBACK 1 -#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK" -#define AL_FOLDBACK_EVENT_BLOCK 0x4112 -#define AL_FOLDBACK_EVENT_START 0x4111 -#define AL_FOLDBACK_EVENT_STOP 0x4113 -#define AL_FOLDBACK_MODE_MONO 0x4101 -#define AL_FOLDBACK_MODE_STEREO 0x4102 -typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei); -typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK); -typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback); -AL_API void AL_APIENTRY alRequestFoldbackStop(void); -#endif -#endif - -#ifndef ALC_EXT_DEDICATED -#define ALC_EXT_DEDICATED 1 -#define AL_DEDICATED_GAIN 0x0001 -#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001 -#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000 -#endif - -#ifndef AL_SOFT_buffer_samples -#define AL_SOFT_buffer_samples 1 -/* Channel configurations */ -#define AL_MONO_SOFT 0x1500 -#define AL_STEREO_SOFT 0x1501 -#define AL_REAR_SOFT 0x1502 -#define AL_QUAD_SOFT 0x1503 -#define AL_5POINT1_SOFT 0x1504 -#define AL_6POINT1_SOFT 0x1505 -#define AL_7POINT1_SOFT 0x1506 - -/* Sample types */ -#define AL_BYTE_SOFT 0x1400 -#define AL_UNSIGNED_BYTE_SOFT 0x1401 -#define AL_SHORT_SOFT 0x1402 -#define AL_UNSIGNED_SHORT_SOFT 0x1403 -#define AL_INT_SOFT 0x1404 -#define AL_UNSIGNED_INT_SOFT 0x1405 -#define AL_FLOAT_SOFT 0x1406 -#define AL_DOUBLE_SOFT 0x1407 -#define AL_BYTE3_SOFT 0x1408 -#define AL_UNSIGNED_BYTE3_SOFT 0x1409 - -/* Storage formats */ -#define AL_MONO8_SOFT 0x1100 -#define AL_MONO16_SOFT 0x1101 -#define AL_MONO32F_SOFT 0x10010 -#define AL_STEREO8_SOFT 0x1102 -#define AL_STEREO16_SOFT 0x1103 -#define AL_STEREO32F_SOFT 0x10011 -#define AL_QUAD8_SOFT 0x1204 -#define AL_QUAD16_SOFT 0x1205 -#define AL_QUAD32F_SOFT 0x1206 -#define AL_REAR8_SOFT 0x1207 -#define AL_REAR16_SOFT 0x1208 -#define AL_REAR32F_SOFT 0x1209 -#define AL_5POINT1_8_SOFT 0x120A -#define AL_5POINT1_16_SOFT 0x120B -#define AL_5POINT1_32F_SOFT 0x120C -#define AL_6POINT1_8_SOFT 0x120D -#define AL_6POINT1_16_SOFT 0x120E -#define AL_6POINT1_32F_SOFT 0x120F -#define AL_7POINT1_8_SOFT 0x1210 -#define AL_7POINT1_16_SOFT 0x1211 -#define AL_7POINT1_32F_SOFT 0x1212 - -/* Buffer attributes */ -#define AL_INTERNAL_FORMAT_SOFT 0x2008 -#define AL_BYTE_LENGTH_SOFT 0x2009 -#define AL_SAMPLE_LENGTH_SOFT 0x200A -#define AL_SEC_LENGTH_SOFT 0x200B - -typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); -typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*); -typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); -typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); -AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); -AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); -AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); -#endif -#endif - -#ifndef AL_SOFT_direct_channels -#define AL_SOFT_direct_channels 1 -#define AL_DIRECT_CHANNELS_SOFT 0x1033 -#endif - -#ifndef ALC_SOFT_loopback -#define ALC_SOFT_loopback 1 -#define ALC_FORMAT_CHANNELS_SOFT 0x1990 -#define ALC_FORMAT_TYPE_SOFT 0x1991 - -/* Sample types */ -#define ALC_BYTE_SOFT 0x1400 -#define ALC_UNSIGNED_BYTE_SOFT 0x1401 -#define ALC_SHORT_SOFT 0x1402 -#define ALC_UNSIGNED_SHORT_SOFT 0x1403 -#define ALC_INT_SOFT 0x1404 -#define ALC_UNSIGNED_INT_SOFT 0x1405 -#define ALC_FLOAT_SOFT 0x1406 - -/* Channel configurations */ -#define ALC_MONO_SOFT 0x1500 -#define ALC_STEREO_SOFT 0x1501 -#define ALC_QUAD_SOFT 0x1503 -#define ALC_5POINT1_SOFT 0x1504 -#define ALC_6POINT1_SOFT 0x1505 -#define ALC_7POINT1_SOFT 0x1506 - -typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*); -typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum); -typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName); -ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type); -ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); -#endif -#endif - -#ifndef AL_EXT_STEREO_ANGLES -#define AL_EXT_STEREO_ANGLES 1 -#define AL_STEREO_ANGLES 0x1030 -#endif - -#ifndef AL_EXT_SOURCE_RADIUS -#define AL_EXT_SOURCE_RADIUS 1 -#define AL_SOURCE_RADIUS 0x1031 -#endif - -#ifndef AL_SOFT_source_latency -#define AL_SOFT_source_latency 1 -#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200 -#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201 -typedef int64_t ALint64SOFT; -typedef uint64_t ALuint64SOFT; -typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble); -typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble); -typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*); -typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT); -typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT); -typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value); -AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3); -AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values); -AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value); -AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3); -AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values); -AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value); -AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3); -AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values); -AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value); -AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3); -AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values); -#endif -#endif - -#ifndef ALC_EXT_DEFAULT_FILTER_ORDER -#define ALC_EXT_DEFAULT_FILTER_ORDER 1 -#define ALC_DEFAULT_FILTER_ORDER 0x1100 -#endif - -#ifndef AL_SOFT_deferred_updates -#define AL_SOFT_deferred_updates 1 -#define AL_DEFERRED_UPDATES_SOFT 0xC002 -typedef ALvoid (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void); -typedef ALvoid (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void); -#ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void); -AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void); -#endif -#endif - -#ifndef AL_SOFT_block_alignment -#define AL_SOFT_block_alignment 1 -#define AL_UNPACK_BLOCK_ALIGNMENT_SOFT 0x200C -#define AL_PACK_BLOCK_ALIGNMENT_SOFT 0x200D -#endif - -#ifndef AL_SOFT_MSADPCM -#define AL_SOFT_MSADPCM 1 -#define AL_FORMAT_MONO_MSADPCM_SOFT 0x1302 -#define AL_FORMAT_STEREO_MSADPCM_SOFT 0x1303 -#endif - -#ifndef AL_SOFT_source_length -#define AL_SOFT_source_length 1 -/*#define AL_BYTE_LENGTH_SOFT 0x2009*/ -/*#define AL_SAMPLE_LENGTH_SOFT 0x200A*/ -/*#define AL_SEC_LENGTH_SOFT 0x200B*/ -#endif - -#ifndef ALC_SOFT_pause_device -#define ALC_SOFT_pause_device 1 -typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device); -typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device); -ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device); -#endif -#endif - -#ifndef AL_EXT_BFORMAT -#define AL_EXT_BFORMAT 1 -#define AL_FORMAT_BFORMAT2D_8 0x20021 -#define AL_FORMAT_BFORMAT2D_16 0x20022 -#define AL_FORMAT_BFORMAT2D_FLOAT32 0x20023 -#define AL_FORMAT_BFORMAT3D_8 0x20031 -#define AL_FORMAT_BFORMAT3D_16 0x20032 -#define AL_FORMAT_BFORMAT3D_FLOAT32 0x20033 -#endif - -#ifndef AL_EXT_MULAW_BFORMAT -#define AL_EXT_MULAW_BFORMAT 1 -#define AL_FORMAT_BFORMAT2D_MULAW 0x10031 -#define AL_FORMAT_BFORMAT3D_MULAW 0x10032 -#endif - -#ifndef ALC_SOFT_HRTF -#define ALC_SOFT_HRTF 1 -#define ALC_HRTF_SOFT 0x1992 -#define ALC_DONT_CARE_SOFT 0x0002 -#define ALC_HRTF_STATUS_SOFT 0x1993 -#define ALC_HRTF_DISABLED_SOFT 0x0000 -#define ALC_HRTF_ENABLED_SOFT 0x0001 -#define ALC_HRTF_DENIED_SOFT 0x0002 -#define ALC_HRTF_REQUIRED_SOFT 0x0003 -#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004 -#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005 -#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 -#define ALC_HRTF_SPECIFIER_SOFT 0x1995 -#define ALC_HRTF_ID_SOFT 0x1996 -typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); -typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); -ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); -#endif -#endif - -#ifndef AL_SOFT_gain_clamp_ex -#define AL_SOFT_gain_clamp_ex 1 -#define AL_GAIN_LIMIT_SOFT 0x200E -#endif - -#ifndef AL_SOFT_source_resampler -#define AL_SOFT_source_resampler -#define AL_NUM_RESAMPLERS_SOFT 0x1210 -#define AL_DEFAULT_RESAMPLER_SOFT 0x1211 -#define AL_SOURCE_RESAMPLER_SOFT 0x1212 -#define AL_RESAMPLER_NAME_SOFT 0x1213 -typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index); -#ifdef AL_ALEXT_PROTOTYPES -AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); -#endif -#endif - -#ifndef AL_SOFT_source_spatialize -#define AL_SOFT_source_spatialize -#define AL_SOURCE_SPATIALIZE_SOFT 0x1214 -#define AL_AUTO_SOFT 0x0002 -#endif - -#ifndef ALC_SOFT_output_limiter -#define ALC_SOFT_output_limiter -#define ALC_OUTPUT_LIMITER_SOFT 0x199A -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/external/include/AL/efx-creative.h b/src/external/include/AL/efx-creative.h deleted file mode 100644 index 0a04c982..00000000 --- a/src/external/include/AL/efx-creative.h +++ /dev/null @@ -1,3 +0,0 @@ -/* The tokens that would be defined here are already defined in efx.h. This - * empty file is here to provide compatibility with Windows-based projects - * that would include it. */ diff --git a/src/external/include/AL/efx-presets.h b/src/external/include/AL/efx-presets.h deleted file mode 100644 index 8539fd51..00000000 --- a/src/external/include/AL/efx-presets.h +++ /dev/null @@ -1,402 +0,0 @@ -/* Reverb presets for EFX */ - -#ifndef EFX_PRESETS_H -#define EFX_PRESETS_H - -#ifndef EFXEAXREVERBPROPERTIES_DEFINED -#define EFXEAXREVERBPROPERTIES_DEFINED -typedef struct { - float flDensity; - float flDiffusion; - float flGain; - float flGainHF; - float flGainLF; - float flDecayTime; - float flDecayHFRatio; - float flDecayLFRatio; - float flReflectionsGain; - float flReflectionsDelay; - float flReflectionsPan[3]; - float flLateReverbGain; - float flLateReverbDelay; - float flLateReverbPan[3]; - float flEchoTime; - float flEchoDepth; - float flModulationTime; - float flModulationDepth; - float flAirAbsorptionGainHF; - float flHFReference; - float flLFReference; - float flRoomRolloffFactor; - int iDecayHFLimit; -} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES; -#endif - -/* Default Presets */ - -#define EFX_REVERB_PRESET_GENERIC \ - { 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PADDEDCELL \ - { 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ROOM \ - { 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_BATHROOM \ - { 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_LIVINGROOM \ - { 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_STONEROOM \ - { 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_AUDITORIUM \ - { 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CONCERTHALL \ - { 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CAVE \ - { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_ARENA \ - { 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_HANGAR \ - { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CARPETEDHALLWAY \ - { 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_HALLWAY \ - { 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_STONECORRIDOR \ - { 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ALLEY \ - { 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FOREST \ - { 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CITY \ - { 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_MOUNTAINS \ - { 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_QUARRY \ - { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PLAIN \ - { 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PARKINGLOT \ - { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_SEWERPIPE \ - { 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_UNDERWATER \ - { 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DRUGGED \ - { 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_DIZZY \ - { 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_PSYCHOTIC \ - { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -/* Castle Presets */ - -#define EFX_REVERB_PRESET_CASTLE_SMALLROOM \ - { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 1.2200f, 0.8300f, 0.3100f, 0.8913f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE \ - { 1.0000f, 0.8900f, 0.3162f, 0.3162f, 0.1000f, 2.3200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_MEDIUMROOM \ - { 1.0000f, 0.9300f, 0.3162f, 0.2818f, 0.1000f, 2.0400f, 0.8300f, 0.4600f, 0.6310f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1550f, 0.0300f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_LARGEROOM \ - { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.1259f, 2.5300f, 0.8300f, 0.5000f, 0.4467f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1850f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_LONGPASSAGE \ - { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 3.4200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_HALL \ - { 1.0000f, 0.8100f, 0.3162f, 0.2818f, 0.1778f, 3.1400f, 0.7900f, 0.6200f, 0.1778f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_CUPBOARD \ - { 1.0000f, 0.8900f, 0.3162f, 0.2818f, 0.1000f, 0.6700f, 0.8700f, 0.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 3.5481f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_COURTYARD \ - { 1.0000f, 0.4200f, 0.3162f, 0.4467f, 0.1995f, 2.1300f, 0.6100f, 0.2300f, 0.2239f, 0.1600f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3700f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_CASTLE_ALCOVE \ - { 1.0000f, 0.8900f, 0.3162f, 0.5012f, 0.1000f, 1.6400f, 0.8700f, 0.3100f, 1.0000f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -/* Factory Presets */ - -#define EFX_REVERB_PRESET_FACTORY_SMALLROOM \ - { 0.3645f, 0.8200f, 0.3162f, 0.7943f, 0.5012f, 1.7200f, 0.6500f, 1.3100f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.1190f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE \ - { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 2.5300f, 0.6500f, 1.3100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_MEDIUMROOM \ - { 0.4287f, 0.8200f, 0.2512f, 0.7943f, 0.5012f, 2.7600f, 0.6500f, 1.3100f, 0.2818f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1740f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_LARGEROOM \ - { 0.4287f, 0.7500f, 0.2512f, 0.7079f, 0.6310f, 4.2400f, 0.5100f, 1.3100f, 0.1778f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2310f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_LONGPASSAGE \ - { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 4.0600f, 0.6500f, 1.3100f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_HALL \ - { 0.4287f, 0.7500f, 0.3162f, 0.7079f, 0.6310f, 7.4300f, 0.5100f, 1.3100f, 0.0631f, 0.0730f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_CUPBOARD \ - { 0.3071f, 0.6300f, 0.2512f, 0.7943f, 0.5012f, 0.4900f, 0.6500f, 1.3100f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.1070f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_COURTYARD \ - { 0.3071f, 0.5700f, 0.3162f, 0.3162f, 0.6310f, 2.3200f, 0.2900f, 0.5600f, 0.2239f, 0.1400f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2900f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_ALCOVE \ - { 0.3645f, 0.5900f, 0.2512f, 0.7943f, 0.5012f, 3.1400f, 0.6500f, 1.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1140f, 0.1000f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -/* Ice Palace Presets */ - -#define EFX_REVERB_PRESET_ICEPALACE_SMALLROOM \ - { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 1.5100f, 1.5300f, 0.2700f, 0.8913f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1640f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_SHORTPASSAGE \ - { 1.0000f, 0.7500f, 0.3162f, 0.5623f, 0.2818f, 1.7900f, 1.4600f, 0.2800f, 0.5012f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_MEDIUMROOM \ - { 1.0000f, 0.8700f, 0.3162f, 0.5623f, 0.4467f, 2.2200f, 1.5300f, 0.3200f, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_LARGEROOM \ - { 1.0000f, 0.8100f, 0.3162f, 0.5623f, 0.4467f, 3.1400f, 1.5300f, 0.3200f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_LONGPASSAGE \ - { 1.0000f, 0.7700f, 0.3162f, 0.5623f, 0.3981f, 3.0100f, 1.4600f, 0.2800f, 0.7943f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.0400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_HALL \ - { 1.0000f, 0.7600f, 0.3162f, 0.4467f, 0.5623f, 5.4900f, 1.5300f, 0.3800f, 0.1122f, 0.0540f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0520f, { 0.0000f, 0.0000f, 0.0000f }, 0.2260f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_CUPBOARD \ - { 1.0000f, 0.8300f, 0.3162f, 0.5012f, 0.2239f, 0.7600f, 1.5300f, 0.2600f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1430f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_COURTYARD \ - { 1.0000f, 0.5900f, 0.3162f, 0.2818f, 0.3162f, 2.0400f, 1.2000f, 0.3800f, 0.3162f, 0.1730f, { 0.0000f, 0.0000f, 0.0000f }, 0.3162f, 0.0430f, { 0.0000f, 0.0000f, 0.0000f }, 0.2350f, 0.4800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_ALCOVE \ - { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 2.7600f, 1.4600f, 0.2800f, 1.1220f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1610f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -/* Space Station Presets */ - -#define EFX_REVERB_PRESET_SPACESTATION_SMALLROOM \ - { 0.2109f, 0.7000f, 0.3162f, 0.7079f, 0.8913f, 1.7200f, 0.8200f, 0.5500f, 0.7943f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 0.1880f, 0.2600f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE \ - { 0.2109f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 3.5700f, 0.5000f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1720f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM \ - { 0.2109f, 0.7500f, 0.3162f, 0.6310f, 0.8913f, 3.0100f, 0.5000f, 0.5500f, 0.3981f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2090f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_LARGEROOM \ - { 0.3645f, 0.8100f, 0.3162f, 0.6310f, 0.8913f, 3.8900f, 0.3800f, 0.6100f, 0.3162f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2330f, 0.2800f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE \ - { 0.4287f, 0.8200f, 0.3162f, 0.6310f, 0.8913f, 4.6200f, 0.6200f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_HALL \ - { 0.4287f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 7.1100f, 0.3800f, 0.6100f, 0.1778f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2500f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_CUPBOARD \ - { 0.1715f, 0.5600f, 0.3162f, 0.7079f, 0.8913f, 0.7900f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1810f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_ALCOVE \ - { 0.2109f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.1600f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1920f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -/* Wooden Galleon Presets */ - -#define EFX_REVERB_PRESET_WOODEN_SMALLROOM \ - { 1.0000f, 1.0000f, 0.3162f, 0.1122f, 0.3162f, 0.7900f, 0.3200f, 0.8700f, 1.0000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE \ - { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.7500f, 0.5000f, 0.8700f, 0.8913f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_MEDIUMROOM \ - { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.2818f, 1.4700f, 0.4200f, 0.8200f, 0.8913f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_LARGEROOM \ - { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.2818f, 2.6500f, 0.3300f, 0.8200f, 0.8913f, 0.0660f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_LONGPASSAGE \ - { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.3162f, 1.9900f, 0.4000f, 0.7900f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4467f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_HALL \ - { 1.0000f, 1.0000f, 0.3162f, 0.0794f, 0.2818f, 3.4500f, 0.3000f, 0.8200f, 0.8913f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_CUPBOARD \ - { 1.0000f, 1.0000f, 0.3162f, 0.1413f, 0.3162f, 0.5600f, 0.4600f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_COURTYARD \ - { 1.0000f, 0.6500f, 0.3162f, 0.0794f, 0.3162f, 1.7900f, 0.3500f, 0.7900f, 0.5623f, 0.1230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_ALCOVE \ - { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.2200f, 0.6200f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -/* Sports Presets */ - -#define EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM \ - { 1.0000f, 1.0000f, 0.3162f, 0.4467f, 0.7943f, 6.2600f, 0.5100f, 1.1000f, 0.0631f, 0.1830f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPORT_SQUASHCOURT \ - { 1.0000f, 0.7500f, 0.3162f, 0.3162f, 0.7943f, 2.2200f, 0.9100f, 1.1600f, 0.4467f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1260f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPORT_SMALLSWIMMINGPOOL \ - { 1.0000f, 0.7000f, 0.3162f, 0.7943f, 0.8913f, 2.7600f, 1.2500f, 1.1400f, 0.6310f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_SPORT_LARGESWIMMINGPOOL \ - { 1.0000f, 0.8200f, 0.3162f, 0.7943f, 1.0000f, 5.4900f, 1.3100f, 1.1400f, 0.4467f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2220f, 0.5500f, 1.1590f, 0.2100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_SPORT_GYMNASIUM \ - { 1.0000f, 0.8100f, 0.3162f, 0.4467f, 0.8913f, 3.1400f, 1.0600f, 1.3500f, 0.3981f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0450f, { 0.0000f, 0.0000f, 0.0000f }, 0.1460f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPORT_FULLSTADIUM \ - { 1.0000f, 1.0000f, 0.3162f, 0.0708f, 0.7943f, 5.2500f, 0.1700f, 0.8000f, 0.1000f, 0.1880f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPORT_STADIUMTANNOY \ - { 1.0000f, 0.7800f, 0.3162f, 0.5623f, 0.5012f, 2.5300f, 0.8800f, 0.6800f, 0.2818f, 0.2300f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -/* Prefab Presets */ - -#define EFX_REVERB_PRESET_PREFAB_WORKSHOP \ - { 0.4287f, 1.0000f, 0.3162f, 0.1413f, 0.3981f, 0.7600f, 1.0000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_PREFAB_SCHOOLROOM \ - { 0.4022f, 0.6900f, 0.3162f, 0.6310f, 0.5012f, 0.9800f, 0.4500f, 0.1800f, 1.4125f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PREFAB_PRACTISEROOM \ - { 0.4022f, 0.8700f, 0.3162f, 0.3981f, 0.5012f, 1.1200f, 0.5600f, 0.1800f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PREFAB_OUTHOUSE \ - { 1.0000f, 0.8200f, 0.3162f, 0.1122f, 0.1585f, 1.3800f, 0.3800f, 0.3500f, 0.8913f, 0.0240f, { 0.0000f, 0.0000f, -0.0000f }, 0.6310f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.1210f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_PREFAB_CARAVAN \ - { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.1259f, 0.4300f, 1.5000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -/* Dome and Pipe Presets */ - -#define EFX_REVERB_PRESET_DOME_TOMB \ - { 1.0000f, 0.7900f, 0.3162f, 0.3548f, 0.2239f, 4.1800f, 0.2100f, 0.1000f, 0.3868f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 1.6788f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_PIPE_SMALL \ - { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 5.0400f, 0.1000f, 0.1000f, 0.5012f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 2.5119f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DOME_SAINTPAULS \ - { 1.0000f, 0.8700f, 0.3162f, 0.3548f, 0.2239f, 10.4800f, 0.1900f, 0.1000f, 0.1778f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0420f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PIPE_LONGTHIN \ - { 0.2560f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 9.2100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_PIPE_LARGE \ - { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 8.4500f, 0.1000f, 0.1000f, 0.3981f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PIPE_RESONANT \ - { 0.1373f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 6.8100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } - -/* Outdoors Presets */ - -#define EFX_REVERB_PRESET_OUTDOORS_BACKYARD \ - { 1.0000f, 0.4500f, 0.3162f, 0.2512f, 0.5012f, 1.1200f, 0.3400f, 0.4600f, 0.4467f, 0.0690f, { 0.0000f, 0.0000f, -0.0000f }, 0.7079f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS \ - { 1.0000f, 0.0000f, 0.3162f, 0.0112f, 0.6310f, 2.1300f, 0.2100f, 0.4600f, 0.1778f, 0.3000f, { 0.0000f, 0.0000f, -0.0000f }, 0.4467f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON \ - { 1.0000f, 0.7400f, 0.3162f, 0.1778f, 0.6310f, 3.8900f, 0.2100f, 0.4600f, 0.3162f, 0.2230f, { 0.0000f, 0.0000f, -0.0000f }, 0.3548f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_OUTDOORS_CREEK \ - { 1.0000f, 0.3500f, 0.3162f, 0.1778f, 0.5012f, 2.1300f, 0.2100f, 0.4600f, 0.3981f, 0.1150f, { 0.0000f, 0.0000f, -0.0000f }, 0.1995f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_OUTDOORS_VALLEY \ - { 1.0000f, 0.2800f, 0.3162f, 0.0282f, 0.1585f, 2.8800f, 0.2600f, 0.3500f, 0.1413f, 0.2630f, { 0.0000f, 0.0000f, -0.0000f }, 0.3981f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } - -/* Mood Presets */ - -#define EFX_REVERB_PRESET_MOOD_HEAVEN \ - { 1.0000f, 0.9400f, 0.3162f, 0.7943f, 0.4467f, 5.0400f, 1.1200f, 0.5600f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0800f, 2.7420f, 0.0500f, 0.9977f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_MOOD_HELL \ - { 1.0000f, 0.5700f, 0.3162f, 0.3548f, 0.4467f, 3.5700f, 0.4900f, 2.0000f, 0.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1100f, 0.0400f, 2.1090f, 0.5200f, 0.9943f, 5000.0000f, 139.5000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_MOOD_MEMORY \ - { 1.0000f, 0.8500f, 0.3162f, 0.6310f, 0.3548f, 4.0600f, 0.8200f, 0.5600f, 0.0398f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.4740f, 0.4500f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -/* Driving Presets */ - -#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \ - { 1.0000f, 0.0000f, 0.3162f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \ - { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_DRIVING_INCAR_RACER \ - { 0.0832f, 0.8000f, 0.3162f, 1.0000f, 0.7943f, 0.1700f, 2.0000f, 0.4100f, 1.7783f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS \ - { 0.0832f, 0.8000f, 0.3162f, 0.6310f, 1.0000f, 0.1700f, 0.7500f, 0.4100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY \ - { 0.2560f, 1.0000f, 0.3162f, 0.1000f, 0.5012f, 0.1300f, 0.4100f, 0.4600f, 0.7943f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND \ - { 1.0000f, 1.0000f, 0.3162f, 0.2818f, 0.6310f, 3.0100f, 1.3700f, 1.2800f, 0.3548f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.1778f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND \ - { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 0.7943f, 4.6200f, 1.7500f, 1.4000f, 0.2082f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_DRIVING_TUNNEL \ - { 1.0000f, 0.8100f, 0.3162f, 0.3981f, 0.8913f, 3.4200f, 0.9400f, 1.3100f, 0.7079f, 0.0510f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.0500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 155.3000f, 0.0000f, 0x1 } - -/* City Presets */ - -#define EFX_REVERB_PRESET_CITY_STREETS \ - { 1.0000f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.7900f, 1.1200f, 0.9100f, 0.2818f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 0.1995f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CITY_SUBWAY \ - { 1.0000f, 0.7400f, 0.3162f, 0.7079f, 0.8913f, 3.0100f, 1.2300f, 0.9100f, 0.7079f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CITY_MUSEUM \ - { 1.0000f, 0.8200f, 0.3162f, 0.1778f, 0.1778f, 3.2800f, 1.4000f, 0.5700f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_CITY_LIBRARY \ - { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.0891f, 2.7600f, 0.8900f, 0.4100f, 0.3548f, 0.0290f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_CITY_UNDERPASS \ - { 1.0000f, 0.8200f, 0.3162f, 0.4467f, 0.8913f, 3.5700f, 1.1200f, 0.9100f, 0.3981f, 0.0590f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1400f, 0.2500f, 0.0000f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CITY_ABANDONED \ - { 1.0000f, 0.6900f, 0.3162f, 0.7943f, 0.8913f, 3.2800f, 1.1700f, 0.9100f, 0.4467f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9966f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -/* Misc. Presets */ - -#define EFX_REVERB_PRESET_DUSTYROOM \ - { 0.3645f, 0.5600f, 0.3162f, 0.7943f, 0.7079f, 1.7900f, 0.3800f, 0.2100f, 0.5012f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0060f, { 0.0000f, 0.0000f, 0.0000f }, 0.2020f, 0.0500f, 0.2500f, 0.0000f, 0.9886f, 13046.0000f, 163.3000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CHAPEL \ - { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 1.0000f, 4.6200f, 0.6400f, 1.2300f, 0.4467f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.1100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SMALLWATERROOM \ - { 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#endif /* EFX_PRESETS_H */ diff --git a/src/external/include/AL/efx.h b/src/external/include/AL/efx.h deleted file mode 100644 index 57766983..00000000 --- a/src/external/include/AL/efx.h +++ /dev/null @@ -1,761 +0,0 @@ -#ifndef AL_EFX_H -#define AL_EFX_H - - -#include "alc.h" -#include "al.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ALC_EXT_EFX_NAME "ALC_EXT_EFX" - -#define ALC_EFX_MAJOR_VERSION 0x20001 -#define ALC_EFX_MINOR_VERSION 0x20002 -#define ALC_MAX_AUXILIARY_SENDS 0x20003 - - -/* Listener properties. */ -#define AL_METERS_PER_UNIT 0x20004 - -/* Source properties. */ -#define AL_DIRECT_FILTER 0x20005 -#define AL_AUXILIARY_SEND_FILTER 0x20006 -#define AL_AIR_ABSORPTION_FACTOR 0x20007 -#define AL_ROOM_ROLLOFF_FACTOR 0x20008 -#define AL_CONE_OUTER_GAINHF 0x20009 -#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A -#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B -#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C - - -/* Effect properties. */ - -/* Reverb effect parameters */ -#define AL_REVERB_DENSITY 0x0001 -#define AL_REVERB_DIFFUSION 0x0002 -#define AL_REVERB_GAIN 0x0003 -#define AL_REVERB_GAINHF 0x0004 -#define AL_REVERB_DECAY_TIME 0x0005 -#define AL_REVERB_DECAY_HFRATIO 0x0006 -#define AL_REVERB_REFLECTIONS_GAIN 0x0007 -#define AL_REVERB_REFLECTIONS_DELAY 0x0008 -#define AL_REVERB_LATE_REVERB_GAIN 0x0009 -#define AL_REVERB_LATE_REVERB_DELAY 0x000A -#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B -#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C -#define AL_REVERB_DECAY_HFLIMIT 0x000D - -/* EAX Reverb effect parameters */ -#define AL_EAXREVERB_DENSITY 0x0001 -#define AL_EAXREVERB_DIFFUSION 0x0002 -#define AL_EAXREVERB_GAIN 0x0003 -#define AL_EAXREVERB_GAINHF 0x0004 -#define AL_EAXREVERB_GAINLF 0x0005 -#define AL_EAXREVERB_DECAY_TIME 0x0006 -#define AL_EAXREVERB_DECAY_HFRATIO 0x0007 -#define AL_EAXREVERB_DECAY_LFRATIO 0x0008 -#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009 -#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A -#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B -#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C -#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D -#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E -#define AL_EAXREVERB_ECHO_TIME 0x000F -#define AL_EAXREVERB_ECHO_DEPTH 0x0010 -#define AL_EAXREVERB_MODULATION_TIME 0x0011 -#define AL_EAXREVERB_MODULATION_DEPTH 0x0012 -#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013 -#define AL_EAXREVERB_HFREFERENCE 0x0014 -#define AL_EAXREVERB_LFREFERENCE 0x0015 -#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016 -#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017 - -/* Chorus effect parameters */ -#define AL_CHORUS_WAVEFORM 0x0001 -#define AL_CHORUS_PHASE 0x0002 -#define AL_CHORUS_RATE 0x0003 -#define AL_CHORUS_DEPTH 0x0004 -#define AL_CHORUS_FEEDBACK 0x0005 -#define AL_CHORUS_DELAY 0x0006 - -/* Distortion effect parameters */ -#define AL_DISTORTION_EDGE 0x0001 -#define AL_DISTORTION_GAIN 0x0002 -#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003 -#define AL_DISTORTION_EQCENTER 0x0004 -#define AL_DISTORTION_EQBANDWIDTH 0x0005 - -/* Echo effect parameters */ -#define AL_ECHO_DELAY 0x0001 -#define AL_ECHO_LRDELAY 0x0002 -#define AL_ECHO_DAMPING 0x0003 -#define AL_ECHO_FEEDBACK 0x0004 -#define AL_ECHO_SPREAD 0x0005 - -/* Flanger effect parameters */ -#define AL_FLANGER_WAVEFORM 0x0001 -#define AL_FLANGER_PHASE 0x0002 -#define AL_FLANGER_RATE 0x0003 -#define AL_FLANGER_DEPTH 0x0004 -#define AL_FLANGER_FEEDBACK 0x0005 -#define AL_FLANGER_DELAY 0x0006 - -/* Frequency shifter effect parameters */ -#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001 -#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002 -#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003 - -/* Vocal morpher effect parameters */ -#define AL_VOCAL_MORPHER_PHONEMEA 0x0001 -#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002 -#define AL_VOCAL_MORPHER_PHONEMEB 0x0003 -#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004 -#define AL_VOCAL_MORPHER_WAVEFORM 0x0005 -#define AL_VOCAL_MORPHER_RATE 0x0006 - -/* Pitchshifter effect parameters */ -#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001 -#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002 - -/* Ringmodulator effect parameters */ -#define AL_RING_MODULATOR_FREQUENCY 0x0001 -#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002 -#define AL_RING_MODULATOR_WAVEFORM 0x0003 - -/* Autowah effect parameters */ -#define AL_AUTOWAH_ATTACK_TIME 0x0001 -#define AL_AUTOWAH_RELEASE_TIME 0x0002 -#define AL_AUTOWAH_RESONANCE 0x0003 -#define AL_AUTOWAH_PEAK_GAIN 0x0004 - -/* Compressor effect parameters */ -#define AL_COMPRESSOR_ONOFF 0x0001 - -/* Equalizer effect parameters */ -#define AL_EQUALIZER_LOW_GAIN 0x0001 -#define AL_EQUALIZER_LOW_CUTOFF 0x0002 -#define AL_EQUALIZER_MID1_GAIN 0x0003 -#define AL_EQUALIZER_MID1_CENTER 0x0004 -#define AL_EQUALIZER_MID1_WIDTH 0x0005 -#define AL_EQUALIZER_MID2_GAIN 0x0006 -#define AL_EQUALIZER_MID2_CENTER 0x0007 -#define AL_EQUALIZER_MID2_WIDTH 0x0008 -#define AL_EQUALIZER_HIGH_GAIN 0x0009 -#define AL_EQUALIZER_HIGH_CUTOFF 0x000A - -/* Effect type */ -#define AL_EFFECT_FIRST_PARAMETER 0x0000 -#define AL_EFFECT_LAST_PARAMETER 0x8000 -#define AL_EFFECT_TYPE 0x8001 - -/* Effect types, used with the AL_EFFECT_TYPE property */ -#define AL_EFFECT_NULL 0x0000 -#define AL_EFFECT_REVERB 0x0001 -#define AL_EFFECT_CHORUS 0x0002 -#define AL_EFFECT_DISTORTION 0x0003 -#define AL_EFFECT_ECHO 0x0004 -#define AL_EFFECT_FLANGER 0x0005 -#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006 -#define AL_EFFECT_VOCAL_MORPHER 0x0007 -#define AL_EFFECT_PITCH_SHIFTER 0x0008 -#define AL_EFFECT_RING_MODULATOR 0x0009 -#define AL_EFFECT_AUTOWAH 0x000A -#define AL_EFFECT_COMPRESSOR 0x000B -#define AL_EFFECT_EQUALIZER 0x000C -#define AL_EFFECT_EAXREVERB 0x8000 - -/* Auxiliary Effect Slot properties. */ -#define AL_EFFECTSLOT_EFFECT 0x0001 -#define AL_EFFECTSLOT_GAIN 0x0002 -#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003 - -/* NULL Auxiliary Slot ID to disable a source send. */ -#define AL_EFFECTSLOT_NULL 0x0000 - - -/* Filter properties. */ - -/* Lowpass filter parameters */ -#define AL_LOWPASS_GAIN 0x0001 -#define AL_LOWPASS_GAINHF 0x0002 - -/* Highpass filter parameters */ -#define AL_HIGHPASS_GAIN 0x0001 -#define AL_HIGHPASS_GAINLF 0x0002 - -/* Bandpass filter parameters */ -#define AL_BANDPASS_GAIN 0x0001 -#define AL_BANDPASS_GAINLF 0x0002 -#define AL_BANDPASS_GAINHF 0x0003 - -/* Filter type */ -#define AL_FILTER_FIRST_PARAMETER 0x0000 -#define AL_FILTER_LAST_PARAMETER 0x8000 -#define AL_FILTER_TYPE 0x8001 - -/* Filter types, used with the AL_FILTER_TYPE property */ -#define AL_FILTER_NULL 0x0000 -#define AL_FILTER_LOWPASS 0x0001 -#define AL_FILTER_HIGHPASS 0x0002 -#define AL_FILTER_BANDPASS 0x0003 - - -/* Effect object function types. */ -typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*); -typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint); -typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*); -typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*); -typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*); -typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*); - -/* Filter object function types. */ -typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*); -typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint); -typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*); -typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*); -typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*); -typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*); - -/* Auxiliary Effect Slot object function types. */ -typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*); -typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); - -#ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects); -AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects); -AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect); -AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue); -AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues); -AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); -AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues); -AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue); -AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue); -AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); - -AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters); -AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters); -AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter); -AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue); -AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues); -AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); -AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues); -AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue); -AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue); -AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); - -AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); -AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots); -AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); -#endif - -/* Filter ranges and defaults. */ - -/* Lowpass filter */ -#define AL_LOWPASS_MIN_GAIN (0.0f) -#define AL_LOWPASS_MAX_GAIN (1.0f) -#define AL_LOWPASS_DEFAULT_GAIN (1.0f) - -#define AL_LOWPASS_MIN_GAINHF (0.0f) -#define AL_LOWPASS_MAX_GAINHF (1.0f) -#define AL_LOWPASS_DEFAULT_GAINHF (1.0f) - -/* Highpass filter */ -#define AL_HIGHPASS_MIN_GAIN (0.0f) -#define AL_HIGHPASS_MAX_GAIN (1.0f) -#define AL_HIGHPASS_DEFAULT_GAIN (1.0f) - -#define AL_HIGHPASS_MIN_GAINLF (0.0f) -#define AL_HIGHPASS_MAX_GAINLF (1.0f) -#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f) - -/* Bandpass filter */ -#define AL_BANDPASS_MIN_GAIN (0.0f) -#define AL_BANDPASS_MAX_GAIN (1.0f) -#define AL_BANDPASS_DEFAULT_GAIN (1.0f) - -#define AL_BANDPASS_MIN_GAINHF (0.0f) -#define AL_BANDPASS_MAX_GAINHF (1.0f) -#define AL_BANDPASS_DEFAULT_GAINHF (1.0f) - -#define AL_BANDPASS_MIN_GAINLF (0.0f) -#define AL_BANDPASS_MAX_GAINLF (1.0f) -#define AL_BANDPASS_DEFAULT_GAINLF (1.0f) - - -/* Effect parameter ranges and defaults. */ - -/* Standard reverb effect */ -#define AL_REVERB_MIN_DENSITY (0.0f) -#define AL_REVERB_MAX_DENSITY (1.0f) -#define AL_REVERB_DEFAULT_DENSITY (1.0f) - -#define AL_REVERB_MIN_DIFFUSION (0.0f) -#define AL_REVERB_MAX_DIFFUSION (1.0f) -#define AL_REVERB_DEFAULT_DIFFUSION (1.0f) - -#define AL_REVERB_MIN_GAIN (0.0f) -#define AL_REVERB_MAX_GAIN (1.0f) -#define AL_REVERB_DEFAULT_GAIN (0.32f) - -#define AL_REVERB_MIN_GAINHF (0.0f) -#define AL_REVERB_MAX_GAINHF (1.0f) -#define AL_REVERB_DEFAULT_GAINHF (0.89f) - -#define AL_REVERB_MIN_DECAY_TIME (0.1f) -#define AL_REVERB_MAX_DECAY_TIME (20.0f) -#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f) - -#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f) -#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f) -#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f) - -#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f) -#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f) -#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) - -#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f) -#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f) -#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) - -#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f) -#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f) -#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) - -#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f) -#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f) -#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) - -#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) -#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) -#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) - -#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) -#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) -#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) - -#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE -#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE -#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE - -/* EAX reverb effect */ -#define AL_EAXREVERB_MIN_DENSITY (0.0f) -#define AL_EAXREVERB_MAX_DENSITY (1.0f) -#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f) - -#define AL_EAXREVERB_MIN_DIFFUSION (0.0f) -#define AL_EAXREVERB_MAX_DIFFUSION (1.0f) -#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f) - -#define AL_EAXREVERB_MIN_GAIN (0.0f) -#define AL_EAXREVERB_MAX_GAIN (1.0f) -#define AL_EAXREVERB_DEFAULT_GAIN (0.32f) - -#define AL_EAXREVERB_MIN_GAINHF (0.0f) -#define AL_EAXREVERB_MAX_GAINHF (1.0f) -#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f) - -#define AL_EAXREVERB_MIN_GAINLF (0.0f) -#define AL_EAXREVERB_MAX_GAINLF (1.0f) -#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f) - -#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f) -#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f) -#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f) - -#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f) -#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f) -#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f) - -#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f) -#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f) -#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f) - -#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f) -#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f) -#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) - -#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f) -#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f) -#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) - -#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f) - -#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f) -#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f) -#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) - -#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f) -#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f) -#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) - -#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f) - -#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f) -#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f) -#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f) - -#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f) -#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f) -#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f) - -#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f) -#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f) -#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f) - -#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f) -#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f) -#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f) - -#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) -#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) -#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) - -#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f) -#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f) -#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f) - -#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f) -#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f) -#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f) - -#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) -#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) -#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) - -#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE -#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE -#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE - -/* Chorus effect */ -#define AL_CHORUS_WAVEFORM_SINUSOID (0) -#define AL_CHORUS_WAVEFORM_TRIANGLE (1) - -#define AL_CHORUS_MIN_WAVEFORM (0) -#define AL_CHORUS_MAX_WAVEFORM (1) -#define AL_CHORUS_DEFAULT_WAVEFORM (1) - -#define AL_CHORUS_MIN_PHASE (-180) -#define AL_CHORUS_MAX_PHASE (180) -#define AL_CHORUS_DEFAULT_PHASE (90) - -#define AL_CHORUS_MIN_RATE (0.0f) -#define AL_CHORUS_MAX_RATE (10.0f) -#define AL_CHORUS_DEFAULT_RATE (1.1f) - -#define AL_CHORUS_MIN_DEPTH (0.0f) -#define AL_CHORUS_MAX_DEPTH (1.0f) -#define AL_CHORUS_DEFAULT_DEPTH (0.1f) - -#define AL_CHORUS_MIN_FEEDBACK (-1.0f) -#define AL_CHORUS_MAX_FEEDBACK (1.0f) -#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f) - -#define AL_CHORUS_MIN_DELAY (0.0f) -#define AL_CHORUS_MAX_DELAY (0.016f) -#define AL_CHORUS_DEFAULT_DELAY (0.016f) - -/* Distortion effect */ -#define AL_DISTORTION_MIN_EDGE (0.0f) -#define AL_DISTORTION_MAX_EDGE (1.0f) -#define AL_DISTORTION_DEFAULT_EDGE (0.2f) - -#define AL_DISTORTION_MIN_GAIN (0.01f) -#define AL_DISTORTION_MAX_GAIN (1.0f) -#define AL_DISTORTION_DEFAULT_GAIN (0.05f) - -#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f) -#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f) -#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f) - -#define AL_DISTORTION_MIN_EQCENTER (80.0f) -#define AL_DISTORTION_MAX_EQCENTER (24000.0f) -#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f) - -#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f) -#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f) -#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f) - -/* Echo effect */ -#define AL_ECHO_MIN_DELAY (0.0f) -#define AL_ECHO_MAX_DELAY (0.207f) -#define AL_ECHO_DEFAULT_DELAY (0.1f) - -#define AL_ECHO_MIN_LRDELAY (0.0f) -#define AL_ECHO_MAX_LRDELAY (0.404f) -#define AL_ECHO_DEFAULT_LRDELAY (0.1f) - -#define AL_ECHO_MIN_DAMPING (0.0f) -#define AL_ECHO_MAX_DAMPING (0.99f) -#define AL_ECHO_DEFAULT_DAMPING (0.5f) - -#define AL_ECHO_MIN_FEEDBACK (0.0f) -#define AL_ECHO_MAX_FEEDBACK (1.0f) -#define AL_ECHO_DEFAULT_FEEDBACK (0.5f) - -#define AL_ECHO_MIN_SPREAD (-1.0f) -#define AL_ECHO_MAX_SPREAD (1.0f) -#define AL_ECHO_DEFAULT_SPREAD (-1.0f) - -/* Flanger effect */ -#define AL_FLANGER_WAVEFORM_SINUSOID (0) -#define AL_FLANGER_WAVEFORM_TRIANGLE (1) - -#define AL_FLANGER_MIN_WAVEFORM (0) -#define AL_FLANGER_MAX_WAVEFORM (1) -#define AL_FLANGER_DEFAULT_WAVEFORM (1) - -#define AL_FLANGER_MIN_PHASE (-180) -#define AL_FLANGER_MAX_PHASE (180) -#define AL_FLANGER_DEFAULT_PHASE (0) - -#define AL_FLANGER_MIN_RATE (0.0f) -#define AL_FLANGER_MAX_RATE (10.0f) -#define AL_FLANGER_DEFAULT_RATE (0.27f) - -#define AL_FLANGER_MIN_DEPTH (0.0f) -#define AL_FLANGER_MAX_DEPTH (1.0f) -#define AL_FLANGER_DEFAULT_DEPTH (1.0f) - -#define AL_FLANGER_MIN_FEEDBACK (-1.0f) -#define AL_FLANGER_MAX_FEEDBACK (1.0f) -#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f) - -#define AL_FLANGER_MIN_DELAY (0.0f) -#define AL_FLANGER_MAX_DELAY (0.004f) -#define AL_FLANGER_DEFAULT_DELAY (0.002f) - -/* Frequency shifter effect */ -#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f) -#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f) -#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f) - -#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0) -#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2) -#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0) - -#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0) -#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1) -#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2) - -#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0) -#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2) -#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0) - -/* Vocal morpher effect */ -#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0) -#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29) -#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0) - -#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24) -#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24) -#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0) - -#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0) -#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29) -#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10) - -#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24) -#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24) -#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0) - -#define AL_VOCAL_MORPHER_PHONEME_A (0) -#define AL_VOCAL_MORPHER_PHONEME_E (1) -#define AL_VOCAL_MORPHER_PHONEME_I (2) -#define AL_VOCAL_MORPHER_PHONEME_O (3) -#define AL_VOCAL_MORPHER_PHONEME_U (4) -#define AL_VOCAL_MORPHER_PHONEME_AA (5) -#define AL_VOCAL_MORPHER_PHONEME_AE (6) -#define AL_VOCAL_MORPHER_PHONEME_AH (7) -#define AL_VOCAL_MORPHER_PHONEME_AO (8) -#define AL_VOCAL_MORPHER_PHONEME_EH (9) -#define AL_VOCAL_MORPHER_PHONEME_ER (10) -#define AL_VOCAL_MORPHER_PHONEME_IH (11) -#define AL_VOCAL_MORPHER_PHONEME_IY (12) -#define AL_VOCAL_MORPHER_PHONEME_UH (13) -#define AL_VOCAL_MORPHER_PHONEME_UW (14) -#define AL_VOCAL_MORPHER_PHONEME_B (15) -#define AL_VOCAL_MORPHER_PHONEME_D (16) -#define AL_VOCAL_MORPHER_PHONEME_F (17) -#define AL_VOCAL_MORPHER_PHONEME_G (18) -#define AL_VOCAL_MORPHER_PHONEME_J (19) -#define AL_VOCAL_MORPHER_PHONEME_K (20) -#define AL_VOCAL_MORPHER_PHONEME_L (21) -#define AL_VOCAL_MORPHER_PHONEME_M (22) -#define AL_VOCAL_MORPHER_PHONEME_N (23) -#define AL_VOCAL_MORPHER_PHONEME_P (24) -#define AL_VOCAL_MORPHER_PHONEME_R (25) -#define AL_VOCAL_MORPHER_PHONEME_S (26) -#define AL_VOCAL_MORPHER_PHONEME_T (27) -#define AL_VOCAL_MORPHER_PHONEME_V (28) -#define AL_VOCAL_MORPHER_PHONEME_Z (29) - -#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0) -#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1) -#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2) - -#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0) -#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2) -#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0) - -#define AL_VOCAL_MORPHER_MIN_RATE (0.0f) -#define AL_VOCAL_MORPHER_MAX_RATE (10.0f) -#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f) - -/* Pitch shifter effect */ -#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12) -#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12) -#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12) - -#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50) -#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50) -#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0) - -/* Ring modulator effect */ -#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f) -#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f) -#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f) - -#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f) -#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f) -#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f) - -#define AL_RING_MODULATOR_SINUSOID (0) -#define AL_RING_MODULATOR_SAWTOOTH (1) -#define AL_RING_MODULATOR_SQUARE (2) - -#define AL_RING_MODULATOR_MIN_WAVEFORM (0) -#define AL_RING_MODULATOR_MAX_WAVEFORM (2) -#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0) - -/* Autowah effect */ -#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f) -#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f) -#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f) - -#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f) -#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f) -#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f) - -#define AL_AUTOWAH_MIN_RESONANCE (2.0f) -#define AL_AUTOWAH_MAX_RESONANCE (1000.0f) -#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f) - -#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f) -#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f) -#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f) - -/* Compressor effect */ -#define AL_COMPRESSOR_MIN_ONOFF (0) -#define AL_COMPRESSOR_MAX_ONOFF (1) -#define AL_COMPRESSOR_DEFAULT_ONOFF (1) - -/* Equalizer effect */ -#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f) -#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f) -#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f) - -#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f) -#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f) -#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f) - -#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f) -#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f) -#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f) - -#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f) -#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f) -#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f) - -#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f) -#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f) -#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f) - -#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f) -#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f) -#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f) - -#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f) -#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f) -#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f) - -#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f) -#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f) -#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f) - -#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f) -#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f) -#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f) - -#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f) -#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f) -#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f) - - -/* Source parameter value ranges and defaults. */ -#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f) -#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f) -#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f) - -#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f) -#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f) -#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) - -#define AL_MIN_CONE_OUTER_GAINHF (0.0f) -#define AL_MAX_CONE_OUTER_GAINHF (1.0f) -#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f) - -#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE -#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE -#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE - -#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE -#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE -#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE - -#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE -#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE -#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE - - -/* Listener parameter value ranges and defaults. */ -#define AL_MIN_METERS_PER_UNIT FLT_MIN -#define AL_MAX_METERS_PER_UNIT FLT_MAX -#define AL_DEFAULT_METERS_PER_UNIT (1.0f) - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* AL_EFX_H */ diff --git a/src/external/include/AL_COPYING b/src/external/include/AL_COPYING deleted file mode 100644 index d0c89786..00000000 --- a/src/external/include/AL_COPYING +++ /dev/null @@ -1,484 +0,0 @@ - - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - - - Copyright (C) 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the library, or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the ordinary -GNU General Public License, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary license. - - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - GNU LIBRARY GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also compile or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - c) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - d) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the source code distributed need not include anything that is normally -distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Library General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - diff --git a/src/rglfw.c b/src/rglfw.c index 5cd2c937..6518a442 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -85,7 +85,7 @@ #include "external/glfw/src/x11_monitor.c" #include "external/glfw/src/x11_window.c" #include "external/glfw/src/xkb_unicode.c" - // TODO: Joistick implementation + // TODO: Joystick implementation #include "external/glfw/src/null_joystick.c" #include "external/glfw/src/posix_time.c" #include "external/glfw/src/posix_thread.c" diff --git a/templates/advance_game/Makefile b/templates/advance_game/Makefile index c418a3d6..9affa1ac 100644 --- a/templates/advance_game/Makefile +++ b/templates/advance_game/Makefile @@ -26,18 +26,12 @@ # Define required raylib variables # WARNING: To compile to HTML5, code must be redesigned to use emscripten.h and emscripten_set_main_loop() PLATFORM ?= PLATFORM_DESKTOP -RAYLIB_PATH ?= ..\.. +RAYLIB_PATH = ..\.. PROJECT_NAME ?= advance_game # Library type used for raylib and OpenAL Soft: STATIC (.a) or SHARED (.so/.dll) # NOTE: Libraries should be provided in the selected form RAYLIB_LIBTYPE ?= STATIC -OPENAL_LIBTYPE ?= STATIC - -# On PLATFORM_WEB force OpenAL Soft shared library -ifeq ($(PLATFORM),PLATFORM_WEB) - OPENAL_LIBTYPE = SHARED -endif # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -125,7 +119,7 @@ endif # Define compiler flags: # -O1 defines optimization level -# -Og enable debugging +# -g enable debugging # -s strip unnecessary data from build # -Wall turns on most, but not all, compiler warnings # -std=c99 defines C language mode (standard C from 1999 revision) @@ -177,37 +171,27 @@ endif # if you want to link libraries (libname.so or libname.a), use the -lname ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) - # Libraries for Windows desktop compiling - # NOTE: GLFW3 and OpenAL Soft libraries should be installed - LDLIBS = -lraylib -lglfw3 -lopengl32 -lgdi32 - - # Define required flags and libs for OpenAL Soft STATIC/SHARED usage - # NOTE: ALLIBS flag only required for raylib Win32 SHARED library building - ifeq ($(OPENAL_LIBTYPE),STATIC) - LDLIBS += -lopenal32 -lwinmm - CFLAGS += -DAL_LIBTYPE_STATIC -Wl,-allow-multiple-definition - else - LDLIBS += -lopenal32dll - endif + # Libraries for Windows desktop compilation + LDLIBS = -lraylib -lopengl32 -lgdi32 endif ifeq ($(PLATFORM_OS),LINUX) # Libraries for Debian GNU/Linux desktop compiling - # NOTE: Required packages: libglfw3-dev libopenal-dev libegl1-mesa-dev - LDLIBS = -lraylib -lglfw3 -lGL -lopenal -lm -lpthread -ldl + # NOTE: Required packages: libegl1-mesa-dev + LDLIBS = -lraylib -lGL -lm -lpthread -ldl # On XWindow requires also below libraries LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor endif ifeq ($(PLATFORM_OS),OSX) # Libraries for OSX 10.9 desktop compiling - # NOTE: Required packages: libglfw3-dev libopenal-dev libegl1-mesa-dev - LDLIBS = -lraylib -lglfw -framework OpenGL -framework OpenAL -framework Cocoa + # NOTE: Required packages: libegl1-mesa-dev + LDLIBS = -lraylib -framework OpenGL -framework OpenAL -framework Cocoa endif endif ifeq ($(PLATFORM),PLATFORM_RPI) # Libraries for Raspberry Pi compiling - # NOTE: Required packages: libopenal1 - LDLIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal + # NOTE: Required packages: libasound2-dev (ALSA) + LDLIBS = -lraylib -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -ldl endif ifeq ($(PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling diff --git a/templates/advance_game/Makefile.Android b/templates/advance_game/Makefile.Android index 1c868454..ef112b57 100644 --- a/templates/advance_game/Makefile.Android +++ b/templates/advance_game/Makefile.Android @@ -101,7 +101,7 @@ LDFLAGS += -L. -L$(PROJECT_BUILD_PATH)/obj -L$(PROJECT_BUILD_PATH)/lib/armeabi-v # Define any libraries to link into executable # if you want to link libraries (libname.so or libname.a), use the -lname -LDLIBS = -lraylib -lnative_app_glue -lopenal -llog -landroid -lEGL -lGLESv2 -lOpenSLES -latomic -lc -lm -ldl +LDLIBS = -lraylib -lnative_app_glue -llog -landroid -lEGL -lGLESv2 -lOpenSLES -latomic -lc -lm -ldl # Generate target objects list from PROJECT_SOURCE_FILES OBJS = $(patsubst %.c, $(PROJECT_BUILD_PATH)/obj/%.o, $(PROJECT_SOURCE_FILES)) @@ -278,7 +278,7 @@ logcat: deploy: $(ANDROID_PLATFORM_TOOLS)/adb install -r $(PROJECT_NAME).apk $(ANDROID_PLATFORM_TOOLS)/adb logcat -c - $(ANDROID_PLATFORM_TOOLS)/adb logcat raylib:V *:S + $(ANDROID_PLATFORM_TOOLS)/adb logcat raylib:V *:W #$(ANDROID_PLATFORM_TOOLS)/adb logcat *:W From 5ae2c0d15b349ce59425c319165505bda8298a6c Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 9 Dec 2017 19:05:42 +0100 Subject: [PATCH 066/139] Added Wayland support Updated to latest GLFW library and working on Wayland support, still looking how to implement it on raylib because it just exposes PLATFORM_DESKTOP and defaults to X11 windowing system on Linux... --- examples/Makefile | 11 +- src/Makefile | 2 +- src/external/glfw/README.md | 17 +- src/external/glfw/include/GLFW/glfw3.h | 150 +++++++-- src/external/glfw/src/CMakeLists.txt | 156 +++++++++ src/external/glfw/src/cocoa_joystick.m | 14 +- src/external/glfw/src/cocoa_platform.h | 4 + src/external/glfw/src/cocoa_window.m | 79 +++-- src/external/glfw/src/glfw_config.h.in | 3 + src/external/glfw/src/glx_context.c | 2 +- src/external/glfw/src/init.c | 29 +- src/external/glfw/src/input.c | 92 +++++- src/external/glfw/src/internal.h | 7 +- src/external/glfw/src/mappings.h | 427 ++++++++++++++----------- src/external/glfw/src/mappings.h.in | 19 +- src/external/glfw/src/mir_window.c | 23 +- src/external/glfw/src/monitor.c | 4 +- src/external/glfw/src/null_window.c | 13 +- src/external/glfw/src/osmesa_context.h | 2 +- src/external/glfw/src/win32_joystick.c | 4 +- src/external/glfw/src/win32_platform.h | 15 +- src/external/glfw/src/win32_window.c | 80 +++-- src/external/glfw/src/window.c | 32 +- src/external/glfw/src/wl_init.c | 37 +++ src/external/glfw/src/wl_platform.h | 33 +- src/external/glfw/src/wl_window.c | 39 ++- src/external/glfw/src/x11_init.c | 16 +- src/external/glfw/src/x11_monitor.c | 3 +- src/external/glfw/src/x11_platform.h | 2 + src/external/glfw/src/x11_window.c | 45 ++- src/rglfw.c | 26 +- 31 files changed, 1025 insertions(+), 361 deletions(-) create mode 100644 src/external/glfw/src/CMakeLists.txt diff --git a/examples/Makefile b/examples/Makefile index 44fd6ac3..2c627459 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -212,10 +212,15 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),LINUX) # Libraries for Debian GNU/Linux desktop compiling # NOTE: Required packages: libegl1-mesa-dev - LDLIBS = -lraylib -lGL -lm -lpthread -ldl + LDLIBS = -lraylib -lGL -lm -lpthread -ldl -lrt - # On XWindow requires also below libraries - LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + # On X11 requires also below libraries + LDLIBS += -lX11 + # NOTE: It seems additional libraries are not required any more, latest GLFW just dlopen them + #LDLIBS += -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + + # On Wayland windowing system, additional libraries requires + #LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon endif ifeq ($(PLATFORM_OS),OSX) # Libraries for OSX 10.9 desktop compiling diff --git a/src/Makefile b/src/Makefile index 83aec5dd..e3bb91cc 100644 --- a/src/Makefile +++ b/src/Makefile @@ -353,7 +353,7 @@ else ifeq ($(PLATFORM_OS),LINUX) # Compile raylib to shared library version for GNU/Linux. # WARNING: you should type "make clean" before doing this target - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lGL -lm -lpthread -ldl + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lGL -lm -lpthread -ldl -lrt @echo "raylib shared library generated (libraylib.so)!" endif ifeq ($(PLATFORM_OS),OSX) diff --git a/src/external/glfw/README.md b/src/external/glfw/README.md index 4048baf1..638d956f 100644 --- a/src/external/glfw/README.md +++ b/src/external/glfw/README.md @@ -69,7 +69,7 @@ and the API reference. ## Contributing to GLFW See the [contribution -guide](https://github.com/glfw/glfw/blob/master/.github/CONTRIBUTING.md) for +guide](https://github.com/glfw/glfw/blob/master/docs/CONTRIBUTING.md) for more information. @@ -118,7 +118,7 @@ find that tool. Bugs are reported to our [issue tracker](https://github.com/glfw/glfw/issues). Please check the [contribution -guide](https://github.com/glfw/glfw/blob/master/.github/CONTRIBUTING.md) for +guide](https://github.com/glfw/glfw/blob/master/docs/CONTRIBUTING.md) for information on what to include when reporting a bug. @@ -148,15 +148,18 @@ information on what to include when reporting a bug. - Added `glfwGetJoystickHats` function for querying joystick hats (#889,#906,#934) - Added `glfwInitHint` and `glfwInitHintString` for setting initialization hints +- Added `glfwGetWindowOpacity` and `glfwSetWindowOpacity` for controlling whole + window transparency (#1089) - Added `glfwGetX11SelectionString` and `glfwSetX11SelectionString` functions for accessing X11 primary selection (#894,#1056) - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850) - Added definition of `GLAPIENTRY` to public header -- Added `GLFW_TRANSPARENT` window hint for enabling window framebuffer - transparency (#197,#663,#715,#723,#1078) +- Added `GLFW_TRANSPARENT_FRAMEBUFFER` window hint and attribute for controlling + per-pixel framebuffer transparency (#197,#663,#715,#723,#1078) - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering (#749,#842) - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) +- Added `GLFW_LOCK_KEY_MODS` input mode and `GLFW_MOD_*_LOCK` mod bits (#946) - Added macOS specific `GLFW_COCOA_RETINA_FRAMEBUFFER` window hint - Added macOS specific `GLFW_COCOA_FRAME_AUTOSAVE` window hint (#195) - Added macOS specific `GLFW_COCOA_GRAPHICS_SWITCHING` window hint (#377,#935) @@ -168,6 +171,8 @@ information on what to include when reporting a bug. - Added `GLFW_OSMESA_CONTEXT_API` for creating OpenGL contexts with [OSMesa](https://www.mesa3d.org/osmesa.html) (#281) - Added `GenerateMappings.cmake` script for updating gamepad mappings +- Deprecated window parameter of clipboard string functions +- Deprecated charmods callback - Removed `GLFW_USE_RETINA` compile-time option - Removed `GLFW_USE_CHDIR` compile-time option - Removed `GLFW_USE_MENUBAR` compile-time option @@ -201,6 +206,7 @@ information on what to include when reporting a bug. (#650,#1071) - [Win32] Bugfix: Returned key names did not match other platforms (#943) - [Win32] Bugfix: Undecorated windows did not maximize to workarea (#899) +- [Win32] Bugfix: Window was resized twice when entering full screen (#1085) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X @@ -214,6 +220,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: Incremental reading of selections was not supported (#275) - [X11] Bugfix: Selection I/O reported but did not support `COMPOUND_TEXT` - [X11] Bugfix: Latin-1 text read from selections was not converted to UTF-8 +- [X11] Bugfix: NVidia EGL would segfault if unloaded before closing the display - [Linux] Moved to evdev for joystick input (#906,#1005) - [Linux] Bugfix: Event processing did not detect joystick disconnection (#932) - [Linux] Bugfix: The joystick device path could be truncated (#1025) @@ -241,6 +248,8 @@ information on what to include when reporting a bug. notification was shown (#971,#1028) - [Cocoa] Bugfix: Some characters did not repeat due to Press and Hold (#1010) - [Cocoa] Bugfix: Window title was lost when full screen or undecorated (#1082) +- [Cocoa] Bugfix: Window was resized twice when entering full screen (#1085) +- [Cocoa] Bugfix: Duplicate size events were not filtered (#1085) - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [WGL] Added support for `WGL_ARB_create_context_no_error` - [GLX] Added support for `GLX_ARB_create_context_no_error` diff --git a/src/external/glfw/include/GLFW/glfw3.h b/src/external/glfw/include/GLFW/glfw3.h index 6923ba68..07f8b172 100644 --- a/src/external/glfw/include/GLFW/glfw3.h +++ b/src/external/glfw/include/GLFW/glfw3.h @@ -493,17 +493,37 @@ extern "C" { * @{ */ /*! @brief If this bit is set one or more Shift keys were held down. + * + * If this bit is set one or more Shift keys were held down. */ #define GLFW_MOD_SHIFT 0x0001 /*! @brief If this bit is set one or more Control keys were held down. + * + * If this bit is set one or more Control keys were held down. */ #define GLFW_MOD_CONTROL 0x0002 /*! @brief If this bit is set one or more Alt keys were held down. + * + * If this bit is set one or more Alt keys were held down. */ #define GLFW_MOD_ALT 0x0004 /*! @brief If this bit is set one or more Super keys were held down. + * + * If this bit is set one or more Super keys were held down. */ #define GLFW_MOD_SUPER 0x0008 +/*! @brief If this bit is set the Caps Lock key is enabled. + * + * If this bit is set the Caps Lock key is enabled and the @ref + * GLFW_LOCK_KEY_MODS input mode is set. + */ +#define GLFW_MOD_CAPS_LOCK 0x0010 +/*! @brief If this bit is set the Num Lock key is enabled. + * + * If this bit is set the Num Lock key is enabled and the @ref + * GLFW_LOCK_KEY_MODS input mode is set. + */ +#define GLFW_MOD_NUM_LOCK 0x0020 /*! @} */ @@ -789,10 +809,11 @@ extern "C" { #define GLFW_CENTER_CURSOR 0x00020009 /*! @brief Window framebuffer transparency hint and attribute * - * Window framebuffer transparency [window hint](@ref GLFW_TRANSPARENT_hint) - * and [window attribute](@ref GLFW_TRANSPARENT_attrib). + * Window framebuffer transparency + * [window hint](@ref GLFW_TRANSPARENT_FRAMEBUFFER_hint) and + * [window attribute](@ref GLFW_TRANSPARENT_FRAMEBUFFER_attrib). */ -#define GLFW_TRANSPARENT 0x0002000A +#define GLFW_TRANSPARENT_FRAMEBUFFER 0x0002000A /*! @brief Framebuffer bit depth hint. * @@ -962,6 +983,7 @@ extern "C" { #define GLFW_CURSOR 0x00033001 #define GLFW_STICKY_KEYS 0x00033002 #define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 +#define GLFW_LOCK_KEY_MODS 0x00033004 #define GLFW_CURSOR_NORMAL 0x00034001 #define GLFW_CURSOR_HIDDEN 0x00034002 @@ -1383,6 +1405,8 @@ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); * @sa @ref input_char * @sa @ref glfwSetCharModsCallback * + * @deprecated Scheduled for removal in version 4.0. + * * @since Added in version 3.1. * * @ingroup input @@ -2086,8 +2110,8 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * - * @remark @wayland Gamma handling is currently unavailable, this function will - * always emit @ref GLFW_PLATFORM_ERROR. + * @remark @wayland Gamma handling is a priviledged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * @@ -2110,8 +2134,9 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * - * @remark @wayland Gamma handling is currently unavailable, this function will - * always return `NULL` and emit @ref GLFW_PLATFORM_ERROR. + * @remark @wayland Gamma handling is a priviledged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR while + * returning `NULL`. * * @pointer_lifetime The returned structure and its arrays are allocated and * freed by GLFW. You should not free them yourself. They are valid until the @@ -2153,8 +2178,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); * * @remark @win32 The gamma ramp size must be 256. * - * @remark @wayland Gamma handling is currently unavailable, this function will - * always emit @ref GLFW_PLATFORM_ERROR. + * @remark @wayland Gamma handling is a priviledged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified gamma ramp is copied before this function * returns. @@ -2288,8 +2313,8 @@ GLFWAPI void glfwWindowHint(int hint, int value); * * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it * will be set as the initial icon for the window. If no such icon is present, - * the `IDI_WINLOGO` icon will be used instead. To set a different icon, see - * @ref glfwSetWindowIcon. + * the `IDI_APPLICATION` icon will be used instead. To set a different icon, + * see @ref glfwSetWindowIcon. * * @remark @win32 The context to share resources with must not be current on * any other thread. @@ -2354,7 +2379,8 @@ GLFWAPI void glfwWindowHint(int hint, int value); * icons, the window will inherit the one defined in the application's * desktop file, so this function emits @ref GLFW_PLATFORM_ERROR. * - * @remark @wayland Screensaver inhibition is currently unimplemented. + * @remark @wayland Screensaver inhibition requires the idle-inhibit protocol + * to be implemented in the user's compositor. * * @thread_safety This function must only be called from the main thread. * @@ -2834,6 +2860,62 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int */ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* window, float* xscale, float* yscale); +/*! @brief Returns the opacity of the whole window. + * + * This function returns the opacity of the window, including any decorations. + * + * The opacity (or alpha) value is a positive finite number between zero and + * one, where zero is fully transparent and one is fully opaque. If the system + * does not support whole window transparency, this function always returns one. + * + * The initial opacity value for newly created windows is one. + * + * @param[in] window The window to query. + * @return The opacity value of the specified window. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_transparency + * @sa @ref glfwSetWindowOpacity + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI float glfwGetWindowOpacity(GLFWwindow* window); + +/*! @brief Sets the opacity of the whole window. + * + * This function sets the opacity of the window, including any decorations. + * + * The opacity (or alpha) value is a positive finite number between zero and + * one, where zero is fully transparent and one is fully opaque. + * + * The initial opacity value for newly created windows is one. + * + * A window created with framebuffer transparency may not use whole window + * transparency. The results of doing this are undefined. + * + * @param[in] window The window to set the opacity for. + * @param[in] opacity The desired opacity of the specified window. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_transparency + * @sa @ref glfwGetWindowOpacity + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowOpacity(GLFWwindow* window, float opacity); + /*! @brief Iconifies the specified window. * * This function iconifies (minimizes) the specified window if it was @@ -3596,12 +3678,12 @@ GLFWAPI void glfwPostEmptyEvent(void); /*! @brief Returns the value of an input option for the specified window. * * This function returns the value of an input option for the specified window. - * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or - * @ref GLFW_STICKY_MOUSE_BUTTONS. + * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, + * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS. * * @param[in] window The window to query. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, + * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. @@ -3619,8 +3701,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); /*! @brief Sets an input option for the specified window. * * This function sets an input mode option for the specified window. The mode - * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or - * @ref GLFW_STICKY_MOUSE_BUTTONS. + * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, + * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS. * * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor * modes: @@ -3646,9 +3728,15 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); * you are only interested in whether mouse buttons have been pressed but not * when or in which order. * + * If the mode is `GLFW_LOCK_KEY_MODS`, the value must be either `GLFW_TRUE` to + * enable lock key modifier bits, or `GLFW_FALSE` to disable them. If enabled, + * callbacks that receive modifier bits will also have the @ref + * GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on, + * and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on. + * * @param[in] window The window whose input mode to set. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, + * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`. * @param[in] value The new value of the specified input mode. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref @@ -4118,6 +4206,8 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); * @return The previously set callback, or `NULL` if no callback was set or an * [error](@ref error_handling) occurred. * + * @deprecated Scheduled for removal in version 4.0. + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -4655,7 +4745,7 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state); * This function sets the system clipboard to the specified, UTF-8 encoded * string. * - * @param[in] window The window that will own the clipboard contents. + * @param[in] window Deprecated. Any valid window or `NULL`. * @param[in] string A UTF-8 encoded string. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref @@ -4684,7 +4774,7 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); * if its contents cannot be converted, `NULL` is returned and a @ref * GLFW_FORMAT_UNAVAILABLE error is generated. * - * @param[in] window The window that will request the clipboard contents. + * @param[in] window Deprecated. Any valid window or `NULL`. * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` * if an [error](@ref error_handling) occurred. * @@ -4809,10 +4899,13 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void); * thread. * * This function makes the OpenGL or OpenGL ES context of the specified window - * current on the calling thread. A context can only be made current on + * current on the calling thread. A context must only be made current on * a single thread at a time and each thread can have only a single current * context at a time. * + * When moving a context between threads, you must make it non-current on the + * old thread before making it current on the new one. + * * By default, making a context non-current implicitly forces a pipeline flush. * On machines that support `GL_KHR_context_flush_control`, you can control * whether a context performs this flush by setting the @@ -4903,12 +4996,11 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); * is sometimes called _vertical synchronization_, _vertical retrace * synchronization_ or just _vsync_. * - * Contexts that support either of the `WGL_EXT_swap_control_tear` and - * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, - * which allow the driver to swap even if a frame arrives a little bit late. - * You can check for the presence of these extensions using @ref - * glfwExtensionSupported. For more information about swap tearing, see the - * extension specifications. + * A context that supports either of the `WGL_EXT_swap_control_tear` and + * `GLX_EXT_swap_control_tear` extensions also accepts _negative_ swap + * intervals, which allows the driver to swap immediately even if a frame + * arrives a little bit late. You can check for these extensions with @ref + * glfwExtensionSupported. * * A context must be current on the calling thread. Calling this function * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. diff --git a/src/external/glfw/src/CMakeLists.txt b/src/external/glfw/src/CMakeLists.txt new file mode 100644 index 00000000..01c01053 --- /dev/null +++ b/src/external/glfw/src/CMakeLists.txt @@ -0,0 +1,156 @@ + +set(common_HEADERS internal.h mappings.h + "${GLFW_BINARY_DIR}/src/glfw_config.h" + "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" + "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h") +set(common_SOURCES context.c init.c input.c monitor.c vulkan.c window.c) + +if (_GLFW_COCOA) + set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h + posix_thread.h nsgl_context.h egl_context.h osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m + cocoa_monitor.m cocoa_window.m cocoa_time.c posix_thread.c + nsgl_context.m egl_context.c osmesa_context.c) +elseif (_GLFW_WIN32) + set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h + wgl_context.h egl_context.h osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_joystick.c + win32_monitor.c win32_time.c win32_thread.c win32_window.c + wgl_context.c egl_context.c osmesa_context.c) +elseif (_GLFW_X11) + set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h posix_time.h + posix_thread.h glx_context.h egl_context.h osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c + xkb_unicode.c posix_time.c posix_thread.c glx_context.c + egl_context.c osmesa_context.c) + + if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + set(glfw_HEADERS ${glfw_HEADERS} linux_joystick.h) + set(glfw_SOURCES ${glfw_SOURCES} linux_joystick.c) + else() + set(glfw_HEADERS ${glfw_HEADERS} null_joystick.h) + set(glfw_SOURCES ${glfw_SOURCES} null_joystick.c) + endif() +elseif (_GLFW_WAYLAND) + set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h + posix_time.h posix_thread.h xkb_unicode.h egl_context.h + osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c + linux_joystick.c posix_time.c posix_thread.c xkb_unicode.c + egl_context.c osmesa_context.c) + + ecm_add_wayland_client_protocol(glfw_SOURCES + PROTOCOL + "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" + BASENAME relative-pointer-unstable-v1) + ecm_add_wayland_client_protocol(glfw_SOURCES + PROTOCOL + "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" + BASENAME pointer-constraints-unstable-v1) + ecm_add_wayland_client_protocol(glfw_SOURCES + PROTOCOL + ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml + BASENAME idle-inhibit-unstable-v1) +elseif (_GLFW_MIR) + set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h + posix_time.h posix_thread.h xkb_unicode.h egl_context.h + osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c + linux_joystick.c posix_time.c posix_thread.c xkb_unicode.c + egl_context.c osmesa_context.c) +elseif (_GLFW_OSMESA) + set(glfw_HEADERS ${common_HEADERS} null_platform.h null_joystick.h + posix_time.h posix_thread.h osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} null_init.c null_monitor.c null_window.c + null_joystick.c posix_time.c posix_thread.c osmesa_context.c) +endif() + +if (APPLE) + # For some reason, CMake doesn't know about .m + set_source_files_properties(${glfw_SOURCES} PROPERTIES LANGUAGE C) +endif() + +# Make GCC and Clang warn about declarations that VS 2010 and 2012 won't accept +# for all source files that VS will build +if (${CMAKE_C_COMPILER_ID} STREQUAL GNU OR ${CMAKE_C_COMPILER_ID} STREQUAL Clang) + if (WIN32) + set(windows_SOURCES ${glfw_SOURCES}) + else() + set(windows_SOURCES ${common_SOURCES}) + endif() + set_source_files_properties(${windows_SOURCES} PROPERTIES + COMPILE_FLAGS -Wdeclaration-after-statement) +endif() + +add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS}) +set_target_properties(glfw PROPERTIES + OUTPUT_NAME ${GLFW_LIB_NAME} + VERSION ${GLFW_VERSION} + SOVERSION ${GLFW_VERSION_MAJOR} + POSITION_INDEPENDENT_CODE ON + FOLDER "GLFW3") + +target_compile_definitions(glfw PRIVATE + _GLFW_USE_CONFIG_H + $<$:_XOPEN_SOURCE=600>) +target_include_directories(glfw PUBLIC + "$" + "$/include>") +target_include_directories(glfw PRIVATE + "${GLFW_SOURCE_DIR}/src" + "${GLFW_BINARY_DIR}/src" + ${glfw_INCLUDE_DIRS}) + +# HACK: When building on MinGW, WINVER and UNICODE need to be defined before +# the inclusion of stddef.h (by glfw3.h), which is itself included before +# win32_platform.h. We define them here until a saner solution can be found +# NOTE: MinGW-w64 and Visual C++ do /not/ need this hack. +target_compile_definitions(glfw PRIVATE + "$<$:UNICODE;WINVER=0x0501>") + +# Enable a reasonable set of warnings (no, -Wextra is not reasonable) +target_compile_options(glfw PRIVATE + "$<$:-Wall>" + "$<$:-Wall>") + +if (BUILD_SHARED_LIBS) + if (WIN32) + if (MINGW) + # Remove the lib prefix on the DLL (but not the import library + set_target_properties(glfw PROPERTIES PREFIX "") + + # Add a suffix to the import library to avoid naming conflicts + set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.a") + else() + # Add a suffix to the import library to avoid naming conflicts + set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.lib") + endif() + elseif (APPLE) + # Add -fno-common to work around a bug in Apple's GCC + target_compile_options(glfw PRIVATE "-fno-common") + + set_target_properties(glfw PROPERTIES + INSTALL_NAME_DIR "lib${LIB_SUFFIX}") + elseif (UNIX) + # Hide symbols not explicitly tagged for export from the shared library + target_compile_options(glfw PRIVATE "-fvisibility=hidden") + endif() + + target_compile_definitions(glfw INTERFACE GLFW_DLL) + target_link_libraries(glfw PRIVATE ${glfw_LIBRARIES}) +else() + target_link_libraries(glfw INTERFACE ${glfw_LIBRARIES}) +endif() + +if (MSVC) + target_compile_definitions(glfw PRIVATE _CRT_SECURE_NO_WARNINGS) +endif() + +if (GLFW_INSTALL) + install(TARGETS glfw + EXPORT glfwTargets + RUNTIME DESTINATION "bin" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + LIBRARY DESTINATION "lib${LIB_SUFFIX}") +endif() + diff --git a/src/external/glfw/src/cocoa_joystick.m b/src/external/glfw/src/cocoa_joystick.m index 3a5751ef..0831809f 100644 --- a/src/external/glfw/src/cocoa_joystick.m +++ b/src/external/glfw/src/cocoa_joystick.m @@ -247,9 +247,9 @@ static void matchCallback(void* context, compareElements, NULL); js = _glfwAllocJoystick(name, guid, - CFArrayGetCount(axes), - CFArrayGetCount(buttons), - CFArrayGetCount(hats)); + (int) CFArrayGetCount(axes), + (int) CFArrayGetCount(buttons), + (int) CFArrayGetCount(hats)); js->ns.device = device; js->ns.axes = axes; @@ -399,11 +399,11 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) const long delta = axis->maximum - axis->minimum; if (delta == 0) - _glfwInputJoystickAxis(js, i, 0.f); + _glfwInputJoystickAxis(js, (int) i, 0.f); else { const float value = (2.f * (raw - axis->minimum) / delta) - 1.f; - _glfwInputJoystickAxis(js, i, value); + _glfwInputJoystickAxis(js, (int) i, value); } } } @@ -417,7 +417,7 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) _GLFWjoyelementNS* button = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.buttons, i); const char value = getElementValue(js, button) - button->minimum; - _glfwInputJoystickButton(js, i, value); + _glfwInputJoystickButton(js, (int) i, value); } for (i = 0; i < CFArrayGetCount(js->ns.hats); i++) @@ -441,7 +441,7 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) if (state < 0 || state > 8) state = 8; - _glfwInputJoystickHat(js, i, states[state]); + _glfwInputJoystickHat(js, (int) i, states[state]); } } diff --git a/src/external/glfw/src/cocoa_platform.h b/src/external/glfw/src/cocoa_platform.h index 61d0ee91..d5cc2379 100644 --- a/src/external/glfw/src/cocoa_platform.h +++ b/src/external/glfw/src/cocoa_platform.h @@ -88,6 +88,10 @@ typedef struct _GLFWwindowNS GLFWbool maximized; + // Cached window and framebuffer sizes used to filter out duplicate events + int width, height; + int fbWidth, fbHeight; + // The total sum of the distances the cursor has been warped // since the last cursor motion event was processed // This is kept to counteract Cocoa doing the same internally diff --git a/src/external/glfw/src/cocoa_window.m b/src/external/glfw/src/cocoa_window.m index 1ee85bc6..cbea7374 100644 --- a/src/external/glfw/src/cocoa_window.m +++ b/src/external/glfw/src/cocoa_window.m @@ -43,6 +43,7 @@ #define NSEventModifierFlagControl NSControlKeyMask #define NSEventModifierFlagOption NSAlternateKeyMask #define NSEventModifierFlagShift NSShiftKeyMask + #define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask #define NSEventMaskAny NSAnyEventMask #define NSEventTypeApplicationDefined NSApplicationDefined @@ -177,6 +178,8 @@ static int translateFlags(NSUInteger flags) mods |= GLFW_MOD_ALT; if (flags & NSEventModifierFlagCommand) mods |= GLFW_MOD_SUPER; + if (flags & NSEventModifierFlagCapsLock) + mods |= GLFW_MOD_CAPS_LOCK; return mods; } @@ -267,8 +270,21 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; - _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); - _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); + if (fbRect.size.width != window->ns.fbWidth || + fbRect.size.height != window->ns.fbHeight) + { + window->ns.fbWidth = fbRect.size.width; + window->ns.fbHeight = fbRect.size.height; + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + } + + if (contentRect.size.width != window->ns.width || + contentRect.size.height != window->ns.height) + { + window->ns.width = contentRect.size.width; + window->ns.height = contentRect.size.height; + _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); + } } - (void)windowDidMove:(NSNotification *)notification @@ -551,7 +567,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; - _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + if (fbRect.size.width != window->ns.fbWidth || + fbRect.size.height != window->ns.fbHeight) + { + window->ns.fbWidth = fbRect.size.width; + window->ns.fbHeight = fbRect.size.height; + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + } } - (void)drawRect:(NSRect)rect @@ -667,17 +689,17 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; [sender draggingLocation].x, contentRect.size.height - [sender draggingLocation].y); - const int count = [files count]; + const NSUInteger count = [files count]; if (count) { NSEnumerator* e = [files objectEnumerator]; char** paths = calloc(count, sizeof(char*)); - int i; + NSUInteger i; for (i = 0; i < count; i++) paths[i] = strdup([[e nextObject] UTF8String]); - _glfwInputDrop(window, count, (const char**) paths); + _glfwInputDrop(window, (int) count, (const char**) paths); for (i = 0; i < count; i++) free(paths[i]); @@ -1095,6 +1117,9 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, [window->ns.object setAcceptsMouseMovedEvents:YES]; [window->ns.object setRestorable:NO]; + _glfwPlatformGetWindowSize(window, &window->ns.width, &window->ns.height); + _glfwPlatformGetFramebufferSize(window, &window->ns.fbWidth, &window->ns.fbHeight); + return GLFW_TRUE; } @@ -1385,28 +1410,6 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, [window->ns.object setStyleMask:styleMask]; [window->ns.object makeFirstResponder:window->ns.view]; - NSRect contentRect; - - if (monitor) - { - GLFWvidmode mode; - - _glfwPlatformGetVideoMode(window->monitor, &mode); - _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); - - contentRect = NSMakeRect(xpos, transformY(ypos + mode.height), - mode.width, mode.height); - } - else - { - contentRect = NSMakeRect(xpos, transformY(ypos + height), - width, height); - } - - NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect - styleMask:styleMask]; - [window->ns.object setFrame:frameRect display:YES]; - if (monitor) { [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; @@ -1416,6 +1419,12 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, } else { + NSRect contentRect = NSMakeRect(xpos, transformY(ypos + height), + width, height); + NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect + styleMask:styleMask]; + [window->ns.object setFrame:frameRect display:YES]; + if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) { @@ -1493,6 +1502,16 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) [window->ns.object setLevel:NSNormalWindowLevel]; } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return (float) [window->ns.object alphaValue]; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ + [window->ns.object setAlphaValue:opacity]; +} + void _glfwPlatformPollEvents(void) { for (;;) @@ -1740,7 +1759,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) updateCursorImage(window); } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil]; @@ -1750,7 +1769,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) forType:NSStringPboardType]; } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; diff --git a/src/external/glfw/src/glfw_config.h.in b/src/external/glfw/src/glfw_config.h.in index bc9f5d3e..0b47945c 100644 --- a/src/external/glfw/src/glfw_config.h.in +++ b/src/external/glfw/src/glfw_config.h.in @@ -55,3 +55,6 @@ // Define this to 1 to force use of high-performance GPU on hybrid systems #cmakedefine _GLFW_USE_HYBRID_HPG +// Define this to 1 if xkbcommon supports the compose key +#cmakedefine HAVE_XKBCOMMON_COMPOSE_H + diff --git a/src/external/glfw/src/glx_context.c b/src/external/glfw/src/glx_context.c index 708663a9..40da6c2f 100644 --- a/src/external/glfw/src/glx_context.c +++ b/src/external/glfw/src/glx_context.c @@ -634,7 +634,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, // Returns the Visual and depth of the chosen GLXFBConfig // GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth) { diff --git a/src/external/glfw/src/init.c b/src/external/glfw/src/init.c index 19a13e0d..ae82831b 100644 --- a/src/external/glfw/src/init.c +++ b/src/external/glfw/src/init.c @@ -205,12 +205,13 @@ GLFWAPI int glfwInit(void) return GLFW_FALSE; } - if (!_glfwPlatformCreateMutex(&_glfw.errorLock)) - return GLFW_FALSE; - if (!_glfwPlatformCreateTls(&_glfw.errorSlot)) - return GLFW_FALSE; - if (!_glfwPlatformCreateTls(&_glfw.contextSlot)) + if (!_glfwPlatformCreateMutex(&_glfw.errorLock) || + !_glfwPlatformCreateTls(&_glfw.errorSlot) || + !_glfwPlatformCreateTls(&_glfw.contextSlot)) + { + terminate(); return GLFW_FALSE; + } _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); @@ -218,7 +219,19 @@ GLFWAPI int glfwInit(void) _glfw.timer.offset = _glfwPlatformGetTimerValue(); glfwDefaultWindowHints(); - glfwUpdateGamepadMappings(_glfwDefaultMappings); + + { + int i; + + for (i = 0; _glfwDefaultMappings[i]; i++) + { + if (!glfwUpdateGamepadMappings(_glfwDefaultMappings[i])) + { + terminate(); + return GLFW_FALSE; + } + } + } return GLFW_TRUE; } @@ -259,11 +272,11 @@ GLFWAPI void glfwInitHintString(int hint, const char* value) case GLFW_X11_WM_CLASS_NAME: strncpy(_glfwInitHints.x11.className, value, sizeof(_glfwInitHints.x11.className) - 1); - break; + return; case GLFW_X11_WM_CLASS_CLASS: strncpy(_glfwInitHints.x11.classClass, value, sizeof(_glfwInitHints.x11.classClass) - 1); - break; + return; } _glfwInputError(GLFW_INVALID_ENUM, diff --git a/src/external/glfw/src/input.c b/src/external/glfw/src/input.c index 7d9ff774..88a27fa3 100644 --- a/src/external/glfw/src/input.c +++ b/src/external/glfw/src/input.c @@ -57,6 +57,58 @@ static _GLFWmapping* findMapping(const char* guid) return NULL; } +// Checks whether a gamepad mapping element is present in the hardware +// +static GLFWbool isValidElementForJoystick(const _GLFWmapelement* e, + const _GLFWjoystick* js) +{ + if (e->type == _GLFW_JOYSTICK_HATBIT && (e->value >> 4) >= js->hatCount) + return GLFW_FALSE; + else if (e->type == _GLFW_JOYSTICK_BUTTON && e->value >= js->buttonCount) + return GLFW_FALSE; + else if (e->type == _GLFW_JOYSTICK_AXIS && e->value >= js->axisCount) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +// Finds a mapping based on joystick GUID and verifies element indices +// +static _GLFWmapping* findValidMapping(const _GLFWjoystick* js) +{ + _GLFWmapping* mapping = findMapping(js->guid); + if (mapping) + { + int i; + + for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) + { + if (!isValidElementForJoystick(mapping->buttons + i, js)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid button in gamepad mapping %s (%s)", + mapping->guid, + mapping->name); + return NULL; + } + } + + for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) + { + if (!isValidElementForJoystick(mapping->axes + i, js)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid axis in gamepad mapping %s (%s)", + mapping->guid, + mapping->name); + return NULL; + } + } + } + + return mapping; +} + // Parses an SDL_GameControllerDB line and adds it to the mapping list // static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) @@ -136,9 +188,9 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) if (fields[i].element->type == _GLFW_JOYSTICK_HATBIT) { - const unsigned int hat = strtoul(c + 1, (char**) &c, 10); - const unsigned int bit = strtoul(c + 1, (char**) &c, 10); - fields[i].element->value = (hat << 4) | bit; + const unsigned long hat = strtoul(c + 1, (char**) &c, 10); + const unsigned long bit = strtoul(c + 1, (char**) &c, 10); + fields[i].element->value = (uint8_t) ((hat << 4) | bit); } else fields[i].element->value = (uint8_t) strtoul(c + 1, (char**) &c, 10); @@ -193,6 +245,9 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m action = GLFW_REPEAT; } + if (!window->lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + if (window->callbacks.key) window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods); } @@ -202,6 +257,9 @@ void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWb if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) return; + if (!window->lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + if (window->callbacks.charmods) window->callbacks.charmods((GLFWwindow*) window, codepoint, mods); @@ -223,6 +281,9 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) return; + if (!window->lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + if (action == GLFW_RELEASE && window->stickyMouseButtons) window->mouseButtons[button] = _GLFW_STICK; else @@ -318,9 +379,9 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, js->axisCount = axisCount; js->buttonCount = buttonCount; js->hatCount = hatCount; - js->mapping = findMapping(guid); strcpy(js->guid, guid); + js->mapping = findValidMapping(js); return js; } @@ -354,6 +415,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) return window->stickyKeys; case GLFW_STICKY_MOUSE_BUTTONS: return window->stickyMouseButtons; + case GLFW_LOCK_KEY_MODS: + return window->lockKeyMods; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); @@ -409,7 +472,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) } } - window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE; + window->stickyKeys = value; } else if (mode == GLFW_STICKY_MOUSE_BUTTONS) { @@ -429,8 +492,10 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) } } - window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE; + window->stickyMouseButtons = value; } + else if (mode == GLFW_LOCK_KEY_MODS) + window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; else _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); } @@ -973,7 +1038,7 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string) { _GLFWjoystick* js = _glfw.joysticks + jid; if (js->present) - js->mapping = findMapping(js->guid); + js->mapping = findValidMapping(js); } return GLFW_TRUE; @@ -1085,8 +1150,8 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) state->axes[i] = js->axes[js->mapping->axes[i].value]; else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT) { - const unsigned int hat = js->mapping->buttons[i].value >> 4; - const unsigned int bit = js->mapping->buttons[i].value & 0xf; + const unsigned int hat = js->mapping->axes[i].value >> 4; + const unsigned int bit = js->mapping->axes[i].value & 0xf; if (js->hats[hat] & bit) state->axes[i] = 1.f; } @@ -1099,21 +1164,16 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) { - _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window != NULL); assert(string != NULL); _GLFW_REQUIRE_INIT(); - _glfwPlatformSetClipboardString(window, string); + _glfwPlatformSetClipboardString(string); } GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) { - _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window != NULL); - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return _glfwPlatformGetClipboardString(window); + return _glfwPlatformGetClipboardString(); } GLFWAPI double glfwGetTime(void) diff --git a/src/external/glfw/src/internal.h b/src/external/glfw/src/internal.h index 485d9434..84d096c4 100644 --- a/src/external/glfw/src/internal.h +++ b/src/external/glfw/src/internal.h @@ -419,6 +419,7 @@ struct _GLFWwindow GLFWbool stickyKeys; GLFWbool stickyMouseButtons; + GLFWbool lockKeyMods; int cursorMode; char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1]; char keys[GLFW_KEY_LAST + 1]; @@ -649,8 +650,8 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string); -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window); +void _glfwPlatformSetClipboardString(const char* string); +const char* _glfwPlatformGetClipboardString(void); int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode); void _glfwPlatformUpdateGamepadGUID(char* guid); @@ -687,9 +688,11 @@ int _glfwPlatformWindowIconified(_GLFWwindow* window); int _glfwPlatformWindowVisible(_GLFWwindow* window); int _glfwPlatformWindowMaximized(_GLFWwindow* window); int _glfwPlatformFramebufferTransparent(_GLFWwindow* window); +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window); void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity); void _glfwPlatformPollEvents(void); void _glfwPlatformWaitEvents(void); diff --git a/src/external/glfw/src/mappings.h b/src/external/glfw/src/mappings.h index 6c1b800d..dd747608 100644 --- a/src/external/glfw/src/mappings.h +++ b/src/external/glfw/src/mappings.h @@ -58,184 +58,253 @@ // // 3. This notice may not be removed or altered from any source distribution. -const char* _glfwDefaultMappings = -"8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" -"ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,\n" -"6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" -"0d0f6e00000000000000504944564944,HORIPAD 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,\n" -"88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,\n" -"4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,\n" -"25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,\n" -"4c05c405000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" -"4c05cc09000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" -"4c05a00b000000000000504944564944,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,\n" -"6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13,\n" -"4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" -"00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,\n" -"00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,\n" -"28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" -"ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,\n" -"8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5,\n" -"79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" -"4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows,\n" -"10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,\n" -"4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"300f1001000000000000504944564944,Saitek P480 Rumble Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,\n" -"10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows,\n" -"63252305000000000000504944564944,USB Vibration Joystick (BM),platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"ff113133000000000000504944564944,Gembird JPD-DualForce,platform:Windows,a:b2,b:b3,x:b0,y:b1,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,leftstick:b10,rightstick:b11,\n" -"341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,\n" -"c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1,\n" -"100801e5000000000000504944564944,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Windows,\n" -"79000600000000000000504944564944,NGS Phantom,a:b2,b:b3,y:b1,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,\n" -"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,\n" -"6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" -"6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" -"6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" -"6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,\n" -"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,\n" -"4c05000000000000c405000000000000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" -"4c05000000000000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,\n" -"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" -"891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X,\n" -"4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X,\n" -"8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" -"4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"AD1B00000000000001F9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,\n" -"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X,\n" -"83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"79000000000000001100000000000000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a3,lefty:a4,platform:Mac OS X,\n" -"5e04000000000000dd02000000000000,Xbox One Wired Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"5e04000000000000ea02000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"5e04000000000000e002000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b10,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X,\n" -"79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X,\n" -"2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,\n" -"351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"81170000000000007e05000000000000,Sega Saturn,x:b0,a:b2,b:b4,y:b6,start:b13,dpleft:b15,dpdown:b16,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,lefttrigger:b10,rightshoulder:b9,righttrigger:a4,righttrigger:b11,leftx:a0,lefty:a2,platform:Mac OS X,\n" -"10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,\n" -"d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7,\n" -"0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4,\n" -"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,\n" -"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,\n" -"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,\n" -"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000006d04000016c2000011010000,Logitech F310 Gamepad (DInput),x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,\n" -"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,\n" -"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,\n" -"030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" -"050000004c050000c405000000010000,Sony DualShock 4 BT,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,\n" -"030000004c050000cc09000011010000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" -"050000004c050000cc09000000010000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" -"030000004c050000a00b000011010000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,\n" -"030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,\n" -"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" -"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" -"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" -"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,\n" -"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,\n" -"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" -"030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,\n" -"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux,\n" -"030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,\n" -"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,\n" -"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" -"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,\n" -"030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,\n" -"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,\n" -"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" -"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,\n" -"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,\n" -"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" -"050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,\n" -"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a3,rightx:a1,righty:a4,\n" -"03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,\n" -"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" -"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,\n" -"030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" -"03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" -"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,\n" -"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,\n" -"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,\n" -"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7\n" -"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" -"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" -"03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" -"03000000790000001100000010010000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,\n" -"03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux,\n" -"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,\n" -"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux,\n" -"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,\n" -"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,\n" -"05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" -"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1,\n" -"030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5,\n" -"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,\n" -"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,\n" -"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,\n" -"05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,\n" -"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux,\n" -"030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,\n" -"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,\n" -"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:a2,righttrigger:a5,\n" -"05000000a00500003232000001000000,8Bitdo Zero GamePad,platform:Linux,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,\n" -"030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Linux,\n" -"03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" -"05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,\n" -"03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1,\n" +const char* _glfwDefaultMappings[] = +{ +"02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows,", +"8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1,", +"d81d0b00000000000000504944564944,BUFFALO BSGP1601 Series ,platform:Windows,x:b4,a:b5,b:b3,y:b2,back:b12,start:b13,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b6,rightshoulder:b9,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"5e048e02000000000000504944564944,Controller (XBOX 360 For Windows),platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,righttrigger:a2,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,", +"0d0f8500000000000000504944564944,Fighting Commander 2016 PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f5f00000000000000504944564944,Fighting Commander 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f5e00000000000000504944564944,Fighting Commander 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a4,righttrigger:a3,platform:Windows,", +"0d0f8400000000000000504944564944,Fighting Commander 5,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f8700000000000000504944564944,Fighting Stick mini 4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f8800000000000000504944564944,Fighting Stick mini 4,a:b1,b:b2,x:b0,y:b3,back:b9,guide:b12,start:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f2700000000000000504944564944,FIGHTING STICK V3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,", +"ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"45130010000000000000504944564944,Generic USB Joystick,a:b0,b:b1,x:b2,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"d8140862000000000000504944564944,HitBox Edition Cthulhu+,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b4,righttrigger:b6,platform:Windows,", +"0d0f4000000000000000504944564944,Hori Fighting Stick Mini 3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b4,righttrigger:b6,platform:Windows,", +"0d0f6e00000000000000504944564944,HORIPAD 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f4d00000000000000504944564944,HORIPAD3 A,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"25090017000000000000504944564944,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b5,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b6,platform:Windows,", +"d81d0f00000000000000504944564944,iBUFFALO BSGP1204 Series,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"d81d1000000000000000504944564944,iBUFFALO BSGP1204P Series,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows,", +"6f0e2401000000000000504944564944,INJUSTICE FightStick for PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Windows", +"49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,", +"6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"38075032000000000000504944564944,Mad Catz FightPad PRO PS3,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"38075082000000000000504944564944,Mad Catz FightPad PRO PS4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b13,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", +"38078433000000000000504944564944,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"38078483000000000000504944564944,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:b6,platform:Windows,", +"38078134000000000000504944564944,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b7,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b4,platform:Windows,", +"38078184000000000000504944564944,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a4,righttrigger:b7,platform:Windows,", +"38078034000000000000504944564944,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"38078084000000000000504944564944,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", +"38078532000000000000504944564944,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"38073888000000000000504944564944,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"38071888000000000000504944564944,MadCatz SFIV FightStick PS3,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b6,platform:Windows,", +"03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"25090128000000000000504944564944,Mayflash Arcade Stick,a:b1,b:b2,x:b5,y:b6,back:b8,start:b9,leftshoulder:b0,rightshoulder:b3,leftx:a0,lefty:a1,rightx:h0.4,righty:h0.0,lefttrigger:b4,righttrigger:b7,platform:Windows,", +"79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", +"8f0e1030000000000000504944564944,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,x:b3,y:b4,start:b9,leftshoulder:b6,rightshoulder:b2,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b5,righttrigger:b7,platform:Windows,", +"2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"100801e5000000000000504944564944,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Windows,", +"bd1215d0000000000000504944564944,Nintendo Retrolink USB Super SNES Classic Controller,y:b0,b:b1,a:b2,x:b3,leftshoulder:b4,rightshoulder:b5,start:b9,back:b8,leftx:a0,lefty:a1,platform:Windows,", +"4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13,", +"120cf60e000000000000504944564944,P4 Wired Gamepad,a:b1,b:b2,x:b0,y:b3,back:b12,guide:b8,start:b9,leftshoulder:b5,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:h0.0,lefttrigger:b7,righttrigger:b6,platform:Windows,", +"8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", +"10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5,", +"88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,", +"4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,", +"25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,", +"10008200000000000000504944564944,PS360+ v1.66,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"300f0011000000000000504944564944,QanBa Arcade JoyStick 1008,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b10,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,", +"300f1611000000000000504944564944,QanBa Arcade JoyStick 4018,a:b1,b:b2,x:b0,y:b3,back:b10,guide:b9,start:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"222c0020000000000000504944564944,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:a3,righttrigger:a4,platform:Windows,", +"300f1210000000000000504944564944,QanBa Joystick Plus,a:b0,b:b1,x:b2,y:b3,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Windows,", +"341a0104000000000000504944564944,QanBa Joystick Q4RAF,a:b5,b:b6,x:b1,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b0,rightshoulder:b3,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b7,platform:Windows,", +"222c0223000000000000504944564944,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"222c0023000000000000504944564944,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,x:b0,y:b3,back:b13,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", +"0d0f1100000000000000504944564944,REAL ARCADE PRO.3,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f8b00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"0d0f8a00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", +"0d0f6b00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"0d0f6a00000000000000504944564944,Real Arcade Pro.4,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", +"0d0f7000000000000000504944564944,REAL ARCADE PRO.4 VLX,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"0d0f2200000000000000504944564944,REAL ARCADE Pro.V3,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,", +"00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,", +"6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", +"300f1201000000000000504944564944,Saitek Dual Analog Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,", +"a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,", +"300f1001000000000000504944564944,Saitek P480 Rumble Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows,", +"9b280500000000000000504944564944,Saturn_Adapter_2.0,a:b1,b:b2,x:b0,y:b3,start:b9,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b5,platform:Windows,", +"79001100000000000000504944564944,Sega Saturn Gamepad,a:b1,b:b2,x:b4,y:b5,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a4,lefttrigger:b3,righttrigger:b0,platform:Windows,", +"4c05cc09000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", +"4c05a00b000000000000504944564944,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows,", +"ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,", +"4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows,", +"66660488000000000000504944564944,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:b12,dpdown:b14,dpleft:b15,dpright:b13,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,platform:Windows,", +"38076652000000000000504944564944,UnKnown,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"63252305000000000000504944564944,USB Vibration Joystick (BM),platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"79001b18000000000000504944564944,Venom Arcade Joystick,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows,", +"10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,", +"79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,", +"AD1B00000000000001F9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,", +"0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4,", +"83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,", +"6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,", +"79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X,", +"d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7,", +"8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,", +"4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X,", +"79000000000000001100000000000000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a3,lefty:a4,platform:Mac OS X,", +"81170000000000007e05000000000000,Sega Saturn,x:b0,a:b2,b:b4,y:b6,start:b13,dpleft:b15,dpdown:b16,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,lefttrigger:b10,rightshoulder:b9,righttrigger:a4,righttrigger:b11,leftx:a0,lefty:a2,platform:Mac OS X,", +"b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,", +"351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X,", +"4c05000000000000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,", +"4c05000000000000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,", +"4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X,", +"bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,", +"10080000000000000100000000000000,Twin USB Joystick,a:b4,b:b2,x:b6,y:b0,back:b16,start:b18,leftstick:b20,rightstick:b22,leftshoulder:b12,rightshoulder:b14,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a2,rightx:a6,righty:a4,lefttrigger:b8,righttrigger:b10,platform:Mac OS X,", +"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X,", +"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X,", +"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"5e04000000000000dd02000000000000,Xbox One Wired Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"5e04000000000000ea02000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"5e04000000000000e002000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b10,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", +"05000000a00500003232000001000000,8Bitdo Zero GamePad,platform:Linux,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", +"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,", +"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux,", +"03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,", +"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", +"030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,", +"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"03000000ff1100004133000010010000,GreenAsia Inc.USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"06000000adde0000efbe000002010000,Hidromancer Game Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1,", +"03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux,", +"030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5,", +"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7", +"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,", +"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", +"03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,", +"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,", +"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", +"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,", +"030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000006d04000016c2000011010000,Logitech F310 Gamepad (DInput),x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,", +"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux,", +"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:a2,righttrigger:a5,", +"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,", +"03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1,", +"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", +"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux,", +"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,", +"030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Linux,", +"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,", +"05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux,", +"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,", +"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,", +"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,", +"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,", +"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,", +"050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,", +"05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,", +"030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,platform:Linux,x:b1,a:b0,b:b4,y:b5,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", +"030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", +"03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", +"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,", +"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux,", +"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", +"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux,", +"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,", +"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux,", +"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,platform:Linux,a:b12,b:b10,x:b13,y:b11,back:b4,start:b5,leftstick:b14,rightstick:b15,leftshoulder:b9,rightshoulder:b8,dpup:b0,dpdown:b2,dpleft:b3,dpright:b1,leftx:a1,lefty:a0,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"030000004c050000c405000011810000,Sony DualShock 4,a:b0,b:b1,y:b2,x:b3,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", +"030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux,", +"050000004c050000cc09000000810000,Sony DualShock 4 (CUH-ZCT2U) (Bluetooth),platform:Linux,a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"030000004c050000cc09000011810000,Sony DualShock 4 (CUH-ZCT2U) (USB),platform:Linux,a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"050000004c050000c405000000010000,Sony DualShock 4 BT,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000004c050000cc09000011010000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,", +"050000004c050000cc09000000010000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,", +"030000004c050000a00b000011010000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,", +"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,", +"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", +"03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,", +"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,", +"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,", +"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", +"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux,", +"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,", +"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", +"03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux,", +"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,", +"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux,", +"03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,", +"03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,", +"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,", +"030000005e040000a102000000010000,X360 Wireless Controller,platform:Linux,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", +"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3,", +"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,platform:Linux,y:b0,x:b1,b:b3,a:b4,leftshoulder:b2,rightshoulder:b5,back:b6,start:b7,guide:b9,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftx:a0,lefty:a1,", -"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n"; +"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +NULL +}; diff --git a/src/external/glfw/src/mappings.h.in b/src/external/glfw/src/mappings.h.in index bf720670..207d40b9 100644 --- a/src/external/glfw/src/mappings.h.in +++ b/src/external/glfw/src/mappings.h.in @@ -58,13 +58,16 @@ // // 3. This notice may not be removed or altered from any source distribution. -const char* _glfwDefaultMappings = +const char* _glfwDefaultMappings[] = +{ @GLFW_GAMEPAD_MAPPINGS@ -"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n" -"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,\n"; +"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +NULL +}; diff --git a/src/external/glfw/src/mir_window.c b/src/external/glfw/src/mir_window.c index c752cdb4..ad06cb07 100644 --- a/src/external/glfw/src/mir_window.c +++ b/src/external/glfw/src/mir_window.c @@ -117,12 +117,16 @@ static int mirModToGLFWMod(uint32_t mods) if (mods & mir_input_event_modifier_alt) publicMods |= GLFW_MOD_ALT; - else if (mods & mir_input_event_modifier_shift) + if (mods & mir_input_event_modifier_shift) publicMods |= GLFW_MOD_SHIFT; - else if (mods & mir_input_event_modifier_ctrl) + if (mods & mir_input_event_modifier_ctrl) publicMods |= GLFW_MOD_CONTROL; - else if (mods & mir_input_event_modifier_meta) + if (mods & mir_input_event_modifier_meta) publicMods |= GLFW_MOD_SUPER; + if (mods & mir_input_event_modifier_caps_lock) + publicMods |= GLFW_MOD_CAPS_LOCK; + if (mods & mir_input_event_modifier_num_lock) + publicMods |= GLFW_MOD_NUM_LOCK; return publicMods; } @@ -648,6 +652,15 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) "Mir: Unsupported function %s", __PRETTY_FUNCTION__); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ +} + void _glfwPlatformPollEvents(void) { EventNode* node = NULL; @@ -858,13 +871,13 @@ int _glfwPlatformGetKeyScancode(int key) return _glfw.mir.scancodes[key]; } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { _glfwInputError(GLFW_PLATFORM_ERROR, "Mir: Unsupported function %s", __PRETTY_FUNCTION__); } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { _glfwInputError(GLFW_PLATFORM_ERROR, "Mir: Unsupported function %s", __PRETTY_FUNCTION__); diff --git a/src/external/glfw/src/monitor.c b/src/external/glfw/src/monitor.c index 0dfb1958..6f64cca5 100644 --- a/src/external/glfw/src/monitor.c +++ b/src/external/glfw/src/monitor.c @@ -113,9 +113,11 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) { if (window->monitor == monitor) { - int width, height; + int width, height, xoff, yoff; _glfwPlatformGetWindowSize(window, &width, &height); _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0); + _glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, NULL, NULL); + _glfwPlatformSetWindowPos(window, xoff, yoff); } } diff --git a/src/external/glfw/src/null_window.c b/src/external/glfw/src/null_window.c index 3cc3905d..6eb4ac6e 100644 --- a/src/external/glfw/src/null_window.c +++ b/src/external/glfw/src/null_window.c @@ -182,6 +182,15 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ +} + void _glfwPlatformShowWindow(_GLFWwindow* window) { } @@ -266,11 +275,11 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { return NULL; } diff --git a/src/external/glfw/src/osmesa_context.h b/src/external/glfw/src/osmesa_context.h index e6ae5781..07bb469a 100644 --- a/src/external/glfw/src/osmesa_context.h +++ b/src/external/glfw/src/osmesa_context.h @@ -37,7 +37,7 @@ #define OSMESA_CONTEXT_MINOR_VERSION 0x37 typedef void* OSMesaContext; -typedef void (*OSMESAproc)(); +typedef void (*OSMESAproc)(void); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext); diff --git a/src/external/glfw/src/win32_joystick.c b/src/external/glfw/src/win32_joystick.c index ad2dbb2f..d9d341ff 100644 --- a/src/external/glfw/src/win32_joystick.c +++ b/src/external/glfw/src/win32_joystick.c @@ -711,9 +711,9 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) return GLFW_TRUE; _glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.5f); - _glfwInputJoystickAxis(js, 1, (xis.Gamepad.sThumbLY + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 1, -(xis.Gamepad.sThumbLY + 0.5f) / 32767.5f); _glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.5f); - _glfwInputJoystickAxis(js, 3, (xis.Gamepad.sThumbRY + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 3, -(xis.Gamepad.sThumbRY + 0.5f) / 32767.5f); _glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.f); _glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.f); diff --git a/src/external/glfw/src/win32_platform.h b/src/external/glfw/src/win32_platform.h index 1bfc638f..73bcb49b 100644 --- a/src/external/glfw/src/win32_platform.h +++ b/src/external/glfw/src/win32_platform.h @@ -105,12 +105,11 @@ #endif #if WINVER < 0x0601 -typedef struct tagCHANGEFILTERSTRUCT +typedef struct { DWORD cbSize; DWORD ExtStatus; - -} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT; +} CHANGEFILTERSTRUCT; #ifndef MSGFLT_ALLOW #define MSGFLT_ALLOW 1 #endif @@ -129,13 +128,13 @@ typedef struct #endif /*Windows Vista*/ #ifndef DPI_ENUMS_DECLARED -typedef enum PROCESS_DPI_AWARENESS +typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; -typedef enum MONITOR_DPI_TYPE +typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, @@ -209,7 +208,7 @@ typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID* // user32.dll function pointer typedefs typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void); -typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); +typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*); #define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_ #define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_ @@ -348,8 +347,8 @@ typedef struct _GLFWmonitorWin32 // This size matches the static size of DISPLAY_DEVICE.DeviceName WCHAR adapterName[32]; WCHAR displayName[32]; - char publicAdapterName[64]; - char publicDisplayName[64]; + char publicAdapterName[32]; + char publicDisplayName[32]; GLFWbool modesPruned; GLFWbool modeChanged; diff --git a/src/external/glfw/src/win32_window.c b/src/external/glfw/src/win32_window.c index 6d3e76cc..60b2f275 100644 --- a/src/external/glfw/src/win32_window.c +++ b/src/external/glfw/src/win32_window.c @@ -384,14 +384,18 @@ static int getKeyMods(void) { int mods = 0; - if (GetKeyState(VK_SHIFT) & (1 << 31)) + if (GetKeyState(VK_SHIFT) & 0x8000) mods |= GLFW_MOD_SHIFT; - if (GetKeyState(VK_CONTROL) & (1 << 31)) + if (GetKeyState(VK_CONTROL) & 0x8000) mods |= GLFW_MOD_CONTROL; - if (GetKeyState(VK_MENU) & (1 << 31)) + if (GetKeyState(VK_MENU) & 0x8000) mods |= GLFW_MOD_ALT; - if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31)) + if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) mods |= GLFW_MOD_SUPER; + if (GetKeyState(VK_CAPITAL) & 1) + mods |= GLFW_MOD_CAPS_LOCK; + if (GetKeyState(VK_NUMLOCK) & 1) + mods |= GLFW_MOD_NUM_LOCK; return mods; } @@ -402,14 +406,18 @@ static int getAsyncKeyMods(void) { int mods = 0; - if (GetAsyncKeyState(VK_SHIFT) & (1 << 31)) + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) mods |= GLFW_MOD_SHIFT; - if (GetAsyncKeyState(VK_CONTROL) & (1 << 31)) + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) mods |= GLFW_MOD_CONTROL; - if (GetAsyncKeyState(VK_MENU) & (1 << 31)) + if (GetAsyncKeyState(VK_MENU) & 0x8000) mods |= GLFW_MOD_ALT; - if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31)) + if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000) mods |= GLFW_MOD_SUPER; + if (GetAsyncKeyState(VK_CAPITAL) & 1) + mods |= GLFW_MOD_CAPS_LOCK; + if (GetAsyncKeyState(VK_NUMLOCK) & 1) + mods |= GLFW_MOD_NUM_LOCK; return mods; } @@ -1497,26 +1505,19 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, if (monitor) { - GLFWvidmode mode; - DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); - UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; - if (window->decorated) { + DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_FRAMECHANGED | SWP_SHOWWINDOW | + SWP_NOACTIVATE | SWP_NOCOPYBITS | + SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE; + style &= ~WS_OVERLAPPEDWINDOW; style |= getWindowStyle(window); SetWindowLongW(window->win32.handle, GWL_STYLE, style); - - flags |= SWP_FRAMECHANGED; + SetWindowPos(window->win32.handle, HWND_TOPMOST, 0, 0, 0, 0, flags); } - _glfwPlatformGetVideoMode(monitor, &mode); - _glfwPlatformGetMonitorPos(monitor, &xpos, &ypos); - - SetWindowPos(window->win32.handle, HWND_TOPMOST, - xpos, ypos, mode.width, mode.height, - flags); - acquireMonitor(window); } else @@ -1591,6 +1592,39 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + BYTE alpha; + DWORD flags; + + if ((GetWindowLongW(window->win32.handle, GWL_EXSTYLE) & WS_EX_LAYERED) && + GetLayeredWindowAttributes(window->win32.handle, NULL, &alpha, &flags)) + { + if (flags & LWA_ALPHA) + return alpha / 255.f; + } + + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ + if (opacity < 1.f) + { + const BYTE alpha = (BYTE) (255 * opacity); + DWORD style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + style |= WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + SetLayeredWindowAttributes(window->win32.handle, 0, alpha, LWA_ALPHA); + } + else + { + DWORD style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + style &= ~WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + } +} + void _glfwPlatformPollEvents(void) { MSG msg; @@ -1796,7 +1830,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) updateCursorImage(window); } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { int characterCount; HANDLE object; @@ -1839,7 +1873,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) CloseClipboard(); } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { HANDLE object; WCHAR* buffer; diff --git a/src/external/glfw/src/window.c b/src/external/glfw/src/window.c index 30321733..f4468e16 100644 --- a/src/external/glfw/src/window.c +++ b/src/external/glfw/src/window.c @@ -316,7 +316,7 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_DOUBLEBUFFER: _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE; return; - case GLFW_TRANSPARENT: + case GLFW_TRANSPARENT_FRAMEBUFFER: _glfw.hints.framebuffer.transparent = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_SAMPLES: @@ -648,6 +648,34 @@ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, _glfwPlatformGetWindowContentScale(window, xscale, yscale); } +GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(1.f); + return _glfwPlatformGetWindowOpacity(window); +} + +GLFWAPI void glfwSetWindowOpacity(GLFWwindow* handle, float opacity) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(opacity == opacity); + assert(opacity >= 0.f); + assert(opacity <= 1.f); + + _GLFW_REQUIRE_INIT(); + + if (opacity != opacity || opacity < 0.f || opacity > 1.f) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid window opacity %f", opacity); + return; + } + + _glfwPlatformSetWindowOpacity(window, opacity); +} + GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; @@ -743,7 +771,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return _glfwPlatformWindowVisible(window); case GLFW_MAXIMIZED: return _glfwPlatformWindowMaximized(window); - case GLFW_TRANSPARENT: + case GLFW_TRANSPARENT_FRAMEBUFFER: return _glfwPlatformFramebufferTransparent(window); case GLFW_RESIZABLE: return window->resizable; diff --git a/src/external/glfw/src/wl_init.c b/src/external/glfw/src/wl_init.c index 3841636f..597275c9 100644 --- a/src/external/glfw/src/wl_init.c +++ b/src/external/glfw/src/wl_init.c @@ -26,6 +26,7 @@ #include "internal.h" +#include #include #include #include @@ -152,6 +153,7 @@ static void pointerHandleAxis(void* data, y = wl_fixed_to_double(value) * scrollFactor; break; default: + assert(GLFW_FALSE); break; } @@ -174,8 +176,12 @@ static void keyboardHandleKeymap(void* data, { struct xkb_keymap* keymap; struct xkb_state* state; + +#ifdef HAVE_XKBCOMMON_COMPOSE_H struct xkb_compose_table* composeTable; struct xkb_compose_state* composeState; +#endif + char* mapStr; const char* locale; @@ -223,6 +229,7 @@ static void keyboardHandleKeymap(void* data, if (!locale) locale = "C"; +#ifdef HAVE_XKBCOMMON_COMPOSE_H composeTable = xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); @@ -242,6 +249,7 @@ static void keyboardHandleKeymap(void* data, _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create XKB compose table"); } +#endif xkb_keymap_unref(_glfw.wl.xkb.keymap); xkb_state_unref(_glfw.wl.xkb.state); @@ -256,6 +264,10 @@ static void keyboardHandleKeymap(void* data, 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); _glfw.wl.xkb.superMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); + _glfw.wl.xkb.capsLockMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock"); + _glfw.wl.xkb.numLockMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2"); } static void keyboardHandleEnter(void* data, @@ -292,6 +304,7 @@ static int toGLFWKeyCode(uint32_t key) return GLFW_KEY_UNKNOWN; } +#ifdef HAVE_XKBCOMMON_COMPOSE_H static xkb_keysym_t composeSymbol(xkb_keysym_t sym) { if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState) @@ -311,6 +324,7 @@ static xkb_keysym_t composeSymbol(xkb_keysym_t sym) return sym; } } +#endif static void inputChar(_GLFWwindow* window, uint32_t key) { @@ -324,7 +338,11 @@ static void inputChar(_GLFWwindow* window, uint32_t key) if (numSyms == 1) { +#ifdef HAVE_XKBCOMMON_COMPOSE_H sym = composeSymbol(syms[0]); +#else + sym = syms[0]; +#endif cp = _glfwKeySym2Unicode(sym); if (cp != -1) { @@ -395,6 +413,10 @@ static void keyboardHandleModifiers(void* data, modifiers |= GLFW_MOD_SHIFT; if (mask & _glfw.wl.xkb.superMask) modifiers |= GLFW_MOD_SUPER; + if (mask & _glfw.wl.xkb.capsLockMask) + modifiers |= GLFW_MOD_CAPS_LOCK; + if (mask & _glfw.wl.xkb.numLockMask) + modifiers |= GLFW_MOD_NUM_LOCK; _glfw.wl.xkb.modifiers = modifiers; } @@ -487,6 +509,13 @@ static void registryHandleGlobal(void* data, &zwp_pointer_constraints_v1_interface, 1); } + else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0) + { + _glfw.wl.idleInhibitManager = + wl_registry_bind(registry, name, + &zwp_idle_inhibit_manager_v1_interface, + 1); + } } static void registryHandleGlobalRemove(void *data, @@ -670,6 +699,8 @@ int _glfwPlatformInit(void) dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask"); _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods) dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods"); + +#ifdef HAVE_XKBCOMMON_COMPOSE_H _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale) dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale"); _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref) @@ -684,6 +715,7 @@ int _glfwPlatformInit(void) dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status"); _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym) dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); +#endif _glfw.wl.display = wl_display_connect(NULL); if (!_glfw.wl.display) @@ -738,7 +770,10 @@ void _glfwPlatformTerminate(void) _glfwTerminateEGL(); _glfwTerminateJoysticksLinux(); +#ifdef HAVE_XKBCOMMON_COMPOSE_H xkb_compose_state_unref(_glfw.wl.xkb.composeState); +#endif + xkb_keymap_unref(_glfw.wl.xkb.keymap); xkb_state_unref(_glfw.wl.xkb.state); xkb_context_unref(_glfw.wl.xkb.context); @@ -766,6 +801,8 @@ void _glfwPlatformTerminate(void) zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager); if (_glfw.wl.pointerConstraints) zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints); + if (_glfw.wl.idleInhibitManager) + zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager); if (_glfw.wl.registry) wl_registry_destroy(_glfw.wl.registry); if (_glfw.wl.display) diff --git a/src/external/glfw/src/wl_platform.h b/src/external/glfw/src/wl_platform.h index 059ea2ee..c3cebecf 100644 --- a/src/external/glfw/src/wl_platform.h +++ b/src/external/glfw/src/wl_platform.h @@ -26,7 +26,9 @@ #include #include +#ifdef HAVE_XKBCOMMON_COMPOSE_H #include +#endif #include typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; @@ -52,6 +54,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h" +#include "wayland-idle-inhibit-unstable-v1-client-protocol.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) @@ -78,13 +81,6 @@ typedef void (* PFN_xkb_state_unref)(struct xkb_state*); typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**); typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t); typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component); -typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags); -typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*); -typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags); -typedef void (* PFN_xkb_compose_state_unref)(struct xkb_compose_state*); -typedef enum xkb_compose_feed_result (* PFN_xkb_compose_state_feed)(struct xkb_compose_state*, xkb_keysym_t); -typedef enum xkb_compose_status (* PFN_xkb_compose_state_get_status)(struct xkb_compose_state*); -typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_state*); #define xkb_context_new _glfw.wl.xkb.context_new #define xkb_context_unref _glfw.wl.xkb.context_unref #define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string @@ -95,6 +91,15 @@ typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_st #define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms #define xkb_state_update_mask _glfw.wl.xkb.state_update_mask #define xkb_state_serialize_mods _glfw.wl.xkb.state_serialize_mods + +#ifdef HAVE_XKBCOMMON_COMPOSE_H +typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags); +typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*); +typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags); +typedef void (* PFN_xkb_compose_state_unref)(struct xkb_compose_state*); +typedef enum xkb_compose_feed_result (* PFN_xkb_compose_state_feed)(struct xkb_compose_state*, xkb_keysym_t); +typedef enum xkb_compose_status (* PFN_xkb_compose_state_get_status)(struct xkb_compose_state*); +typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_state*); #define xkb_compose_table_new_from_locale _glfw.wl.xkb.compose_table_new_from_locale #define xkb_compose_table_unref _glfw.wl.xkb.compose_table_unref #define xkb_compose_state_new _glfw.wl.xkb.compose_state_new @@ -102,6 +107,7 @@ typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_st #define xkb_compose_state_feed _glfw.wl.xkb.compose_state_feed #define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status #define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym +#endif // Wayland-specific per-window data @@ -133,6 +139,9 @@ typedef struct _GLFWwindowWayland struct zwp_relative_pointer_v1* relativePointer; struct zwp_locked_pointer_v1* lockedPointer; } pointerLock; + + struct zwp_idle_inhibitor_v1* idleInhibitor; + } _GLFWwindowWayland; // Wayland-specific global data @@ -149,6 +158,7 @@ typedef struct _GLFWlibraryWayland struct wl_keyboard* keyboard; struct zwp_relative_pointer_manager_v1* relativePointerManager; struct zwp_pointer_constraints_v1* pointerConstraints; + struct zwp_idle_inhibit_manager_v1* idleInhibitManager; int compositorVersion; @@ -164,11 +174,17 @@ typedef struct _GLFWlibraryWayland struct xkb_context* context; struct xkb_keymap* keymap; struct xkb_state* state; + +#ifdef HAVE_XKBCOMMON_COMPOSE_H struct xkb_compose_state* composeState; +#endif + xkb_mod_mask_t controlMask; xkb_mod_mask_t altMask; xkb_mod_mask_t shiftMask; xkb_mod_mask_t superMask; + xkb_mod_mask_t capsLockMask; + xkb_mod_mask_t numLockMask; unsigned int modifiers; PFN_xkb_context_new context_new; @@ -181,6 +197,8 @@ typedef struct _GLFWlibraryWayland PFN_xkb_state_key_get_syms state_key_get_syms; PFN_xkb_state_update_mask state_update_mask; PFN_xkb_state_serialize_mods state_serialize_mods; + +#ifdef HAVE_XKBCOMMON_COMPOSE_H PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale; PFN_xkb_compose_table_unref compose_table_unref; PFN_xkb_compose_state_new compose_state_new; @@ -188,6 +206,7 @@ typedef struct _GLFWlibraryWayland PFN_xkb_compose_state_feed compose_state_feed; PFN_xkb_compose_state_get_status compose_state_get_status; PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym; +#endif } xkb; _GLFWwindow* pointerFocus; diff --git a/src/external/glfw/src/wl_window.c b/src/external/glfw/src/wl_window.c index f0f2637e..9759ba26 100644 --- a/src/external/glfw/src/wl_window.c +++ b/src/external/glfw/src/wl_window.c @@ -189,6 +189,24 @@ static void setOpaqueRegion(_GLFWwindow* window) wl_region_destroy(region); } +static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) +{ + if (enable && !window->wl.idleInhibitor && _glfw.wl.idleInhibitManager) + { + window->wl.idleInhibitor = + zwp_idle_inhibit_manager_v1_create_inhibitor( + _glfw.wl.idleInhibitManager, window->wl.surface); + if (!window->wl.idleInhibitor) + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Idle inhibitor creation failed"); + } + else if (!enable && window->wl.idleInhibitor) + { + zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor); + window->wl.idleInhibitor = NULL; + } +} + static GLFWbool createSurface(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) { @@ -239,14 +257,17 @@ static GLFWbool createShellSurface(_GLFWwindow* window) WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, window->monitor->wl.output); + setIdleInhibitor(window, GLFW_TRUE); } else if (window->wl.maximized) { wl_shell_surface_set_maximized(window->wl.shellSurface, NULL); + setIdleInhibitor(window, GLFW_FALSE); } else { wl_shell_surface_set_toplevel(window->wl.shellSurface); + setIdleInhibitor(window, GLFW_FALSE); } wl_surface_commit(window->wl.surface); @@ -452,6 +473,9 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) _glfwInputWindowFocus(window, GLFW_FALSE); } + if (window->wl.idleInhibitor) + zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor); + if (window->context.destroy) window->context.destroy(window); @@ -637,10 +661,12 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, refreshRate * 1000, // Convert Hz to mHz. monitor->wl.output); + setIdleInhibitor(window, GLFW_TRUE); } else { wl_shell_surface_set_toplevel(window->wl.shellSurface); + setIdleInhibitor(window, GLFW_FALSE); } _glfwInputWindowMonitor(window, monitor); } @@ -692,6 +718,15 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) "Wayland: Window attribute setting not implemented yet"); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ +} + void _glfwPlatformPollEvents(void) { handleEvents(0); @@ -1008,14 +1043,14 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) } } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { // TODO _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Clipboard setting not implemented yet"); } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { // TODO _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/external/glfw/src/x11_init.c b/src/external/glfw/src/x11_init.c index b603a15f..6786231c 100644 --- a/src/external/glfw/src/x11_init.c +++ b/src/external/glfw/src/x11_init.c @@ -737,9 +737,18 @@ static GLFWbool initExtensions(void) XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False); _glfw.x11.NET_WM_BYPASS_COMPOSITOR = XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False); + _glfw.x11.NET_WM_WINDOW_OPACITY = + XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False); _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); + // The compositing manager selection name contains the screen number + { + char name[32]; + snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen); + _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False); + } + return GLFW_TRUE; } @@ -985,8 +994,6 @@ void _glfwPlatformTerminate(void) _glfw.x11.im = NULL; } - _glfwTerminateEGL(); - if (_glfw.x11.display) { XCloseDisplay(_glfw.x11.display); @@ -1017,8 +1024,9 @@ void _glfwPlatformTerminate(void) _glfw.x11.xinerama.handle = NULL; } - // NOTE: This needs to be done after XCloseDisplay, as libGL registers - // cleanup callbacks that get called by it + // NOTE: These need to be unloaded after XCloseDisplay, as they register + // cleanup callbacks that get called by that function + _glfwTerminateEGL(); _glfwTerminateGLX(); #if defined(__linux__) diff --git a/src/external/glfw/src/x11_monitor.c b/src/external/glfw/src/x11_monitor.c index d68c5888..d9144bb4 100644 --- a/src/external/glfw/src/x11_monitor.c +++ b/src/external/glfw/src/x11_monitor.c @@ -203,8 +203,7 @@ void _glfwPollMonitorsX11(void) free(disconnected); } - - if (!_glfw.monitorCount) + else { const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); diff --git a/src/external/glfw/src/x11_platform.h b/src/external/glfw/src/x11_platform.h index 7eba441d..c5a11cf2 100644 --- a/src/external/glfw/src/x11_platform.h +++ b/src/external/glfw/src/x11_platform.h @@ -257,6 +257,8 @@ typedef struct _GLFWlibraryX11 Atom NET_WM_STATE_DEMANDS_ATTENTION; Atom NET_WM_BYPASS_COMPOSITOR; Atom NET_WM_FULLSCREEN_MONITORS; + Atom NET_WM_WINDOW_OPACITY; + Atom NET_WM_CM_Sx; Atom NET_ACTIVE_WINDOW; Atom NET_FRAME_EXTENTS; Atom NET_REQUEST_FRAME_EXTENTS; diff --git a/src/external/glfw/src/x11_window.c b/src/external/glfw/src/x11_window.c index c89d2ec5..e9708f98 100644 --- a/src/external/glfw/src/x11_window.c +++ b/src/external/glfw/src/x11_window.c @@ -212,6 +212,10 @@ static int translateState(int state) mods |= GLFW_MOD_ALT; if (state & Mod4Mask) mods |= GLFW_MOD_SUPER; + if (state & LockMask) + mods |= GLFW_MOD_CAPS_LOCK; + if (state & Mod2Mask) + mods |= GLFW_MOD_NUM_LOCK; return mods; } @@ -2449,11 +2453,7 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) if (!window->x11.transparent) return GLFW_FALSE; - // Check whether a compositing manager is running - char name[32]; - snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen); - const Atom selection = XInternAtom(_glfw.x11.display, name, False); - return XGetSelectionOwner(_glfw.x11.display, selection) != None; + return XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx) != None; } void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) @@ -2559,6 +2559,37 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) XFlush(_glfw.x11.display); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + float opacity = 1.f; + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx)) + { + CARD32* value = NULL; + + if (_glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_WM_WINDOW_OPACITY, + XA_CARDINAL, + (unsigned char**) &value)) + { + opacity = (float) (*value / (double) 0xffffffffu); + } + + if (value) + XFree(value); + } + + return opacity; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ + const CARD32 value = (CARD32) (0xffffffffu * (double) opacity); + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*) &value, 1); +} + void _glfwPlatformPollEvents(void) { _GLFWwindow* window; @@ -2773,7 +2804,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) } } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { free(_glfw.x11.clipboardString); _glfw.x11.clipboardString = strdup(string); @@ -2791,7 +2822,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) } } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { return getSelectionString(_glfw.x11.CLIPBOARD); } diff --git a/src/rglfw.c b/src/rglfw.c index 6518a442..0b577e3a 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -34,7 +34,9 @@ #define _GLFW_WIN32 #endif #ifdef __linux__ - #define _GLFW_X11 + #ifndef _GLFW_WAYLAND // Required for Wayland windowing + #define _GLFW_X11 + #endif #endif #ifdef __FreeBSD__ #define _GLFW_X11 @@ -68,14 +70,24 @@ #endif #ifdef __linux__ - #include "external/glfw/src/x11_init.c" - #include "external/glfw/src/x11_monitor.c" - #include "external/glfw/src/x11_window.c" - #include "external/glfw/src/xkb_unicode.c" + #ifdef _GLFW_WAYLAND + #include "external/glfw/src/wl_init.c" + #include "external/glfw/src/wl_monitor.c" + #include "external/glfw/src/wl_window.c" + #include "external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c" + #include "external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c" + #endif + #ifdef _GLFW_X11 + #include "external/glfw/src/x11_init.c" + #include "external/glfw/src/x11_monitor.c" + #include "external/glfw/src/x11_window.c" + #include "external/glfw/src/glx_context.c" + #endif + #include "external/glfw/src/linux_joystick.c" - #include "external/glfw/src/posix_time.c" #include "external/glfw/src/posix_thread.c" - #include "external/glfw/src/glx_context.c" + #include "external/glfw/src/posix_time.c" + #include "external/glfw/src/xkb_unicode.c" #include "external/glfw/src/egl_context.c" #include "external/glfw/src/osmesa_context.c" #endif From 203b2f65d11033e5ad42bdaeb6b09b83ff576b96 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sun, 10 Dec 2017 21:11:04 +0100 Subject: [PATCH 067/139] Fix typo in preprocessor macro --- src/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core.c b/src/core.c index cf8f0258..ec7db978 100644 --- a/src/core.c +++ b/src/core.c @@ -89,7 +89,7 @@ #include "raylib.h" -#if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_S_SOURCE < 199309L +#if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. #endif From de78fa69bc49afa83898e33e73b6dfbffc43f0e4 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 6 Dec 2017 22:18:14 +0100 Subject: [PATCH 068/139] Fix CI builds after mini_al changes --- .travis.yml | 2 +- appveyor.yml | 3 --- src/CMakeLists.txt | 3 +-- src/external/mini_al.h | 4 +++- utils.cmake | 1 - 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 28641b38..7d1ffef0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ before_script: before_install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -y gcc-multilib - libopenal-dev + libasound2-dev libxcursor-dev libxinerama-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev libglew-dev; diff --git a/appveyor.yml b/appveyor.yml index bee59fa5..a8572d07 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,9 +28,6 @@ environment: bits: 64 before_build: - - appveyor DownloadFile http://openal-soft.org/openal-binaries/openal-soft-1.17.2-bin.zip - - 7z x openal-soft-1.17.2-bin.zip - - move openal-soft-1.17.2-bin src\external\openal - if [%compiler%]==[mingw] set CFLAGS=-m%BITS% & set LDFLAGS=-m%BITS% & set GENERATOR="MinGW Makefiles" - if [%COMPILER%]==[msvc15] if [%BITS%]==[32] set GENERATOR="Visual Studio 14 2015" - if [%COMPILER%]==[msvc15] if [%BITS%]==[64] set GENERATOR="Visual Studio 14 2015 Win64" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 819dd1a4..200ae6f9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -83,8 +83,7 @@ endif() # Get the sources together file(GLOB raylib_sources *.c) file(GLOB stb_vorbis external/stb_vorbis.c) -file(GLOB mini_al external/mini_al.c) -set(sources ${raylib_sources} ${stb_vorbis}) +file(GLOB mini_al external/mini_al.c ${stb_vorbis}) set(sources ${raylib_sources} ${mini_al}) # Which platform? diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 7d83b548..36c394ad 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -2745,12 +2745,14 @@ static mal_result mal_context__try_get_device_name_by_id(mal_context* pContext, } } break; #endif + #if 0 #ifdef MAL_HAS_COREAUDIO - case mal_backend_coreaudio + case mal_backend_coreaudio: { // TODO: Implement me. } break; #endif + #endif #ifdef MAL_HAS_OSS case mal_backend_oss: { diff --git a/utils.cmake b/utils.cmake index 43b479da..d2c82cd1 100644 --- a/utils.cmake +++ b/utils.cmake @@ -23,7 +23,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL Linux) # Elsewhere (such as Linux), need `-lopenal -lGL`, etc... set(LIBS_PRIVATE m pthread dl - openal GL X11 Xrandr Xinerama Xi Xxf86vm Xcursor) # X11 stuff endif() From d24b89bb0ec8abe7243963bdbca96cb254c27256 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sun, 10 Dec 2017 21:57:25 +0100 Subject: [PATCH 069/139] Add library versioning to Make/CMake build systems See #401 for the discussion. Also bumps version number to 1.9.2 without the -dev, because neither ELF nor MachO like such a suffix. The -dev suffix will have to be restricted to the git tags. --- src/CMakeLists.txt | 9 +++++++-- src/Makefile | 39 +++++++++++++++++++++++++++------------ 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 200ae6f9..e86bff9b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,7 +2,8 @@ project(raylib) include("../utils.cmake") -set(PROJECT_VERSION 1.9.1-dev) +set(PROJECT_VERSION 1.9.2) +set(API_VERSION 1) set(RAYLIB raylib) # Name of the generated library ### Config options ### @@ -123,7 +124,11 @@ if(${PLATFORM} MATCHES "PLATFORM_DESKTOP") set(CMAKE_MACOSX_RPATH ON) target_link_libraries(${RAYLIB}_shared ${LIBS_PRIVATE}) - set_target_properties(${RAYLIB}_shared PROPERTIES PUBLIC_HEADER "raylib.h") + set_target_properties(${RAYLIB}_shared PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${API_VERSION} + PUBLIC_HEADER "raylib.h" + ) if(WIN32) install( TARGETS ${RAYLIB}_shared diff --git a/src/Makefile b/src/Makefile index e3bb91cc..b9c21929 100644 --- a/src/Makefile +++ b/src/Makefile @@ -42,6 +42,8 @@ .PHONY: all clean install uninstall # Define required raylib variables +VERSION = 1.9.2 +API_VERSION = 1 PLATFORM ?= PLATFORM_DESKTOP RAYLIB_PATH = .. @@ -172,6 +174,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),OSX) # OSX default compiler CC = clang + GLFW_CFLAGS = -x objective-c endif ifeq ($(PLATFORM_OS),FREEBSD) # FreeBSD default compiler @@ -291,7 +294,7 @@ endif # Define linker options ifeq ($(PLATFORM),PLATFORM_ANDROID) - LDFLAGS = -Wl,-soname,libraylib.so -Wl,--exclude-libs,libatomic.a + LDFLAGS = -Wl,-soname,libraylib.$(API_VERSION).so -Wl,--exclude-libs,libatomic.a LDFLAGS += -Wl,--build-id -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings # Force linking of library module to define symbol LDFLAGS += -u ANativeActivity_onCreate @@ -353,22 +356,30 @@ else ifeq ($(PLATFORM_OS),LINUX) # Compile raylib to shared library version for GNU/Linux. # WARNING: you should type "make clean" before doing this target - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lGL -lm -lpthread -ldl -lrt - @echo "raylib shared library generated (libraylib.so)!" + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).so $(OBJS) -Wl,-soname,libraylib.$(API_VERSION).so -lGL -lm -lpthread -ldl -lrt + @echo "raylib shared library generated (libraylib.$(VERSION).so)!" + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.$(API_VERSION).so + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.so endif ifeq ($(PLATFORM_OS),OSX) - $(CC) -dynamiclib -o $(RAYLIB_RELEASE_PATH)/libraylib.dylib $(OBJS) -L/usr/local/Cellar/glfw/3.2.1/lib -framework OpenGL -framework OpenAL -framework Cocoa - install_name_tool -id "libraylib.dylib" $(RAYLIB_RELEASE_PATH)/libraylib.dylib - @echo "raylib shared library generated (libraylib.dylib)!" + $(CC) -dynamiclib -o $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).dylib $(OBJS) -compatibility_version $(API_VERSION) -current_version $(VERSION) -framework OpenGL -framework OpenAL -framework IOKit -framework CoreVideo -framework Cocoa + install_name_tool -id "libraylib.$(VERSION).dylib" $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).dylib + @echo "raylib shared library generated (libraylib.$(VERSION).dylib)!" + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).dylib libraylib.$(API_VERSION).dylib + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).dylib libraylib.dylib endif ifeq ($(PLATFORM_OS),FREEBSD) # WARNING: you should type "gmake clean" before doing this target - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) -lGL -lpthread - @echo "raylib shared library generated (libraylib.so)!" + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).so $(OBJS) -Wl,-soname,libraylib.$(API_VERSION).so -lGL -lpthread + @echo "raylib shared library generated (libraylib.$(VERSION).so)!" + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.$(API_VERSION).so + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.so endif ifeq ($(PLATFORM),PLATFORM_ANDROID) - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so $(OBJS) $(LDFLAGS) $(LDLIBS) - @echo "raylib shared library generated (libraylib.so)!" + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).so $(OBJS) $(LDFLAGS) $(LDLIBS) + @echo "raylib shared library generated (libraylib.$(VERSION).so)!" + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.$(API_VERSION).so + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.so endif else # Compile raylib static library @@ -386,7 +397,7 @@ core.o : core.c raylib.h rlgl.h utils.h raymath.h gestures.h # Compile rglfw module rglfw.o : rglfw.c - $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS) + $(CC) $(GLFW_CFLAGS) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS) # Compile rlgl module rlgl.o : rlgl.c rlgl.h raymath.h @@ -434,6 +445,8 @@ ifeq ($(ROOT),root) # /usr/local/include/) are for libraries that are installed # manually (without a package manager). ifeq ($(RAYLIB_LIBTYPE),SHARED) + cp --update $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).so /usr/local/lib/libraylib.$(VERSION).so + cp --update $(RAYLIB_RELEASE_PATH)/libraylib.$(API_VERSION).so /usr/local/lib/libraylib.$(API_VERSION).so cp --update $(RAYLIB_RELEASE_PATH)/libraylib.so /usr/local/lib/libraylib.so else cp --update raylib.h /usr/local/include/raylib.h @@ -455,6 +468,8 @@ ifeq ($(ROOT),root) rm --force /usr/local/include/raylib.h ifeq ($(RAYLIB_LIBTYPE),SHARED) rm --force /usr/local/lib/libraylib.so + rm --force /usr/local/lib/libraylib.$(API_VERSION).so + rm --force /usr/local/lib/libraylib.$(VERSION).so else rm --force /usr/local/lib/libraylib.a endif @@ -471,7 +486,7 @@ clean: ifeq ($(PLATFORM_OS),WINDOWS) del *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so external/stb_vorbis.o else - rm -f *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so external/stb_vorbis.o + rm -f *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so $(RAYLIB_RELEASE_PATH)/libraylib.$(API_VERSION).so $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).so external/stb_vorbis.o endif ifeq ($(PLATFORM),PLATFORM_ANDROID) rm -rf $(ANDROID_TOOLCHAIN) From 4a7840b75297e2a2ea3ddf5ef6b2e0c9b9d5d057 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 11 Dec 2017 11:13:34 +0100 Subject: [PATCH 070/139] Remove Meson build system Less maintenance overhead that way, given that make/CMake now also do library versioning. --- .gitignore | 3 --- meson.build | 15 --------------- src/meson.build | 22 ---------------------- 3 files changed, 40 deletions(-) delete mode 100644 meson.build delete mode 100644 src/meson.build diff --git a/.gitignore b/.gitignore index 65b3020c..44f882d6 100644 --- a/.gitignore +++ b/.gitignore @@ -110,9 +110,6 @@ docs/examples/web/*/*.html !docs/examples/web/shaders/loader.html !docs/examples/web/models/loader.html -# Meson build system -builddir/ - # CMake stuff CMakeCache.txt CMakeFiles diff --git a/meson.build b/meson.build deleted file mode 100644 index c85905cc..00000000 --- a/meson.build +++ /dev/null @@ -1,15 +0,0 @@ -project('raylib', 'c', version: '1.8.0', - license: 'zlib', - meson_version: '>= 0.39.1', - default_options : 'c_std=gnu99') - -cc = meson.get_compiler('c') - -glfw_dep = dependency('glfw3', version : '>=3.2') -gl_dep = dependency('gl') -openal_dep = dependency('openal') -x11_dep = dependency('x11') -m_dep = cc.find_library('m', required : false) - -subdir('src') - diff --git a/src/meson.build b/src/meson.build deleted file mode 100644 index 12385fc9..00000000 --- a/src/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -install_headers('raylib.h') - -source_c = [ - 'audio.c', - 'core.c', - 'models.c', - 'rlgl.c', - 'shapes.c', - 'text.c', - 'textures.c', - 'utils.c', - 'external/stb_vorbis.c', -] - -# use 'meson --default-library=static builddir' to build as static, if no builddir yet exists -# use 'mesonconf -Ddefault_library=static builddir' to change the type -raylib = library('raylib', - source_c, - dependencies : [ glfw_dep, gl_dep, openal_dep, m_dep, x11_dep], - install : true, - version : '1.8.0') - From a6f9cc5629841b7adf3d9ff21eaa2aaabb3e4bc1 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 11 Dec 2017 11:55:02 +0100 Subject: [PATCH 071/139] Remove rres support Let the user choose if using rres external library --- src/audio.c | 13 - src/external/tinfl.c | 592 ------------------------------------------- src/raylib.h | 16 -- src/rres.h | 483 ----------------------------------- src/text.c | 29 +-- src/textures.c | 13 +- src/utils.c | 3 - src/utils.h | 2 - 8 files changed, 2 insertions(+), 1149 deletions(-) delete mode 100644 src/external/tinfl.c delete mode 100644 src/rres.h diff --git a/src/audio.c b/src/audio.c index d397b064..15f50a24 100644 --- a/src/audio.c +++ b/src/audio.c @@ -812,19 +812,6 @@ Wave LoadWave(const char *fileName) #endif #if defined(SUPPORT_FILEFORMAT_FLAC) else if (IsFileExtension(fileName, ".flac")) wave = LoadFLAC(fileName); -#endif -#if !defined(AUDIO_STANDALONE) - else if (IsFileExtension(fileName, ".rres")) - { - RRES rres = LoadResource(fileName, 0); - - // NOTE: Parameters for RRES_TYPE_WAVE are: sampleCount, sampleRate, sampleSize, channels - - if (rres[0].type == RRES_TYPE_WAVE) wave = LoadWaveEx(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3, rres[0].param4); - else TraceLog(LOG_WARNING, "[%s] Resource file does not contain wave data", fileName); - - UnloadResource(rres); - } #endif else TraceLog(LOG_WARNING, "[%s] Audio fileformat not supported, it can't be loaded", fileName); diff --git a/src/external/tinfl.c b/src/external/tinfl.c deleted file mode 100644 index a17a156b..00000000 --- a/src/external/tinfl.c +++ /dev/null @@ -1,592 +0,0 @@ -/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c) - See "unlicense" statement at the end of this file. - Rich Geldreich , last updated May 20, 2011 - Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt - - The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers. -*/ -#ifndef TINFL_HEADER_INCLUDED -#define TINFL_HEADER_INCLUDED - -#include - -typedef unsigned char mz_uint8; -typedef signed short mz_int16; -typedef unsigned short mz_uint16; -typedef unsigned int mz_uint32; -typedef unsigned int mz_uint; -typedef unsigned long long mz_uint64; - -#if defined(_M_IX86) || defined(_M_X64) -// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster). -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 -// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. -#define MINIZ_LITTLE_ENDIAN 1 -#endif - -#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) -// Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator) -#define MINIZ_HAS_64BIT_REGISTERS 1 -#endif - -// Works around MSVC's spammy "warning C4127: conditional expression is constant" message. -#ifdef _MSC_VER - #define MZ_MACRO_END while (0, 0) -#else - #define MZ_MACRO_END while (0) -#endif - -// Decompression flags used by tinfl_decompress(). -// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. -// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. -// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). -// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. -enum -{ - TINFL_FLAG_PARSE_ZLIB_HEADER = 1, - TINFL_FLAG_HAS_MORE_INPUT = 2, - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, - TINFL_FLAG_COMPUTE_ADLER32 = 8 -}; - -// High level decompression functions: -// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). -// On entry: -// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. -// On return: -// Function returns a pointer to the decompressed data, or NULL on failure. -// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. -// The caller must free() the returned block when it's no longer needed. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. -// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. -#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. -// Returns 1 on success or 0 on failure. -typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; - -// Max size of LZ dictionary. -#define TINFL_LZ_DICT_SIZE 32768 - -// Return status. -typedef enum -{ - TINFL_STATUS_BAD_PARAM = -3, - TINFL_STATUS_ADLER32_MISMATCH = -2, - TINFL_STATUS_FAILED = -1, - TINFL_STATUS_DONE = 0, - TINFL_STATUS_NEEDS_MORE_INPUT = 1, - TINFL_STATUS_HAS_MORE_OUTPUT = 2 -} tinfl_status; - -// Initializes the decompressor to its initial state. -#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END -#define tinfl_get_adler32(r) (r)->m_check_adler32 - -// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. -// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); - -// Internal/private bits follow. -enum -{ - TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, - TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS -}; - -typedef struct -{ - mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; - mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; -} tinfl_huff_table; - -#if MINIZ_HAS_64BIT_REGISTERS - #define TINFL_USE_64BIT_BITBUF 1 -#endif - -#if TINFL_USE_64BIT_BITBUF - typedef mz_uint64 tinfl_bit_buf_t; - #define TINFL_BITBUF_SIZE (64) -#else - typedef mz_uint32 tinfl_bit_buf_t; - #define TINFL_BITBUF_SIZE (32) -#endif - -struct tinfl_decompressor_tag -{ - mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; - tinfl_bit_buf_t m_bit_buf; - size_t m_dist_from_out_buf_start; - tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; - mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; -}; - -#endif // #ifdef TINFL_HEADER_INCLUDED - -// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) - -#ifndef TINFL_HEADER_FILE_ONLY - -#include - -// MZ_MALLOC, etc. are only used by the optional high-level helper functions. -#ifdef MINIZ_NO_MALLOC - #define MZ_MALLOC(x) NULL - #define MZ_FREE(x) x, ((void)0) - #define MZ_REALLOC(p, x) NULL -#else - #define MZ_MALLOC(x) malloc(x) - #define MZ_FREE(x) free(x) - #define MZ_REALLOC(p, x) realloc(p, x) -#endif - -#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) -#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) -#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) - #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) -#else - #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) - #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) -#endif - -#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) -#define TINFL_MEMSET(p, c, l) memset(p, c, l) - -#define TINFL_CR_BEGIN switch(r->m_state) { case 0: -#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END -#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END -#define TINFL_CR_FINISH } - -// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never -// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. -#define TINFL_GET_BYTE(state_index, c) do { \ - if (pIn_buf_cur >= pIn_buf_end) { \ - for ( ; ; ) { \ - if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ - TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ - if (pIn_buf_cur < pIn_buf_end) { \ - c = *pIn_buf_cur++; \ - break; \ - } \ - } else { \ - c = 0; \ - break; \ - } \ - } \ - } else c = *pIn_buf_cur++; } MZ_MACRO_END - -#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) -#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END -#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END - -// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. -// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a -// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the -// bit buffer contains >=15 bits (deflate's max. Huffman code size). -#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ - do { \ - temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ - if (temp >= 0) { \ - code_len = temp >> 9; \ - if ((code_len) && (num_bits >= code_len)) \ - break; \ - } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ - } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ - } while (num_bits < 15); - -// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read -// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully -// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. -// The slow path is only executed at the very end of the input buffer. -#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ - int temp; mz_uint code_len, c; \ - if (num_bits < 15) { \ - if ((pIn_buf_end - pIn_buf_cur) < 2) { \ - TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ - } else { \ - bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ - } \ - } \ - if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ - code_len = temp >> 9, temp &= 511; \ - else { \ - code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ - } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END - -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) -{ - static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; - static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - static const int s_min_table_sizes[3] = { 257, 1, 4 }; - - tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; - const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; - size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; - - // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). - if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } - - num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; - TINFL_CR_BEGIN - - bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); - counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); - if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); - if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } - } - - do - { - TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; - if (r->m_type == 0) - { - TINFL_SKIP_BITS(5, num_bits & 7); - for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } - if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } - while ((counter) && (num_bits)) - { - TINFL_GET_BITS(51, dist, 8); - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (mz_uint8)dist; - counter--; - } - while (counter) - { - size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } - while (pIn_buf_cur >= pIn_buf_end) - { - if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) - { - TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); - } - else - { - TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); - } - } - n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); - TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; - } - } - else if (r->m_type == 3) - { - TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); - } - else - { - if (r->m_type == 1) - { - mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; - r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); - for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; - } - else - { - for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } - MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } - r->m_table_sizes[2] = 19; - } - for ( ; (int)r->m_type >= 0; r->m_type--) - { - int tree_next, tree_cur; tinfl_huff_table *pTable; - mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); - for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; - used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; - for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } - if ((65536 != total) && (used_syms > 1)) - { - TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); - } - for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) - { - mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; - cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); - if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } - if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } - rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); - for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) - { - tree_cur -= ((rev_code >>= 1) & 1); - if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; - } - tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; - } - if (r->m_type == 2) - { - for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) - { - mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } - if ((dist == 16) && (!counter)) - { - TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); - } - num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; - TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; - } - if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) - { - TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); - } - TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); - } - } - for ( ; ; ) - { - mz_uint8 *pSrc; - for ( ; ; ) - { - if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) - { - TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); - if (counter >= 256) - break; - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (mz_uint8)counter; - } - else - { - int sym2; mz_uint code_len; -#if TINFL_USE_64BIT_BITBUF - if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } -#else - if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - counter = sym2; bit_buf >>= code_len; num_bits -= code_len; - if (counter & 256) - break; - -#if !TINFL_USE_64BIT_BITBUF - if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - bit_buf >>= code_len; num_bits -= code_len; - - pOut_buf_cur[0] = (mz_uint8)counter; - if (sym2 & 256) - { - pOut_buf_cur++; - counter = sym2; - break; - } - pOut_buf_cur[1] = (mz_uint8)sym2; - pOut_buf_cur += 2; - } - } - if ((counter &= 511) == 256) break; - - num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } - - TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); - num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } - - dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; - if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - { - TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); - } - - pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); - - if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) - { - while (counter--) - { - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; - } - continue; - } -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES - else if ((counter >= 9) && (counter <= dist)) - { - const mz_uint8 *pSrc_end = pSrc + (counter & ~7); - do - { - ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; - ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; - pOut_buf_cur += 8; - } while ((pSrc += 8) < pSrc_end); - if ((counter &= 7) < 3) - { - if (counter) - { - pOut_buf_cur[0] = pSrc[0]; - if (counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - continue; - } - } -#endif - do - { - pOut_buf_cur[0] = pSrc[0]; - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur[2] = pSrc[2]; - pOut_buf_cur += 3; pSrc += 3; - } while ((int)(counter -= 3) > 2); - if ((int)counter > 0) - { - pOut_buf_cur[0] = pSrc[0]; - if ((int)counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - } - } - } while (!(r->m_final & 1)); - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } - } - TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); - TINFL_CR_FINISH - -common_exit: - r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; - *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; - if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) - { - const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; - mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; - } - for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; - } - r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; - } - return status; -} - -// Higher level helper functions. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -{ - tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; - *pOut_len = 0; - tinfl_init(&decomp); - for ( ; ; ) - { - size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, - (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - src_buf_ofs += src_buf_size; - *pOut_len += dst_buf_size; - if (status == TINFL_STATUS_DONE) break; - new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; - pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); - if (!pNew_buf) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; - } - return pBuf; -} - -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -{ - tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); - status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; -} - -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - int result = 0; - tinfl_decompressor decomp; - mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; - if (!pDict) - return TINFL_STATUS_FAILED; - tinfl_init(&decomp); - for ( ; ; ) - { - size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, - (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); - in_buf_ofs += in_buf_size; - if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) - break; - if (status != TINFL_STATUS_HAS_MORE_OUTPUT) - { - result = (status == TINFL_STATUS_DONE); - break; - } - dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); - } - MZ_FREE(pDict); - *pIn_buf_size = in_buf_ofs; - return result; -} - -#endif // #ifndef TINFL_HEADER_FILE_ONLY - -/* - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - For more information, please refer to -*/ diff --git a/src/raylib.h b/src/raylib.h index a3914c4d..ac739830 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -495,22 +495,6 @@ typedef struct AudioStream { unsigned int buffers[2]; // OpenAL audio buffers (double buffering) } AudioStream; -// rRES data returned when reading a resource, -// it contains all required data for user (24 byte) -typedef struct RRESData { - unsigned int type; // Resource type (4 byte) - - unsigned int param1; // Resouce parameter 1 (4 byte) - unsigned int param2; // Resouce parameter 2 (4 byte) - unsigned int param3; // Resouce parameter 3 (4 byte) - unsigned int param4; // Resouce parameter 4 (4 byte) - - void *data; // Resource data pointer (4 byte) -} RRESData; - -// RRES type (pointer to RRESData array) -typedef struct RRESData *RRES; - // Head-Mounted-Display device parameters typedef struct VrDeviceInfo { int hResolution; // HMD horizontal resolution in pixels diff --git a/src/rres.h b/src/rres.h deleted file mode 100644 index 75faf640..00000000 --- a/src/rres.h +++ /dev/null @@ -1,483 +0,0 @@ -/********************************************************************************************** -* -* rres v1.0 - raylib resource (rRES) custom fileformat management functions -* -* CONFIGURATION: -* -* #define RREM_IMPLEMENTATION -* Generates the implementation of the library into the included file. -* If not defined, the library is in header only mode and can be included in other headers -* or source files without problems. But only ONE file should hold the implementation. -* -* DEPENDENCIES: -* tinfl - DEFLATE decompression functions -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2016-2017 Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -/* -References: - RIFF file-format: http://www.johnloomis.org/cpe102/asgn/asgn1/riff.html - ZIP file-format: https://en.wikipedia.org/wiki/Zip_(file_format) - http://www.onicos.com/staff/iz/formats/zip.html - XNB file-format: http://xbox.create.msdn.com/en-US/sample/xnb_format -*/ - -#ifndef RRES_H -#define RRES_H - -#if !defined(RRES_STANDALONE) - #include "raylib.h" -#endif - -//#define RRES_STATIC -#ifdef RRES_STATIC - #define RRESDEF static // Functions just visible to module including this file -#else - #ifdef __cplusplus - #define RRESDEF extern "C" // Functions visible from other files (no name mangling of functions in C++) - #else - #define RRESDEF extern // Functions visible from other files - #endif -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define MAX_RESOURCES_SUPPORTED 256 - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -// NOTE: Some types are required for RAYGUI_STANDALONE usage -//---------------------------------------------------------------------------------- -#if defined(RRES_STANDALONE) - // rRES data returned when reading a resource, it contains all required data for user (24 byte) - // NOTE: Using void *data pointer, so we can load to image.data, wave.data, mesh.*, (unsigned char *) - typedef struct RRESData { - unsigned int type; // Resource type (4 byte) - - unsigned int param1; // Resouce parameter 1 (4 byte) - unsigned int param2; // Resouce parameter 2 (4 byte) - unsigned int param3; // Resouce parameter 3 (4 byte) - unsigned int param4; // Resouce parameter 4 (4 byte) - - void *data; // Resource data pointer (4 byte) - } RRESData; - - // RRES type (pointer to RRESData array) - typedef struct RRESData *RRES; // Resource pointer - - // RRESData type - typedef enum { - RRES_TYPE_RAW = 0, - RRES_TYPE_IMAGE, - RRES_TYPE_WAVE, - RRES_TYPE_VERTEX, - RRES_TYPE_TEXT, - RRES_TYPE_FONT_IMAGE, - RRES_TYPE_FONT_CHARDATA, // CharInfo { int value, recX, recY, recWidth, recHeight, offsetX, offsetY, xAdvance } - RRES_TYPE_DIRECTORY - } RRESDataType; - -// Parameters information depending on resource type - -// RRES_TYPE_RAW params: -// RRES_TYPE_IMAGE params: width, height, mipmaps, format -// RRES_TYPE_WAVE params: sampleCount, sampleRate, sampleSize, channels -// RRES_TYPE_VERTEX params: vertexCount, vertexType, vertexFormat // Use masks instead? -// RRES_TYPE_TEXT params: charsCount, cultureCode -// RRES_TYPE_FONT_IMAGE params: width, height, format, mipmaps; -// RRES_TYPE_FONT_CHARDATA params: charsCount, baseSize -// RRES_TYPE_DIRECTORY params: fileCount, directoryCount - -// SpriteFont = RRES_TYPE_FONT_IMAGE chunk + RRES_TYPE_FONT_DATA chunk -// Mesh = multiple RRES_TYPE_VERTEX chunks - - -#endif - -//---------------------------------------------------------------------------------- -// Global variables -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -//RRESDEF RRESData LoadResourceData(const char *rresFileName, int rresId, int part); -RRESDEF RRES LoadResource(const char *fileName, int rresId); -RRESDEF void UnloadResource(RRES rres); - -/* -QUESTION: How to load each type of data from RRES ? - -rres->type == RRES_TYPE_RAW -unsigned char data = (unsigned char *)rres[0]->data; - -rres->type == RRES_TYPE_IMAGE -Image image; -image.data = rres[0]->data; // Be careful, duplicate pointer -image.width = rres[0]->param1; -image.height = rres[0]->param2; -image.mipmaps = rres[0]->param3; -image.format = rres[0]->format; - -rres->type == RRES_TYPE_WAVE -Wave wave; -wave.data = rres[0]->data; -wave.sampleCount = rres[0]->param1; -wave.sampleRate = rres[0]->param2; -wave.sampleSize = rres[0]->param3; -wave.channels = rres[0]->param4; - -rres->type == RRES_TYPE_VERTEX (multiple parts) -Mesh mesh; -mesh.vertexCount = rres[0]->param1; -mesh.vertices = (float *)rres[0]->data; -mesh.texcoords = (float *)rres[1]->data; -mesh.normals = (float *)rres[2]->data; -mesh.tangents = (float *)rres[3]->data; -mesh.tangents = (unsigned char *)rres[4]->data; - -rres->type == RRES_TYPE_TEXT -unsigned char *text = (unsigned char *)rres->data; -Shader shader = LoadShaderText(text, rres->param1); Shader LoadShaderText(const char *shdrText, int length); - -rres->type == RRES_TYPE_FONT_IMAGE (multiple parts) -rres->type == RRES_TYPE_FONT_CHARDATA -SpriteFont font; -font.texture = LoadTextureFromImage(image); // rres[0] -font.chars = (CharInfo *)rres[1]->data; -font.charsCount = rres[1]->param1; -font.baseSize = rres[1]->param2; - -rres->type == RRES_TYPE_DIRECTORY -unsigned char *fileNames = (unsigned char *)rres[0]->data; // fileNames separed by \n -int filesCount = rres[0]->param1; -*/ - -#endif // RRES_H - - -/*********************************************************************************** -* -* RRES IMPLEMENTATION -* -************************************************************************************/ - -#if defined(RRES_IMPLEMENTATION) - -#include // Required for: FILE, fopen(), fclose() - -// Check if custom malloc/free functions defined, if not, using standard ones -#if !defined(RRES_MALLOC) - #include // Required for: malloc(), free() - - #define RRES_MALLOC(size) malloc(size) - #define RRES_FREE(ptr) free(ptr) -#endif - -#include "external/tinfl.c" // Required for: tinfl_decompress_mem_to_mem() - // NOTE: DEFLATE algorythm data decompression - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- - -// rRES file header (8 byte) -typedef struct { - char id[4]; // File identifier: rRES (4 byte) - unsigned short version; // File version and subversion (2 byte) - unsigned short count; // Number of resources in this file (2 byte) -} RRESFileHeader; - -// rRES info header, every resource includes this header (16 byte + 16 byte) -typedef struct { - unsigned int id; // Resource unique identifier (4 byte) - unsigned char dataType; // Resource data type (1 byte) - unsigned char compType; // Resource data compression type (1 byte) - unsigned char cryptoType; // Resource data encryption type (1 byte) - unsigned char partsCount; // Resource data parts count, used for splitted data (1 byte) - unsigned int dataSize; // Resource data size (compressed or not, only DATA) (4 byte) - unsigned int uncompSize; // Resource data size (uncompressed, only DATA) (4 byte) - - unsigned int param1; // Resouce parameter 1 (4 byte) - unsigned int param2; // Resouce parameter 2 (4 byte) - unsigned int param3; // Resouce parameter 3 (4 byte) - unsigned int param4; // Resouce parameter 4 (4 byte) -} RRESInfoHeader; - -// Compression types -typedef enum { - RRES_COMP_NONE = 0, // No data compression - RRES_COMP_DEFLATE, // DEFLATE compression - RRES_COMP_LZ4, // LZ4 compression - RRES_COMP_LZMA, // LZMA compression - RRES_COMP_BROTLI, // BROTLI compression - // gzip, zopfli, lzo, zstd // Other compression algorythms... -} RRESCompressionType; - -// Encryption types -typedef enum { - RRES_CRYPTO_NONE = 0, // No data encryption - RRES_CRYPTO_XOR, // XOR (128 bit) encryption - RRES_CRYPTO_AES, // RIJNDAEL (128 bit) encryption (AES) - RRES_CRYPTO_TDES, // Triple DES encryption - RRES_CRYPTO_BLOWFISH, // BLOWFISH encryption - RRES_CRYPTO_XTEA, // XTEA encryption - // twofish, RC5, RC6 // Other encryption algorythm... -} RRESEncryptionType; - -// Image/Texture data type -typedef enum { - RRES_IM_UNCOMP_GRAYSCALE = 1, // 8 bit per pixel (no alpha) - RRES_IM_UNCOMP_GRAY_ALPHA, // 16 bpp (2 channels) - RRES_IM_UNCOMP_R5G6B5, // 16 bpp - RRES_IM_UNCOMP_R8G8B8, // 24 bpp - RRES_IM_UNCOMP_R5G5B5A1, // 16 bpp (1 bit alpha) - RRES_IM_UNCOMP_R4G4B4A4, // 16 bpp (4 bit alpha) - RRES_IM_UNCOMP_R8G8B8A8, // 32 bpp - RRES_IM_COMP_DXT1_RGB, // 4 bpp (no alpha) - RRES_IM_COMP_DXT1_RGBA, // 4 bpp (1 bit alpha) - RRES_IM_COMP_DXT3_RGBA, // 8 bpp - RRES_IM_COMP_DXT5_RGBA, // 8 bpp - RRES_IM_COMP_ETC1_RGB, // 4 bpp - RRES_IM_COMP_ETC2_RGB, // 4 bpp - RRES_IM_COMP_ETC2_EAC_RGBA, // 8 bpp - RRES_IM_COMP_PVRT_RGB, // 4 bpp - RRES_IM_COMP_PVRT_RGBA, // 4 bpp - RRES_IM_COMP_ASTC_4x4_RGBA, // 8 bpp - RRES_IM_COMP_ASTC_8x8_RGBA // 2 bpp - //... -} RRESImageFormat; - -// Vertex data type -typedef enum { - RRES_VERT_POSITION, - RRES_VERT_TEXCOORD1, - RRES_VERT_TEXCOORD2, - RRES_VERT_TEXCOORD3, - RRES_VERT_TEXCOORD4, - RRES_VERT_NORMAL, - RRES_VERT_TANGENT, - RRES_VERT_COLOR, - RRES_VERT_INDEX, - //... -} RRESVertexType; - -// Vertex data format type -typedef enum { - RRES_VERT_BYTE, - RRES_VERT_SHORT, - RRES_VERT_INT, - RRES_VERT_HFLOAT, - RRES_VERT_FLOAT, - //... -} RRESVertexFormat; - -#if defined(RRES_STANDALONE) -typedef enum { LOG_INFO = 0, LOG_ERROR, LOG_WARNING, LOG_DEBUG, LOG_OTHER } TraceLogType; -#endif - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static void *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize); - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Load resource from file by id (could be multiple parts) -// NOTE: Returns uncompressed data with parameters, search resource by id -RRESDEF RRES LoadResource(const char *fileName, int rresId) -{ - RRES rres = { 0 }; - - RRESFileHeader fileHeader; - RRESInfoHeader infoHeader; - - FILE *rresFile = fopen(fileName, "rb"); - - if (rresFile == NULL) TraceLog(LOG_WARNING, "[%s] rRES raylib resource file could not be opened", fileName); - else - { - // Read rres file info header - fread(&fileHeader.id[0], sizeof(char), 1, rresFile); - fread(&fileHeader.id[1], sizeof(char), 1, rresFile); - fread(&fileHeader.id[2], sizeof(char), 1, rresFile); - fread(&fileHeader.id[3], sizeof(char), 1, rresFile); - fread(&fileHeader.version, sizeof(short), 1, rresFile); - fread(&fileHeader.count, sizeof(short), 1, rresFile); - - // Verify "rRES" identifier - if ((fileHeader.id[0] != 'r') && (fileHeader.id[1] != 'R') && (fileHeader.id[2] != 'E') && (fileHeader.id[3] != 'S')) - { - TraceLog(LOG_WARNING, "[%s] This is not a valid raylib resource file", fileName); - } - else - { - for (int i = 0; i < fileHeader.count; i++) - { - // Read resource info and parameters - fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile); - - if (infoHeader.id == rresId) - { - rres = (RRES)malloc(sizeof(RRESData)*infoHeader.partsCount); - - // Load all required resources parts - for (int k = 0; k < infoHeader.partsCount; k++) - { - // TODO: Verify again that rresId is the same in every part - - // Register data type and parameters - rres[k].type = infoHeader.dataType; - rres[k].param1 = infoHeader.param1; - rres[k].param2 = infoHeader.param2; - rres[k].param3 = infoHeader.param3; - rres[k].param4 = infoHeader.param4; - - // Read resource data block - void *data = RRES_MALLOC(infoHeader.dataSize); - fread(data, infoHeader.dataSize, 1, rresFile); - - if (infoHeader.compType == RRES_COMP_DEFLATE) - { - void *uncompData = DecompressData(data, infoHeader.dataSize, infoHeader.uncompSize); - - rres[k].data = uncompData; - - RRES_FREE(data); - } - else rres[k].data = data; - - if (rres[k].data != NULL) TraceLog(LOG_INFO, "[%s][ID %i] Resource data loaded successfully", fileName, (int)infoHeader.id); - - // Read next part - fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile); - } - } - else - { - // Skip required data to read next resource infoHeader - fseek(rresFile, infoHeader.dataSize, SEEK_CUR); - } - } - - if (rres[0].data == NULL) TraceLog(LOG_WARNING, "[%s][ID %i] Requested resource could not be found", fileName, (int)rresId); - } - - fclose(rresFile); - } - - return rres; -} - -// Unload resource data -RRESDEF void UnloadResource(RRES rres) -{ - // TODO: When you load resource... how many parts conform it? depends on type? --> Not clear... - - if (rres[0].data != NULL) free(rres[0].data); -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - -// Data decompression function -// NOTE: Allocated data MUST be freed by user -static void *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize) -{ - int tempUncompSize; - void *uncompData; - - // Allocate buffer to hold decompressed data - uncompData = (mz_uint8 *)RRES_MALLOC((size_t)uncompSize); - - // Check correct memory allocation - if (uncompData == NULL) - { - TraceLog(LOG_WARNING, "Out of memory while decompressing data"); - } - else - { - // Decompress data - tempUncompSize = tinfl_decompress_mem_to_mem(uncompData, (size_t)uncompSize, data, compSize, 1); - - if (tempUncompSize == -1) - { - TraceLog(LOG_WARNING, "Data decompression failed"); - RRES_FREE(uncompData); - } - - if (uncompSize != (int)tempUncompSize) - { - TraceLog(LOG_WARNING, "Expected uncompressed size do not match, data may be corrupted"); - TraceLog(LOG_WARNING, " -- Expected uncompressed size: %i", uncompSize); - TraceLog(LOG_WARNING, " -- Returned uncompressed size: %i", tempUncompSize); - } - - TraceLog(LOG_INFO, "Data decompressed successfully from %u bytes to %u bytes", (mz_uint32)compSize, (mz_uint32)tempUncompSize); - } - - return uncompData; -} - -// Some required functions for rres standalone module version -#if defined(RRES_STANDALONE) -// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) -void TraceLog(int logType, const char *text, ...) -{ - va_list args; - va_start(args, text); - - switch (msgType) - { - case LOG_INFO: fprintf(stdout, "INFO: "); break; - case LOG_ERROR: fprintf(stdout, "ERROR: "); break; - case LOG_WARNING: fprintf(stdout, "WARNING: "); break; - case LOG_DEBUG: fprintf(stdout, "DEBUG: "); break; - default: break; - } - - vfprintf(stdout, text, args); - fprintf(stdout, "\n"); - - va_end(args); - - if (msgType == LOG_ERROR) exit(1); -} -#endif - -#endif // RRES_IMPLEMENTATION diff --git a/src/text.c b/src/text.c index 8db2fc9f..0215bb5b 100644 --- a/src/text.c +++ b/src/text.c @@ -288,35 +288,8 @@ SpriteFont LoadSpriteFont(const char *fileName) SpriteFont spriteFont = { 0 }; - // Check file extension - if (IsFileExtension(fileName, ".rres")) - { - // TODO: Read multiple resource blocks from file (RRES_FONT_IMAGE, RRES_FONT_CHARDATA) - RRES rres = LoadResource(fileName, 0); - - // Load sprite font texture - if (rres[0].type == RRES_TYPE_FONT_IMAGE) - { - // NOTE: Parameters for RRES_FONT_IMAGE type are: width, height, format, mipmaps - Image image = LoadImagePro(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3); - spriteFont.texture = LoadTextureFromImage(image); - UnloadImage(image); - } - - // Load sprite characters data - if (rres[1].type == RRES_TYPE_FONT_CHARDATA) - { - // NOTE: Parameters for RRES_FONT_CHARDATA type are: fontSize, charsCount - spriteFont.baseSize = rres[1].param1; - spriteFont.charsCount = rres[1].param2; - spriteFont.chars = rres[1].data; - } - - // TODO: Do not free rres.data memory (chars info data!) - //UnloadResource(rres[0]); - } #if defined(SUPPORT_FILEFORMAT_TTF) - else if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadSpriteFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); + if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadSpriteFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); #endif #if defined(SUPPORT_FILEFORMAT_FNT) else if (IsFileExtension(fileName, ".fnt")) spriteFont = LoadBMFont(fileName); diff --git a/src/textures.c b/src/textures.c index 090de24b..6bd306f4 100644 --- a/src/textures.c +++ b/src/textures.c @@ -167,18 +167,7 @@ Image LoadImage(const char *fileName) { Image image = { 0 }; - if (IsFileExtension(fileName, ".rres")) - { - RRES rres = LoadResource(fileName, 0); - - // NOTE: Parameters for RRES_TYPE_IMAGE are: width, height, format, mipmaps - - if (rres[0].type == RRES_TYPE_IMAGE) image = LoadImagePro(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3); - else TraceLog(LOG_WARNING, "[%s] Resource file does not contain image data", fileName); - - UnloadResource(rres); - } - else if ((IsFileExtension(fileName, ".png")) + if ((IsFileExtension(fileName, ".png")) #if defined(SUPPORT_FILEFORMAT_BMP) || (IsFileExtension(fileName, ".bmp")) #endif diff --git a/src/utils.c b/src/utils.c index 967ed916..aaa5bdb4 100644 --- a/src/utils.c +++ b/src/utils.c @@ -66,9 +66,6 @@ #include "external/stb_image_write.h" // Required for: stbi_write_bmp(), stbi_write_png() #endif -#define RRES_IMPLEMENTATION -#include "rres.h" - //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- diff --git a/src/utils.h b/src/utils.h index 64592c73..a1801245 100644 --- a/src/utils.h +++ b/src/utils.h @@ -32,8 +32,6 @@ #include // Required for: AAssetManager #endif -#include "rres.h" - #define SUPPORT_SAVE_PNG //---------------------------------------------------------------------------------- From 2388cbc3cd73ab228a4d60f05becd51035c703ea Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 13 Dec 2017 20:10:13 +0100 Subject: [PATCH 072/139] Corrected crash on shader loading If shader file could not be found on loading it crashed, instead added fallback to default shader! --- src/rlgl.c | 51 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/rlgl.c b/src/rlgl.c index 6ae7df4c..cdce92d0 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2365,38 +2365,49 @@ Shader LoadShader(char *vsFileName, char *fsFileName) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - unsigned int vertexShaderId, fragmentShaderId; + unsigned int vertexShaderId = defaultVShaderId; + unsigned int fragmentShaderId = defaultFShaderId; - if (vsFileName == NULL) vertexShaderId = defaultVShaderId; - else + if (vsFileName != NULL) { char *vShaderStr = LoadText(vsFileName); - vertexShaderId = CompileShader(vShaderStr, GL_VERTEX_SHADER); - free(vShaderStr); + + if (vShaderStr != NULL) + { + vertexShaderId = CompileShader(vShaderStr, GL_VERTEX_SHADER); + free(vShaderStr); + } } - if (fsFileName == NULL) fragmentShaderId = defaultVShaderId; - else + if (fsFileName != NULL) { char* fShaderStr = LoadText(fsFileName); - fragmentShaderId = CompileShader(fShaderStr, GL_FRAGMENT_SHADER); - free(fShaderStr); + + if (fShaderStr != NULL) + { + fragmentShaderId = CompileShader(fShaderStr, GL_FRAGMENT_SHADER); + free(fShaderStr); + } } - shader.id = LoadShaderProgram(vertexShaderId, fragmentShaderId); - - if (vertexShaderId != defaultVShaderId) glDeleteShader(vertexShaderId); - if (fragmentShaderId != defaultFShaderId) glDeleteShader(fragmentShaderId); - - if (shader.id == 0) + if ((vertexShaderId == defaultVShaderId) && (fragmentShaderId == defaultFShaderId)) shader = defaultShader; + else { - TraceLog(LOG_WARNING, "Custom shader could not be loaded"); - shader = defaultShader; + shader.id = LoadShaderProgram(vertexShaderId, fragmentShaderId); + + if (vertexShaderId != defaultVShaderId) glDeleteShader(vertexShaderId); + if (fragmentShaderId != defaultFShaderId) glDeleteShader(fragmentShaderId); + + if (shader.id == 0) + { + TraceLog(LOG_WARNING, "Custom shader could not be loaded"); + shader = defaultShader; + } + + // After shader loading, we TRY to set default location names + if (shader.id > 0) SetShaderDefaultLocations(&shader); } - // After shader loading, we TRY to set default location names - if (shader.id > 0) SetShaderDefaultLocations(&shader); - // Get available shader uniforms // NOTE: This information is useful for debug... int uniformCount = -1; From 08fc886afd88907516dc7519ac7542fa30e5f369 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:40:08 +0100 Subject: [PATCH 073/139] added proper define checks for png-save if it's disabled --- src/core.c | 2 +- src/textures.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core.c b/src/core.c index ec7db978..d4646268 100644 --- a/src/core.c +++ b/src/core.c @@ -1134,7 +1134,7 @@ void SetConfigFlags(char flags) // Takes a screenshot of current screen (saved a .png) void TakeScreenshot(const char *fileName) { -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) +#if (defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)) && defined(SUPPORT_SAVE_PNG) unsigned char *imgData = rlReadScreenPixels(renderWidth, renderHeight); SavePNG(fileName, imgData, renderWidth, renderHeight, 4); // Save image as PNG free(imgData); diff --git a/src/textures.c b/src/textures.c index 6bd306f4..55749118 100644 --- a/src/textures.c +++ b/src/textures.c @@ -554,7 +554,7 @@ void UpdateTexture(Texture2D texture, const void *pixels) // Save image to a PNG file void SaveImageAs(const char* fileName, Image image) { -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) +#if (defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)) && defined(SUPPORT_SAVE_PNG) unsigned char* imgData = (unsigned char*)GetImageData(image); // this works since Color is just a container for the RGBA values SavePNG(fileName, imgData, image.width, image.height, 4); free(imgData); From 54587d7fdb6bf250c70f6a5eb653496e9bdf24ea Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:41:31 +0100 Subject: [PATCH 074/139] proper if-clauses for disabling functionality in text.c --- src/text.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/text.c b/src/text.c index 0215bb5b..f577be19 100644 --- a/src/text.c +++ b/src/text.c @@ -290,11 +290,12 @@ SpriteFont LoadSpriteFont(const char *fileName) #if defined(SUPPORT_FILEFORMAT_TTF) if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadSpriteFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); + else #endif #if defined(SUPPORT_FILEFORMAT_FNT) - else if (IsFileExtension(fileName, ".fnt")) spriteFont = LoadBMFont(fileName); -#endif + if (IsFileExtension(fileName, ".fnt")) spriteFont = LoadBMFont(fileName); else +#endif { Image image = LoadImage(fileName); if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR); From 69c8fa409a6eed0c6b041d288d40e25b4dbda740 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:42:06 +0100 Subject: [PATCH 075/139] fixed function declaration differ from implementation --- src/rlgl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 2e67c699..90d6a71b 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -456,8 +456,8 @@ Texture2D GetTextureDefault(void); // Get default texture // Shader configuration functions int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location -void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) -void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) +void SetShaderValue(Shader shader, int uniformLoc, const float *value, int size); // Set shader uniform value (float) +void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int size); // Set shader uniform value (int) void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) From 963551ee6e99e069fca8eed47151f4caf628507e Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:43:06 +0100 Subject: [PATCH 076/139] added possibility to get modelview matrix from rlgl to be able to send it to shaders --- src/rlgl.c | 6 ++++++ src/rlgl.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/rlgl.c b/src/rlgl.c index cdce92d0..5db6f1cc 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2539,6 +2539,12 @@ void SetMatrixModelview(Matrix view) #endif } +Matrix GetMatrixModelview() { +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + return modelview; +#endif +} + // Generate cubemap texture from HDR texture // TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24 Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size) diff --git a/src/rlgl.h b/src/rlgl.h index 90d6a71b..a54a912f 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -461,6 +461,8 @@ void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int size); void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) +Matrix GetMatrixModelview(); + // Texture maps generation (PBR) // NOTE: Required shaders should be provided From 0e18b146055efd18029c4ac5553fd1e53dfbbfc8 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:44:48 +0100 Subject: [PATCH 077/139] added debug-event-markers for opengl so that you're able to set markers for renderdoc or other gpu debuggers what your program is currently doing --- src/external/glad.h | 25 +++++++++++++++++++++++++ src/rlgl.c | 8 ++++++++ src/rlgl.h | 3 +++ 3 files changed, 36 insertions(+) diff --git a/src/external/glad.h b/src/external/glad.h index ab5947e6..70dbc739 100644 --- a/src/external/glad.h +++ b/src/external/glad.h @@ -3446,6 +3446,19 @@ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC)(GLenum sfactorRGB, GLenum GLAPI PFNGLBLENDFUNCSEPARATEEXTPROC glad_glBlendFuncSeparateEXT; #define glBlendFuncSeparateEXT glad_glBlendFuncSeparateEXT #endif +#ifndef GL_EXT_debug_marker +#define GL_EXT_debug_marker 1 +GLAPI int GLAD_GL_EXT_debug_marker; +typedef void (APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC)(GLsizei length, const GLchar *marker); +GLAPI PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT; +#define glInsertEventMarkerEXT glad_glInsertEventMarkerEXT +typedef void (APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC)(GLsizei length, const GLchar *marker); +GLAPI PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT; +#define glPushGroupMarkerEXT glad_glPushGroupMarkerEXT +typedef void (APIENTRYP PFNGLPOPGROUPMARKEREXTPROC)(void); +GLAPI PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT; +#define glPopGroupMarkerEXT glad_glPopGroupMarkerEXT +#endif #ifndef GL_EXT_framebuffer_blit #define GL_EXT_framebuffer_blit 1 GLAPI int GLAD_GL_EXT_framebuffer_blit; @@ -4209,6 +4222,7 @@ int GLAD_GL_ARB_vertex_shader; int GLAD_GL_ARB_vertex_attrib_binding; int GLAD_GL_ARB_vertex_program; int GLAD_GL_EXT_texture_compression_s3tc; +int GLAD_GL_EXT_debug_marker; int GLAD_GL_EXT_texture_swizzle; int GLAD_GL_ARB_texture_multisample; int GLAD_GL_ARB_texture_rg; @@ -4391,6 +4405,9 @@ PFNGLGETVARIANTARRAYOBJECTIVATIPROC glad_glGetVariantArrayObjectivATI; PFNGLBLENDCOLOREXTPROC glad_glBlendColorEXT; PFNGLBLENDEQUATIONSEPARATEEXTPROC glad_glBlendEquationSeparateEXT; PFNGLBLENDFUNCSEPARATEEXTPROC glad_glBlendFuncSeparateEXT; +PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT; +PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT; +PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT; PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT; PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT; PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT; @@ -5190,6 +5207,12 @@ static void load_GL_EXT_blend_func_separate(GLADloadproc load) { if(!GLAD_GL_EXT_blend_func_separate) return; glad_glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC)load("glBlendFuncSeparateEXT"); } +static void load_GL_EXT_debug_marker(GLADloadproc load) { + if(!GLAD_GL_EXT_debug_marker) return; + glad_glInsertEventMarkerEXT = (PFNGLINSERTEVENTMARKEREXTPROC)load("glInsertEventMarkerEXT"); + glad_glPushGroupMarkerEXT = (PFNGLPUSHGROUPMARKEREXTPROC)load("glPushGroupMarkerEXT"); + glad_glPopGroupMarkerEXT = (PFNGLPOPGROUPMARKEREXTPROC)load("glPopGroupMarkerEXT"); +} static void load_GL_EXT_framebuffer_blit(GLADloadproc load) { if(!GLAD_GL_EXT_framebuffer_blit) return; glad_glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC)load("glBlitFramebufferEXT"); @@ -5316,6 +5339,7 @@ static int find_extensionsGL(void) { GLAD_GL_EXT_blend_color = has_ext("GL_EXT_blend_color"); GLAD_GL_EXT_blend_equation_separate = has_ext("GL_EXT_blend_equation_separate"); GLAD_GL_EXT_blend_func_separate = has_ext("GL_EXT_blend_func_separate"); + GLAD_GL_EXT_debug_marker = has_ext("GL_EXT_debug_marker"); GLAD_GL_EXT_framebuffer_blit = has_ext("GL_EXT_framebuffer_blit"); GLAD_GL_EXT_framebuffer_multisample = has_ext("GL_EXT_framebuffer_multisample"); GLAD_GL_EXT_framebuffer_multisample_blit_scaled = has_ext("GL_EXT_framebuffer_multisample_blit_scaled"); @@ -5430,6 +5454,7 @@ int gladLoadGLLoader(GLADloadproc load) { load_GL_EXT_blend_color(load); load_GL_EXT_blend_equation_separate(load); load_GL_EXT_blend_func_separate(load); + load_GL_EXT_debug_marker(load); load_GL_EXT_framebuffer_blit(load); load_GL_EXT_framebuffer_multisample(load); load_GL_EXT_framebuffer_object(load); diff --git a/src/rlgl.c b/src/rlgl.c index 5db6f1cc..e34e48da 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -307,6 +307,8 @@ static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays; //static PFNGLISVERTEXARRAYOESPROC glIsVertexArray; // NOTE: Fails in WebGL, omitted #endif +static bool debugMarkerSupported = false; + // Compressed textures support flags static bool texCompDXTSupported = false; // DDS texture compression support static bool texNPOTSupported = false; // NPOT textures full support @@ -1135,6 +1137,10 @@ void rlglInit(int width, int height) glGetFloatv(0x84FF, &maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT } + if(strcmp(extList[i], (const char *)"GL_EXT_debug_marker") == 0) { + debugMarkerSupported = true; + } + // Clamp mirror wrap mode supported if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true; } @@ -1160,6 +1166,8 @@ void rlglInit(int width, int height) if (texAnisotropicFilterSupported) TraceLog(LOG_INFO, "[EXTENSION] Anisotropic textures filtering supported (max: %.0fX)", maxAnisotropicLevel); if (texClampMirrorSupported) TraceLog(LOG_INFO, "[EXTENSION] Clamp mirror wrap texture mode supported"); + if (debugMarkerSupported) TraceLog(LOG_INFO, "[EXTENSION] Debug Marker supported"); + // Initialize buffers, default shaders and default textures //---------------------------------------------------------- diff --git a/src/rlgl.h b/src/rlgl.h index a54a912f..93afb44e 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -440,6 +440,9 @@ void rlUpdateMesh(Mesh mesh, int buffer, int numVertex); // Update ve void rlDrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform void rlUnloadMesh(Mesh *mesh); // Unload mesh data from CPU and GPU +// Debug Marker for Analysis +void rlSetMarker(const char *text); + // NOTE: There is a set of shader related functions that are available to end user, // to avoid creating function wrappers through core module, they have been directly declared in raylib.h From a7f2fedbfbfde92e7c12c21b108a2b99965bc28d Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:45:47 +0100 Subject: [PATCH 078/139] compilefix for function declaration (win only) --- src/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core.c b/src/core.c index d4646268..882aadcd 100644 --- a/src/core.c +++ b/src/core.c @@ -153,8 +153,9 @@ //#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version! #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) - __stdcall unsigned int timeBeginPeriod(unsigned int uPeriod); - __stdcall unsigned int timeEndPeriod(unsigned int uPeriod); + // NOTE: Those functions require linking with winmm library + unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod); + unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #endif #endif From 07b522c1131faf29df49da5f0f09826cef765d4b Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:46:38 +0100 Subject: [PATCH 079/139] make matrix stack work closer to old opengl implementation --- src/rlgl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rlgl.c b/src/rlgl.c index e34e48da..7ec4c4ac 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -414,7 +414,7 @@ void rlPushMatrix(void) } stack[stackCounter] = *currentMatrix; - rlLoadIdentity(); +// rlLoadIdentity(); stackCounter++; if (currentMatrixMode == RL_MODELVIEW) useTempBuffer = true; From b5395b22cc920bf4b92742c284180ffc8ba9e897 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:47:52 +0100 Subject: [PATCH 080/139] make raymath compiling with msvc in c++ mode --- src/raymath.h | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/raymath.h b/src/raymath.h index decd02c5..47f77e85 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -227,21 +227,29 @@ RMDEF float Clamp(float value, float min, float max) //---------------------------------------------------------------------------------- // Vector with components value 0.0f -RMDEF Vector2 Vector2Zero(void) { return (Vector2){ 0.0f, 0.0f }; } +RMDEF Vector2 Vector2Zero(void) { + Vector2 tmp = {0.0f, 0.0f}; + return tmp; +} // Vector with components value 1.0f -RMDEF Vector2 Vector2One(void) { return (Vector2){ 1.0f, 1.0f }; } +RMDEF Vector2 Vector2One(void) { + Vector2 tmp = {1.0f, 1.0f}; + return tmp; +} // Add two vectors (v1 + v2) RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2) { - return (Vector2){ v1.x + v2.x, v1.y + v2.y }; + Vector2 tmp = { v1.x + v2.x, v1.y + v2.y }; + return tmp; } // Subtract two vectors (v1 - v2) RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) { - return (Vector2){ v1.x - v2.x, v1.y - v2.y }; + Vector2 tmp = { v1.x - v2.x, v1.y - v2.y }; + return tmp; } // Calculate vector length @@ -289,7 +297,8 @@ RMDEF void Vector2Negate(Vector2 *v) // Divide vector by a float value RMDEF void Vector2Divide(Vector2 *v, float div) { - *v = (Vector2){v->x/div, v->y/div}; + Vector2 tmp = {v->x/div, v->y/div}; + *v = tmp; } // Normalize provided vector @@ -303,21 +312,29 @@ RMDEF void Vector2Normalize(Vector2 *v) //---------------------------------------------------------------------------------- // Vector with components value 0.0f -RMDEF Vector3 Vector3Zero(void) { return (Vector3){ 0.0f, 0.0f, 0.0f }; } +RMDEF Vector3 Vector3Zero(void) { + Vector3 tmp = { 0.0f, 0.0f, 0.0f }; + return tmp; +} // Vector with components value 1.0f -RMDEF Vector3 Vector3One(void) { return (Vector3){ 1.0f, 1.0f, 1.0f }; } +RMDEF Vector3 Vector3One(void) { + Vector3 tmp = { 1.0f, 1.0f, 1.0f }; + return tmp; +} // Add two vectors RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2) { - return (Vector3){ v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; + Vector3 tmp = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; + return tmp; } // Substract two vectors RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2) { - return (Vector3){ v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; + Vector3 tmp = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; + return tmp; } // Multiply vector by scalar @@ -365,12 +382,14 @@ RMDEF Vector3 Vector3Perpendicular(Vector3 v) if (fabsf(v.y) < min) { min = fabsf(v.y); - cardinalAxis = (Vector3){0.0f, 1.0f, 0.0f}; + Vector3 tmp = {0.0f, 1.0f, 0.0f}; + cardinalAxis = tmp; } if (fabsf(v.z) < min) { - cardinalAxis = (Vector3){0.0f, 0.0f, 1.0f}; + Vector3 tmp = {0.0f, 0.0f, 1.0f}; + cardinalAxis = tmp; } result = Vector3CrossProduct(v, cardinalAxis); @@ -1011,7 +1030,8 @@ RMDEF float *MatrixToFloat(Matrix mat) // Returns identity quaternion RMDEF Quaternion QuaternionIdentity(void) { - return (Quaternion){ 0.0f, 0.0f, 0.0f, 1.0f }; + Quaternion q = { 0.0f, 0.0f, 0.0f, 1.0f }; + return q; } // Computes the length of a quaternion From d51f382ef858700e173bd25a7f0fdd8ed64dbbb8 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:48:33 +0100 Subject: [PATCH 081/139] optimized matrixrotate function by removing identity matrix --- src/raymath.h | 46 ++++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/src/raymath.h b/src/raymath.h index 47f77e85..3d95a089 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -759,8 +759,6 @@ RMDEF Matrix MatrixRotate(Vector3 axis, float angle) { Matrix result; - Matrix mat = MatrixIdentity(); - float x = axis.x, y = axis.y, z = axis.z; float length = sqrtf(x*x + y*y + z*z); @@ -777,33 +775,25 @@ RMDEF Matrix MatrixRotate(Vector3 axis, float angle) float cosres = cosf(angle); float t = 1.0f - cosres; - // Cache some matrix values (speed optimization) - float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; - float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; - float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; + result.m0 = x*x*t + cosres; + result.m1 = y*x*t + z*sinres; + result.m2 = z*x*t - y*sinres; + result.m3 = 0.0f; - // Construct the elements of the rotation matrix - float b00 = x*x*t + cosres, b01 = y*x*t + z*sinres, b02 = z*x*t - y*sinres; - float b10 = x*y*t - z*sinres, b11 = y*y*t + cosres, b12 = z*y*t + x*sinres; - float b20 = x*z*t + y*sinres, b21 = y*z*t - x*sinres, b22 = z*z*t + cosres; - - // Perform rotation-specific matrix multiplication - result.m0 = a00*b00 + a10*b01 + a20*b02; - result.m1 = a01*b00 + a11*b01 + a21*b02; - result.m2 = a02*b00 + a12*b01 + a22*b02; - result.m3 = a03*b00 + a13*b01 + a23*b02; - result.m4 = a00*b10 + a10*b11 + a20*b12; - result.m5 = a01*b10 + a11*b11 + a21*b12; - result.m6 = a02*b10 + a12*b11 + a22*b12; - result.m7 = a03*b10 + a13*b11 + a23*b12; - result.m8 = a00*b20 + a10*b21 + a20*b22; - result.m9 = a01*b20 + a11*b21 + a21*b22; - result.m10 = a02*b20 + a12*b21 + a22*b22; - result.m11 = a03*b20 + a13*b21 + a23*b22; - result.m12 = mat.m12; - result.m13 = mat.m13; - result.m14 = mat.m14; - result.m15 = mat.m15; + result.m4 = x*y*t - z*sinres; + result.m5 = y*y*t + cosres; + result.m6 = z*y*t + x*sinres; + result.m7 = 0.0f; + + result.m8 = x*z*t + y*sinres; + result.m9 = y*z*t - x*sinres; + result.m10 = z*z*t + cosres; + result.m11 = 0.0f; + + result.m12 = 0.0f; + result.m13 = 0.0f; + result.m14 = 0.0f; + result.m15 = 1.0f; return result; } From b872de951b0c1a830e3452ede6fbdd471df0d025 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:49:31 +0100 Subject: [PATCH 082/139] fix for GetMatrixModelview (former cl) --- src/raylib.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/raylib.h b/src/raylib.h index ac739830..9af21872 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1046,6 +1046,7 @@ RLAPI void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) +RLAPI Matrix GetMatrixModelview(); // Texture maps generation (PBR) // NOTE: Required shaders should be provided From 48d0c93ace63225231d56f6a7aaa058218622578 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:50:35 +0100 Subject: [PATCH 083/139] make GetTime available to user of library --- src/core.c | 4 ++-- src/raylib.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/core.c b/src/core.c index 882aadcd..011e0d76 100644 --- a/src/core.c +++ b/src/core.c @@ -352,7 +352,7 @@ extern void UnloadDefaultFont(void); // [Module: text] Unloads default fo static void InitGraphicsDevice(int width, int height); // Initialize graphics device static void SetupFramebufferSize(int displayWidth, int displayHeight); static void InitTimer(void); // Initialize timer -static double GetTime(void); // Returns time since InitTimer() was run + double GetTime(void); // Returns time since InitTimer() was run static void Wait(float ms); // Wait for some milliseconds (stop program execution) static bool GetKeyStatus(int key); // Returns if a key has been pressed static bool GetMouseButtonStatus(int button); // Returns if a mouse button has been pressed @@ -2120,7 +2120,7 @@ static void InitTimer(void) } // Get current time measure (in seconds) since InitTimer() -static double GetTime(void) +double GetTime(void) { #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetTime(); diff --git a/src/raylib.h b/src/raylib.h index 9af21872..0a9eab46 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -723,6 +723,9 @@ RLAPI void SetTargetFPS(int fps); // Set target RLAPI int GetFPS(void); // Returns current FPS RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn +RLAPI double GetTime(void); // Return time in seconds + + // Color-related functions RLAPI int GetHexValue(Color color); // Returns hexadecimal value for a Color RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value From 217917530b12c7332fb83381aef6acf9975e7361 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:51:17 +0100 Subject: [PATCH 084/139] fix for eventmarker missed in first cl --- src/rlgl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/rlgl.c b/src/rlgl.c index 7ec4c4ac..713646ac 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -4226,3 +4226,8 @@ void TraceLog(int msgType, const char *text, ...) if (msgType == LOG_ERROR) exit(1); } #endif + +void rlSetMarker(const char *text) { + if(debugMarkerSupported) + glInsertEventMarkerEXT(0, text); //0 terminated string +} From 2affac820e64393ac4294c53c1a7f47742e8dec9 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 14 Dec 2017 11:52:45 +0100 Subject: [PATCH 085/139] make raylib not clash with windows-header --- src/core.c | 10 +++++----- src/raylib.h | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core.c b/src/core.c index 011e0d76..8e26d2b1 100644 --- a/src/core.c +++ b/src/core.c @@ -413,7 +413,7 @@ static void *GamepadThread(void *arg); // Mouse reading thread #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // Initialize window and OpenGL context // NOTE: data parameter could be used to pass any kind of required data to the initialization -void InitWindow(int width, int height, void *data) +void InitRLWindow(int width, int height, void *data) { TraceLog(LOG_INFO, "Initializing raylib (v1.9-dev)"); @@ -477,7 +477,7 @@ void InitWindow(int width, int height, void *data) #if defined(PLATFORM_ANDROID) // Initialize window and OpenGL context (and Android activity) // NOTE: data parameter could be used to pass any kind of required data to the initialization -void InitWindow(int width, int height, void *data) +void InitRLWindow(int width, int height, void *data) { TraceLog(LOG_INFO, "Initializing raylib (v1.9-dev)"); @@ -538,7 +538,7 @@ void InitWindow(int width, int height, void *data) #endif // Close window and unload OpenGL context -void CloseWindow(void) +void CloseRLWindow(void) { #if defined(SUPPORT_GIF_RECORDING) if (gifRecording) @@ -715,7 +715,7 @@ int GetScreenHeight(void) } // Show mouse cursor -void ShowCursor() +void ShowRLCursor() { #if defined(PLATFORM_DESKTOP) #if defined(__linux__) @@ -728,7 +728,7 @@ void ShowCursor() } // Hides mouse cursor -void HideCursor() +void HideRLCursor() { #if defined(PLATFORM_DESKTOP) #if defined(__linux__) diff --git a/src/raylib.h b/src/raylib.h index 0a9eab46..16595b5b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -682,8 +682,8 @@ extern "C" { // Prevents name mangling of functions //------------------------------------------------------------------------------------ // Window-related functions -RLAPI void InitWindow(int width, int height, void *data); // Initialize window and OpenGL context -RLAPI void CloseWindow(void); // Close window and unload OpenGL context +RLAPI void InitRLWindow(int width, int height, void *data); // Initialize window and OpenGL context +RLAPI void CloseRLWindow(void); // Close window and unload OpenGL context RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed RLAPI bool IsWindowMinimized(void); // Check if window has been minimized (or lost focus) RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (only PLATFORM_DESKTOP) @@ -696,8 +696,8 @@ RLAPI int GetScreenWidth(void); // Get current RLAPI int GetScreenHeight(void); // Get current screen height // Cursor-related functions -RLAPI void ShowCursor(void); // Shows cursor -RLAPI void HideCursor(void); // Hides cursor +RLAPI void ShowRLCursor(void); // Shows cursor +RLAPI void HideRLCursor(void); // Hides cursor RLAPI bool IsCursorHidden(void); // Check if cursor is not visible RLAPI void EnableCursor(void); // Enables cursor (unlock cursor) RLAPI void DisableCursor(void); // Disables cursor (lock cursor) From 263e81b5c92a575b35e44a33b4b5f833489073a0 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 14 Dec 2017 12:20:05 +0100 Subject: [PATCH 086/139] Build shared libs, games and examples on CI Now with external OpenAL and GLFW dependencies removed, we don't have to worry about installing them in CI. Shared libraries are now always built along with static libs. Games and examples are built everwhere except for Visual Studio, because Physac needs pthreads, which VS doesn't provide. --- .travis.yml | 18 +++++++++--------- appveyor.yml | 6 +++++- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7d1ffef0..62278cd4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,26 +7,26 @@ git: # TODO we could use a 32 bit Docker container for running true 32-bit tests # services: - docker -matrix: # We don't install x11 32-bit libraries, so skip shared libraries on -m32 +matrix: include: - os: linux - env: ARCH=i386 SHARED=OFF EXAMPLES=OFF + env: ARCH=i386 sudo: required - os: linux - env: ARCH=amd64 SHARED=ON EXAMPLES=ON + env: ARCH=amd64 sudo: required - os: osx - env: ARCH=amd64 SHARED=ON EXAMPLES=ON + env: ARCH=amd64 before_script: before_install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -y gcc-multilib - libasound2-dev - libxcursor-dev libxinerama-dev - mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev - libgl1-mesa-dev libglu1-mesa-dev libglew-dev; + libasound2-dev:$ARCH + libxcursor-dev:$ARCH libxinerama-dev:$ARCH mesa-common-dev:$ARCH + libx11-dev:$ARCH libxrandr-dev:$ARCH libxi-dev:$ARCH + libgl1-mesa-dev:$ARCH libglu1-mesa-dev:$ARCH libglew-dev:$ARCH; export RAYLIB_PACKAGE_SUFFIX="-Linux-$ARCH"; if [ "$ARCH" == "i386" ]; then export CFLAGS="-m32"; fi; if [ "$ARCH" == "amd64" ]; then export CFLAGS="-m64"; fi; @@ -37,7 +37,7 @@ before_install: script: - mkdir build - cd build - - cmake -DMACOS_FATLIB=ON -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=$SHARED -DBUILD_EXAMPLES=$EXAMPLES -DBUILD_GAMES=$EXAMPLES .. + - cmake -DMACOS_FATLIB=ON -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=ON -DBUILD_EXAMPLES=ON -DBUILD_GAMES=ON .. - make VERBOSE=1 - make package diff --git a/appveyor.yml b/appveyor.yml index a8572d07..4148e744 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,12 +20,16 @@ environment: matrix: - compiler: mingw bits: 32 + examples: ON - compiler: mingw bits: 64 + examples: ON - compiler: msvc15 bits: 32 + examples: OFF - compiler: msvc15 bits: 64 + examples: OFF before_build: - if [%compiler%]==[mingw] set CFLAGS=-m%BITS% & set LDFLAGS=-m%BITS% & set GENERATOR="MinGW Makefiles" @@ -35,7 +39,7 @@ before_build: - cd build build_script: - - cmake -G %GENERATOR% -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=OFF -DBUILD_EXAMPLES=OFF -DBUILD_GAMES=OFF .. + - cmake -G %GENERATOR% -DSTATIC_RAYLIB=ON -DSHARED_RAYLIB=ON -DBUILD_EXAMPLES=%examples% -DBUILD_GAMES=%examples% .. - cmake --build . --target install after_build: From 53ad53d05127ac083f7439c5c2e1c2ab5e73e1c0 Mon Sep 17 00:00:00 2001 From: Ray San Date: Fri, 15 Dec 2017 13:44:31 +0100 Subject: [PATCH 087/139] Manually review previous PR --- src/core.c | 21 ++++++++++----------- src/raylib.h | 14 ++++++-------- src/raymath.h | 12 ++++++++---- src/rlgl.c | 6 ++++++ src/rlgl.h | 10 ++++------ src/textures.c | 5 ++--- 6 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/core.c b/src/core.c index 8e26d2b1..ec7db978 100644 --- a/src/core.c +++ b/src/core.c @@ -153,9 +153,8 @@ //#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version! #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) - // NOTE: Those functions require linking with winmm library - unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod); - unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); + __stdcall unsigned int timeBeginPeriod(unsigned int uPeriod); + __stdcall unsigned int timeEndPeriod(unsigned int uPeriod); #endif #endif @@ -352,7 +351,7 @@ extern void UnloadDefaultFont(void); // [Module: text] Unloads default fo static void InitGraphicsDevice(int width, int height); // Initialize graphics device static void SetupFramebufferSize(int displayWidth, int displayHeight); static void InitTimer(void); // Initialize timer - double GetTime(void); // Returns time since InitTimer() was run +static double GetTime(void); // Returns time since InitTimer() was run static void Wait(float ms); // Wait for some milliseconds (stop program execution) static bool GetKeyStatus(int key); // Returns if a key has been pressed static bool GetMouseButtonStatus(int button); // Returns if a mouse button has been pressed @@ -413,7 +412,7 @@ static void *GamepadThread(void *arg); // Mouse reading thread #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // Initialize window and OpenGL context // NOTE: data parameter could be used to pass any kind of required data to the initialization -void InitRLWindow(int width, int height, void *data) +void InitWindow(int width, int height, void *data) { TraceLog(LOG_INFO, "Initializing raylib (v1.9-dev)"); @@ -477,7 +476,7 @@ void InitRLWindow(int width, int height, void *data) #if defined(PLATFORM_ANDROID) // Initialize window and OpenGL context (and Android activity) // NOTE: data parameter could be used to pass any kind of required data to the initialization -void InitRLWindow(int width, int height, void *data) +void InitWindow(int width, int height, void *data) { TraceLog(LOG_INFO, "Initializing raylib (v1.9-dev)"); @@ -538,7 +537,7 @@ void InitRLWindow(int width, int height, void *data) #endif // Close window and unload OpenGL context -void CloseRLWindow(void) +void CloseWindow(void) { #if defined(SUPPORT_GIF_RECORDING) if (gifRecording) @@ -715,7 +714,7 @@ int GetScreenHeight(void) } // Show mouse cursor -void ShowRLCursor() +void ShowCursor() { #if defined(PLATFORM_DESKTOP) #if defined(__linux__) @@ -728,7 +727,7 @@ void ShowRLCursor() } // Hides mouse cursor -void HideRLCursor() +void HideCursor() { #if defined(PLATFORM_DESKTOP) #if defined(__linux__) @@ -1135,7 +1134,7 @@ void SetConfigFlags(char flags) // Takes a screenshot of current screen (saved a .png) void TakeScreenshot(const char *fileName) { -#if (defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)) && defined(SUPPORT_SAVE_PNG) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) unsigned char *imgData = rlReadScreenPixels(renderWidth, renderHeight); SavePNG(fileName, imgData, renderWidth, renderHeight, 4); // Save image as PNG free(imgData); @@ -2120,7 +2119,7 @@ static void InitTimer(void) } // Get current time measure (in seconds) since InitTimer() -double GetTime(void) +static double GetTime(void) { #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetTime(); diff --git a/src/raylib.h b/src/raylib.h index 16595b5b..a581929e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -682,8 +682,8 @@ extern "C" { // Prevents name mangling of functions //------------------------------------------------------------------------------------ // Window-related functions -RLAPI void InitRLWindow(int width, int height, void *data); // Initialize window and OpenGL context -RLAPI void CloseRLWindow(void); // Close window and unload OpenGL context +RLAPI void InitWindow(int width, int height, void *data); // Initialize window and OpenGL context +RLAPI void CloseWindow(void); // Close window and unload OpenGL context RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed RLAPI bool IsWindowMinimized(void); // Check if window has been minimized (or lost focus) RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (only PLATFORM_DESKTOP) @@ -696,8 +696,8 @@ RLAPI int GetScreenWidth(void); // Get current RLAPI int GetScreenHeight(void); // Get current screen height // Cursor-related functions -RLAPI void ShowRLCursor(void); // Shows cursor -RLAPI void HideRLCursor(void); // Hides cursor +RLAPI void ShowCursor(void); // Shows cursor +RLAPI void HideCursor(void); // Hides cursor RLAPI bool IsCursorHidden(void); // Check if cursor is not visible RLAPI void EnableCursor(void); // Enables cursor (unlock cursor) RLAPI void DisableCursor(void); // Disables cursor (lock cursor) @@ -722,9 +722,7 @@ RLAPI Matrix GetCameraMatrix(Camera camera); // Returns cam RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) RLAPI int GetFPS(void); // Returns current FPS RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn - -RLAPI double GetTime(void); // Return time in seconds - +//RLAPI double GetCurrentTime(void); // Return current time in seconds // Color-related functions RLAPI int GetHexValue(Color color); // Returns hexadecimal value for a Color @@ -1049,7 +1047,7 @@ RLAPI void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) -RLAPI Matrix GetMatrixModelview(); +RLAPI Matrix GetMatrixModelview(); // Get internal modelview matrix // Texture maps generation (PBR) // NOTE: Required shaders should be provided diff --git a/src/raymath.h b/src/raymath.h index 3d95a089..c29c6b95 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -227,13 +227,15 @@ RMDEF float Clamp(float value, float min, float max) //---------------------------------------------------------------------------------- // Vector with components value 0.0f -RMDEF Vector2 Vector2Zero(void) { +RMDEF Vector2 Vector2Zero(void) +{ Vector2 tmp = {0.0f, 0.0f}; return tmp; } // Vector with components value 1.0f -RMDEF Vector2 Vector2One(void) { +RMDEF Vector2 Vector2One(void) +{ Vector2 tmp = {1.0f, 1.0f}; return tmp; } @@ -312,13 +314,15 @@ RMDEF void Vector2Normalize(Vector2 *v) //---------------------------------------------------------------------------------- // Vector with components value 0.0f -RMDEF Vector3 Vector3Zero(void) { +RMDEF Vector3 Vector3Zero(void) +{ Vector3 tmp = { 0.0f, 0.0f, 0.0f }; return tmp; } // Vector with components value 1.0f -RMDEF Vector3 Vector3One(void) { +RMDEF Vector3 Vector3One(void) +{ Vector3 tmp = { 1.0f, 1.0f, 1.0f }; return tmp; } diff --git a/src/rlgl.c b/src/rlgl.c index 713646ac..96932686 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1293,6 +1293,12 @@ int rlGetVersion(void) #endif } +// Set debug marker +void rlSetDebugMarker(const char *text) +{ + if(debugMarkerSupported) glInsertEventMarkerEXT(0, text); // 0 terminated string +} + // Load OpenGL extensions // NOTE: External loader function could be passed as a pointer void rlLoadExtensions(void *loader) diff --git a/src/rlgl.h b/src/rlgl.h index 93afb44e..2437487d 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -422,6 +422,7 @@ void rlglClose(void); // De-inititialize rlgl (buffers void rlglDraw(void); // Update and Draw default buffers (lines, triangles, quads) int rlGetVersion(void); // Returns current OpenGL version +void rlDebugSetMarker(const char *text); // Set debug marker for analysis void rlLoadExtensions(void *loader); // Load OpenGL extensions Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates @@ -440,9 +441,6 @@ void rlUpdateMesh(Mesh mesh, int buffer, int numVertex); // Update ve void rlDrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform void rlUnloadMesh(Mesh *mesh); // Unload mesh data from CPU and GPU -// Debug Marker for Analysis -void rlSetMarker(const char *text); - // NOTE: There is a set of shader related functions that are available to end user, // to avoid creating function wrappers through core module, they have been directly declared in raylib.h @@ -462,9 +460,9 @@ int GetShaderLocation(Shader shader, const char *uniformName); // G void SetShaderValue(Shader shader, int uniformLoc, const float *value, int size); // Set shader uniform value (float) void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int size); // Set shader uniform value (int) void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) -void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) -void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) -Matrix GetMatrixModelview(); +void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) +void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) +Matrix GetMatrixModelview(); // Get internal modelview matrix // Texture maps generation (PBR) diff --git a/src/textures.c b/src/textures.c index 55749118..01b8e4fc 100644 --- a/src/textures.c +++ b/src/textures.c @@ -554,13 +554,12 @@ void UpdateTexture(Texture2D texture, const void *pixels) // Save image to a PNG file void SaveImageAs(const char* fileName, Image image) { -#if (defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)) && defined(SUPPORT_SAVE_PNG) - unsigned char* imgData = (unsigned char*)GetImageData(image); // this works since Color is just a container for the RGBA values + // NOTE: Getting Color array as RGBA unsigned char values + unsigned char* imgData = (unsigned char*)GetImageData(image); SavePNG(fileName, imgData, image.width, image.height, 4); free(imgData); TraceLog(LOG_INFO, "Image saved: %s", fileName); -#endif } // Convert image data to desired format From e17a9a82169935ea2d1eeb98425e608daf98b7f1 Mon Sep 17 00:00:00 2001 From: Ray San Date: Fri, 15 Dec 2017 17:01:50 +0100 Subject: [PATCH 088/139] Updated mini_al to latest version --- src/external/mini_al.h | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/external/mini_al.h b/src/external/mini_al.h index 36c394ad..906e3c59 100644 --- a/src/external/mini_al.h +++ b/src/external/mini_al.h @@ -1,5 +1,5 @@ // Audio playback and capture library. Public domain. See "unlicense" statement at the end of this file. -// mini_al - v0.x - 2017-xx-xx +// mini_al - v0.x - xxxx-xx-xx // // David Reid - davidreidsoftware@gmail.com @@ -1422,12 +1422,13 @@ mal_uint32 mal_src_read_frames(mal_src* pSRC, mal_uint32 frameCount, void* pFram // The same mal_src_read_frames() with extra control over whether or not the internal buffers should be flushed at the end. // // Internally there exists a buffer that keeps track of the previous and next samples for sample rate conversion. The simple -// version of this function does _not_ flush this buffer because otherwise it causes clitches for streaming based conversion +// version of this function does _not_ flush this buffer because otherwise it causes glitches for streaming based conversion // pipelines. The problem, however, is that sometimes you need those last few samples (such as if you're doing a bulk conversion // of a static file). Enabling flushing will fix this for you. mal_uint32 mal_src_read_frames_ex(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush); + /////////////////////////////////////////////////////////////////////////////// // // DSP @@ -1465,6 +1466,8 @@ mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 chann // Helper for initializing a mal_dsp_config object. mal_dsp_config mal_dsp_config_init(mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut); + + /////////////////////////////////////////////////////////////////////////////// // // Utiltities @@ -1635,7 +1638,14 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form #define MAL_HAS_OPENSL // Like OSS, OpenSL is the only supported backend for Android. It must be present. #endif #ifdef MAL_ENABLE_OPENAL - #define MAL_HAS_OPENAL // mini_al inlines the necessary OpenAL stuff. + #define MAL_HAS_OPENAL + #ifdef MAL_NO_RUNTIME_LINKING + #ifdef __has_include + #if !__has_include() + #undef MAL_HAS_OPENAL + #endif + #endif + #endif #endif #ifdef MAL_ENABLE_SDL #define MAL_HAS_SDL @@ -2745,13 +2755,11 @@ static mal_result mal_context__try_get_device_name_by_id(mal_context* pContext, } } break; #endif - #if 0 #ifdef MAL_HAS_COREAUDIO - case mal_backend_coreaudio: - { - // TODO: Implement me. - } break; - #endif + //case mal_backend_coreaudio: + //{ + // // TODO: Implement me. + //} break; #endif #ifdef MAL_HAS_OSS case mal_backend_oss: @@ -5488,8 +5496,8 @@ struct const char* name; float scale; } g_malDefaultBufferSizeScalesALSA[] = { - {"bcm2835 IEC958/HDMI", 32}, - {"bcm2835 ALSA", 32} + {"bcm2835 IEC958/HDMI", 20}, + {"bcm2835 ALSA", 20} }; static float mal_find_default_buffer_size_scale__alsa(const char* deviceName) @@ -11486,7 +11494,11 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) // REVISION HISTORY // ================ // -// v0.x - 2017-xx-xx +// v0.x - xxxx-xx-xx +// - Improvements to the build system for the OpenAL backend. +// - Documentation fixes. +// +// v0.6 - 2017-12-08 // - API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll // need to update. // - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively. @@ -11499,7 +11511,7 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) // - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of // audio data to a different format. // - Improvements to f32 -> u8/s16/s24/s32 conversion routines. -// - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL and SDL backends. +// - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL backend. // - Fixes and improvements for Raspberry Pi. // - Warning fixes. // From b155333178247d917e99e806cdcb27e9ab2d5c3c Mon Sep 17 00:00:00 2001 From: Ray San Date: Fri, 15 Dec 2017 17:02:29 +0100 Subject: [PATCH 089/139] Support audio module skip on compiling Some programs like tools could not require audio support --- src/Makefile | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Makefile b/src/Makefile index b9c21929..00f5fa2f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -47,6 +47,10 @@ API_VERSION = 1 PLATFORM ?= PLATFORM_DESKTOP RAYLIB_PATH = .. +# Included raylib audio module on compilation +# NOTE: Some programs like tools could not require audio support +INCLUDE_AUDIO_MODULE ?= YES + # Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) RAYLIB_LIBTYPE ?= STATIC @@ -317,15 +321,18 @@ OBJS = core.o \ textures.o \ text.o \ models.o \ - audio.o \ - mini_al.o \ - stb_vorbis.o \ utils.o ifeq ($(PLATFORM),PLATFORM_DESKTOP) OBJS += rglfw.o endif +ifeq ($(INCLUDE_AUDIO_MODULE),YES) + OBJS += audio.o + OBJS += mini_al.o + OBJS += stb_vorbis.o +endif + # Default target entry all: raylib From bc6ae93a4824d2592fb2146531a420f976606f4d Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 18 Dec 2017 00:06:57 +0100 Subject: [PATCH 090/139] Added some comments on GetTime() Reviewing GetTime() functionality --- src/core.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core.c b/src/core.c index ec7db978..8a2e40b3 100644 --- a/src/core.c +++ b/src/core.c @@ -263,12 +263,12 @@ static char gamepadName[64]; // Gamepad name holder #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) -static EGLDisplay display; // Native display device (physical screen connection) -static EGLSurface surface; // Surface to draw on, framebuffers (connected to context) -static EGLContext context; // Graphic context, mode in which drawing can be done -static EGLConfig config; // Graphic config -static uint64_t baseTime; // Base time measure for hi-res timer -static bool windowShouldClose = false; // Flag to set window for closing +static EGLDisplay display; // Native display device (physical screen connection) +static EGLSurface surface; // Surface to draw on, framebuffers (connected to context) +static EGLContext context; // Graphic context, mode in which drawing can be done +static EGLConfig config; // Graphic config +static uint64_t baseTime; // Base time measure for hi-res timer +static bool windowShouldClose = false; // Flag to set window for closing #endif // Display size-related data @@ -2118,11 +2118,11 @@ static void InitTimer(void) previousTime = GetTime(); // Get time as double } -// Get current time measure (in seconds) since InitTimer() +// Get elapsed time measure (in seconds) static double GetTime(void) { #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - return glfwGetTime(); + return glfwGetTime(); // Elapsed time since glfwInit() #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) @@ -2130,7 +2130,7 @@ static double GetTime(void) clock_gettime(CLOCK_MONOTONIC, &ts); uint64_t time = (uint64_t)ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec; - return (double)(time - baseTime)*1e-9; + return (double)(time - baseTime)*1e-9; // Elapsed time since InitTimer() #endif } From bd4aa2459f007aee27b087740a9609574bd8e706 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 18 Dec 2017 12:06:58 +0100 Subject: [PATCH 091/139] Create CONTRIBUTING.md --- CONTRIBUTING.md | 143 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..dddb38ed --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,143 @@ +## Contributing to raylib + +Hello contributors! Welcome to raylib! + +This document contains a set of guidelines to contribute to the project. These are mostly guidelines, not rules. +Use your best judgement, and feel free to propose changes to this document in a pull-request. + +### raylib philosophy + + - raylib is a tool to LEARN videogames programming, every single function in raylib should be a tutorial on itself. + - raylib is SIMPLE and EASY-TO-USE, I tried to keep it compact with a small set of functions, if a function is too complex or has not a clear usefulness, better not to include it. + - raylib is open source and free; educators and institutions can use this tool to TEACH videogames programming completely by free. + - raylib is collaborative; contribution of tutorials / code-examples / bugs-solving / code-comments are highly appreciated. + - raylib's license (and its external libs respective licenses) allow using it for commercial products. + +### Some interesting reads to start with + + - [raylib history](HISTORY.md) + - [raylib architecture](https://github.com/raysan5/raylib/wiki/raylib-architecture) + - [raylib license](LICENSE.md) + - [raylib roadmap](ROADMAP.md) + +[raylib Wiki](https://github.com/raysan5/raylib/wiki) contains some information about the library and is open to anyone for edit. +Feel free to review it if required, just take care not to break anything. + +### Using raylib develop branch + +raylib [master branch](https://github.com/raysan5/raylib) contains latest raylib release but all +the future work is always done on [develop branch](https://github.com/raysan5/raylib/tree/develop), +it's far ahead of master and I try to keep it always stable with latest library changes. + +Please, if issuing a bug or sending a pull-request, verify that you're using develop branch. + +Note that while using develop branch predefined Notepad++ building scripts could not work, in that case, +use provided [Makefile](https://github.com/raysan5/raylib/blob/develop/src/Makefile) or [CMake](https://github.com/raysan5/raylib/blob/develop/src/CMakeLists.txt) building systems. + +For detailed information on building raylib and examples, please check [raylib Wiki](https://github.com/raysan5/raylib/wiki). + +### raylib C coding conventions + +Despite being written in C, raylib does not follow the standard hungarian notation for C, +it [follows Pascal-case/camel-case notation](https://github.com/raysan5/raylib/wiki/raylib-coding-conventions), +more common on C# language. All code formatting decisions have been carefully taken +to make it easier for students to read, write and understand code. + +Source code is extensively commented for that pourpose, raylib primary learning method is: + + > learn by reading code and examples + + +### Opening new Issues + +To open new issue for raylib (bug, enhacement, discussion...), just try to follow this rules: + + - Make sure the issue has not already been reported before by searching on GitHub under Issues. + - If you're unable to find an open issue addressing the problem, open a new one. Be sure to include a + title and clear description, as much relevant information as possible, and a code sample demonstrating the unexpected behavior. + - If applies, attach some screenshot of the issue and a .zip file with the code sample and required resources. + - On issue description, add a brackets tag about the raylib module that relates to this issue. + If don't know the module, just report the issue, I will review it. + - You can check other issues to see how is being done! + +### Sending a Pull-Request + +To send a pull-request, first of all, make sure you're sending it to **develop-branch**. Here are some other rules: + + - Make sure thee PR description clearly describes the problem and solution. Include the relevant issue number if applicable. + - Don't send big pull-requests (lots of changelists), they are difficult to review. It's better to send small pull-request, one at a time. + - Verify that changes don't break the build (at least on Windows platform). As many platforms where you can test it, the better, but don't worry + if you can not test all the platforms. + +### raylib bindings + +Some people ported raylib to other languages in form of bindings or wrappers to the library, here it is a list with the ones I'm aware: + + - [raylib C/C++ version (default)](https://github.com/raysan5/raylib) + - [raylib Lua binding](https://github.com/raysan5/raylib-lua) + - [raylib Go binding](https://github.com/gen2brain/raylib-go) + - [raylib Nim binding](https://gitlab.com/define-private-public/raylib-Nim) + - [raylib Crystal binding](https://gitlab.com/Zatherz/cray) + - [raylib Perl wrapper](https://metacpan.org/pod/Graphics::Raylib) + - [raylib Perl frontend](https://github.com/athreef/Alien-raylib) + - raylib Pascal binding with custom IDE (closed-source) + +Usually, raylib bindings follow the convention: `raylib-{language}` + +Let me know if you're writting a new binding for raylib, I will list it here and I usually +provide the icon/logo for that new language binding. + +### contact information + +If you have any doubt, don't hessitate to [contact me](mailto:ray@raylib.com)!. +You can write me a direct mail but you can also contact me on the following networks: + + - [raylib forum](http://forum.raylib.com/) - A good place for discussions or to ask for help. + - [raylib gitter](https://gitter.im/raylib) - A direct communication channel for project discussions. + - [raylib twitter](https://twitter.com/raysan5) - My personal twitter account, I usually post about raylib, you can send me PMs. + - [raylib web](http://www.raylib.com/) - On top-right corner there is a bunch of networks where you can find me. + +Thank you very much for your time! :) + +---- + +Here it is a list of raylib contributors, this people has invested part of their time +contributing (in some way or another) to make raylib project better. Huge thanks to all of them! + + - [Zopokx](https://github.com/Zopokx) for testing the web. + - [Elendow](http://www.elendow.com) for testing and helping on web development. + - Victor Dual for implementing and testing 3D shapes functions. + - Marc Palau for implementing and testing 3D shapes functions and contribute on camera and gestures modules. + - Kevin Gato for improving texture internal formats support and helping on raygui development. + - Daniel Nicolas for improving texture internal formats support and helping on raygui development. + - Marc Agüera for testing and using raylib on a real product ([Koala Seasons](http://www.koalaseasons.com)) + - Daniel Moreno for testing and using raylib on a real product ([Koala Seasons](http://www.koalaseasons.com)) + - Daniel Gomez for testing and using raylib on a real product ([Koala Seasons](http://www.koalaseasons.com)) + - [Sergio Martinez](https://github.com/anidealgift) for helping on raygui development and tools development (raygui_styler). + - [Victor Fisac](https://github.com/victorfisac) for developing physics raylib module (physac) and implementing PBR materials and lighting systems... among multiple other improvements and multiple tools and games. + - Albert Martos for helping on raygui and porting examples and game-templates to Android and HTML5. + - Ian Eito for helping on raygui and porting examples and game-templates to Android and HTML5. + - [procedural](https://github.com/procedural) for testing raylib on Linux, correcting some bugs and adding several mouse functions. + - [Chris Hemingway](https://github.com/cHemingway) for improving raylib on OSX build system. + - [Emanuele Petriglia](https://github.com/LelixSuper) for working on multiple GNU/Linux improvements and developing [TicTacToe](https://github.com/LelixSuper/TicTacToe) raylib game. + - [Joshua Reisenauer](https://github.com/kd7tck) for adding audio modules support (XM, MOD) and reviewing audio system. + - [Marcelo Paez](https://github.com/paezao) for his help on OSX to solve High DPI display issue. Thanks Marcelo! + - [Ghassan Al-Mashareqa](https://github.com/ghassanpl) for his amazing contribution with raylib Lua module, I just work over his code to implement [rlua](https://github.com/raysan5/raylib/blob/master/src/rlua.h) + - [Teodor Stoenescu](https://github.com/teodor-stoenescu) for his improvements on OBJ object loading. + - [RDR8](https://github.com/RDR8) for helping with Linux build improvements + - [Saggi Mizrahi](https://github.com/ficoos) for multiple fixes on Linux and audio system + - [Daniel Lemos](https://github.com/xspager) for fixing issues on Linux games building + - [Joel Davis](https://github.com/joeld42) for adding raycast picking utilities and a [great example](https://github.com/raysan5/raylib/blob/master/examples/models/models_mesh_picking.c) + - [Richard Goodwin](https://github.com/AudioMorphology) for adding RPI touchscreen support + - [Milan Nikolic](https://github.com/gen2brain) for adding Android build support with custom standalone toolchain + - [Michael Vetter](https://github.com/jubalh) for improvements on build system and adding meson support for Linux + - [Wilhem Barbier](https://github.com/nounoursheureux) for adding Image generation functions and some fixes + - [Benjamin Summerton](https://github.com/define-private-public) for improving OSX building and his amazing work on CMake build sytem + - [MartinFX](https://github.com/Martinfx) for adding compilation support for FreeBSD OS + - [Wilhem Barbier](https://github.com/nounoursheureux) for supporting default shaders on shader loading, if shader not provided + - [Ahmad Fatoum](https://github.com/a3f) for implementing continuus integration support for raylib (Travis and AppVeyor) and greatly improving build system. + - [SamNChiet](https://github.com/SamNChiet) for his work on UWP inputs implementation. + - [David Reid](https://github.com/mackron) for a complete review of audio module to support his amazing mini_al audio library. + - [Kai](https://github.com/questor) for multiple code reviews and improvements. + +Please, if I forget someone in this list, excuse me and write me an email to remind me to add you! From f3f3e7cf6dfc1fac380a2c4adb65e2dd0a563afb Mon Sep 17 00:00:00 2001 From: Ray San Date: Mon, 18 Dec 2017 12:23:29 +0100 Subject: [PATCH 092/139] Removed contributors file Contributors added to contributing file --- CONTRIBUTORS.md | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 CONTRIBUTORS.md diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md deleted file mode 100644 index a31f0e1f..00000000 --- a/CONTRIBUTORS.md +++ /dev/null @@ -1,35 +0,0 @@ - -I believe that time is the most valuable resource and the following people have invested part of their time -contributing (in some way or another) to make raylib project better. Huge thanks! - - - [Zopokx](https://github.com/Zopokx) for testing the web. - - [Elendow](http://www.elendow.com) for testing and helping on web development. - - Victor Dual for implementing and testing 3D shapes functions. - - Marc Palau for implementing and testing 3D shapes functions and contribute on camera and gestures modules. - - Kevin Gato for improving texture internal formats support and helping on raygui development. - - Daniel Nicolas for improving texture internal formats support and helping on raygui development. - - Marc Agüera for testing and using raylib on a real product ([Koala Seasons](http://www.koalaseasons.com)) - - Daniel Moreno for testing and using raylib on a real product ([Koala Seasons](http://www.koalaseasons.com)) - - Daniel Gomez for testing and using raylib on a real product ([Koala Seasons](http://www.koalaseasons.com)) - - [Sergio Martinez](https://github.com/anidealgift) for helping on raygui development and tools development (raygui_styler). - - [Victor Fisac](https://github.com/victorfisac) for developing physics raylib module (physac) and implementing PBR materials and lighting systems... among multiple other improvements and multiple tools and games. - - Albert Martos for helping on raygui and porting examples and game-templates to Android and HTML5. - - Ian Eito for helping on raygui and porting examples and game-templates to Android and HTML5. - - [procedural](https://github.com/procedural) for testing raylib on Linux, correcting some bugs and adding several mouse functions. - - [Chris Hemingway](https://github.com/cHemingway) for improving raylib on OSX build system. - - [Emanuele Petriglia](https://github.com/LelixSuper) for working on multiple GNU/Linux improvements and developing [TicTacToe](https://github.com/LelixSuper/TicTacToe) raylib game. - - [Joshua Reisenauer](https://github.com/kd7tck) for adding audio modules support (XM, MOD) and reviewing audio system. - - [Marcelo Paez](https://github.com/paezao) for his help on OSX to solve High DPI display issue. Thanks Marcelo! - - [Ghassan Al-Mashareqa](https://github.com/ghassanpl) for his amazing contribution with raylib Lua module, I just work over his code to implement [rlua](https://github.com/raysan5/raylib/blob/master/src/rlua.h) - - [Teodor Stoenescu](https://github.com/teodor-stoenescu) for his improvements on OBJ object loading. - - [RDR8](https://github.com/RDR8) for helping with Linux build improvements - - [Saggi Mizrahi](https://github.com/ficoos) for multiple fixes on Linux and audio system - - [Daniel Lemos](https://github.com/xspager) for fixing issues on Linux games building - - [Joel Davis](https://github.com/joeld42) for adding raycast picking utilities and a [great example](https://github.com/raysan5/raylib/blob/master/examples/models/models_mesh_picking.c) - - [Richard Goodwin](https://github.com/AudioMorphology) for adding RPI touchscreen support - - [Milan Nikolic](https://github.com/gen2brain) for adding Android build support with custom standalone toolchain - - [Michael Vetter](https://github.com/jubalh) for improvements on build system and adding meson support for Linux - - [Wilhem Barbier](https://github.com/nounoursheureux) for adding Image generation functions and some fixes - - [Benjamin Summerton](https://github.com/define-private-public) for improving OSX building and his amazing work on CMake build sytem - -Please, if I forget someone in this list, excuse me and write me an email to remind me to add you! From 647d8b2d53e995224e48daccc4a28b9dcd2c5155 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 18 Dec 2017 15:35:10 +0100 Subject: [PATCH 093/139] Remove Alien::raylib from bindings list * `Alien::raylib` downloads raylib, builds it and installs it in the Perl module path (Basically abusing CPAN as package manager) * `Graphics::Raylib::XS` depends on `Alien::raylib` and reexports all C symbols as XS symbols usable in Perl * `Graphics::Raylib` depends on `Graphics::Raylib::XS` and is the actual Perl wrapper with a Perlish API, which users should be using --- CONTRIBUTING.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dddb38ed..5cb11a83 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,7 +79,6 @@ Some people ported raylib to other languages in form of bindings or wrappers to - [raylib Nim binding](https://gitlab.com/define-private-public/raylib-Nim) - [raylib Crystal binding](https://gitlab.com/Zatherz/cray) - [raylib Perl wrapper](https://metacpan.org/pod/Graphics::Raylib) - - [raylib Perl frontend](https://github.com/athreef/Alien-raylib) - raylib Pascal binding with custom IDE (closed-source) Usually, raylib bindings follow the convention: `raylib-{language}` From 8d5484bbe0bc589ba92f8859d8878728151aeb86 Mon Sep 17 00:00:00 2001 From: RDR8 Date: Tue, 19 Dec 2017 02:19:43 -0600 Subject: [PATCH 094/139] Fix some typos in CONTRIBUTING.md (#422) --- CONTRIBUTING.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5cb11a83..8dbc1ced 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ Use your best judgement, and feel free to propose changes to this document in a ### raylib philosophy - raylib is a tool to LEARN videogames programming, every single function in raylib should be a tutorial on itself. - - raylib is SIMPLE and EASY-TO-USE, I tried to keep it compact with a small set of functions, if a function is too complex or has not a clear usefulness, better not to include it. + - raylib is SIMPLE and EASY-TO-USE, I tried to keep it compact with a small set of functions, if a function is too complex or is not clearly useful, better not to include it. - raylib is open source and free; educators and institutions can use this tool to TEACH videogames programming completely by free. - raylib is collaborative; contribution of tutorials / code-examples / bugs-solving / code-comments are highly appreciated. - raylib's license (and its external libs respective licenses) allow using it for commercial products. @@ -23,6 +23,18 @@ Use your best judgement, and feel free to propose changes to this document in a [raylib Wiki](https://github.com/raysan5/raylib/wiki) contains some information about the library and is open to anyone for edit. Feel free to review it if required, just take care not to break anything. +### raylib C coding conventions + +Despite being written in C, raylib does not follow the standard Hungarian notation for C, +it [follows Pascal-case/camel-case notation](https://github.com/raysan5/raylib/wiki/raylib-coding-conventions), +more common on C# language. All code formatting decisions have been carefully taken +to make it easier for students to read, write and understand code. + +Source code is extensively commented for that purpose, raylib primary learning method is: + + > learn by reading code and examples + + ### Using raylib develop branch raylib [master branch](https://github.com/raysan5/raylib) contains latest raylib release but all @@ -36,21 +48,9 @@ use provided [Makefile](https://github.com/raysan5/raylib/blob/develop/src/Makef For detailed information on building raylib and examples, please check [raylib Wiki](https://github.com/raysan5/raylib/wiki). -### raylib C coding conventions - -Despite being written in C, raylib does not follow the standard hungarian notation for C, -it [follows Pascal-case/camel-case notation](https://github.com/raysan5/raylib/wiki/raylib-coding-conventions), -more common on C# language. All code formatting decisions have been carefully taken -to make it easier for students to read, write and understand code. - -Source code is extensively commented for that pourpose, raylib primary learning method is: - - > learn by reading code and examples - - ### Opening new Issues -To open new issue for raylib (bug, enhacement, discussion...), just try to follow this rules: +To open new issue for raylib (bug, enhacement, discussion...), just try to follow these rules: - Make sure the issue has not already been reported before by searching on GitHub under Issues. - If you're unable to find an open issue addressing the problem, open a new one. Be sure to include a @@ -62,16 +62,16 @@ To open new issue for raylib (bug, enhacement, discussion...), just try to follo ### Sending a Pull-Request -To send a pull-request, first of all, make sure you're sending it to **develop-branch**. Here are some other rules: +To send a pull-request, first of all, make sure you're sending it to [develop branch](https://github.com/raysan5/raylib/tree/develop). Here are some other rules: - - Make sure thee PR description clearly describes the problem and solution. Include the relevant issue number if applicable. + - Make sure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. - Don't send big pull-requests (lots of changelists), they are difficult to review. It's better to send small pull-request, one at a time. - Verify that changes don't break the build (at least on Windows platform). As many platforms where you can test it, the better, but don't worry - if you can not test all the platforms. + if you cannot test all the platforms. ### raylib bindings -Some people ported raylib to other languages in form of bindings or wrappers to the library, here it is a list with the ones I'm aware: +Some people ported raylib to other languages in form of bindings or wrappers to the library, here is a list with the ones I'm aware of: - [raylib C/C++ version (default)](https://github.com/raysan5/raylib) - [raylib Lua binding](https://github.com/raysan5/raylib-lua) @@ -83,12 +83,12 @@ Some people ported raylib to other languages in form of bindings or wrappers to Usually, raylib bindings follow the convention: `raylib-{language}` -Let me know if you're writting a new binding for raylib, I will list it here and I usually +Let me know if you're writing a new binding for raylib, I will list it here and I usually provide the icon/logo for that new language binding. -### contact information +### Contact information -If you have any doubt, don't hessitate to [contact me](mailto:ray@raylib.com)!. +If you have any doubt, don't hesitate to [contact me](mailto:ray@raylib.com)!. You can write me a direct mail but you can also contact me on the following networks: - [raylib forum](http://forum.raylib.com/) - A good place for discussions or to ask for help. @@ -100,8 +100,8 @@ Thank you very much for your time! :) ---- -Here it is a list of raylib contributors, this people has invested part of their time -contributing (in some way or another) to make raylib project better. Huge thanks to all of them! +Here is a list of raylib contributors, these people have invested part of their time +contributing (in some way or another) to make the raylib project better. Huge thanks to all of them! - [Zopokx](https://github.com/Zopokx) for testing the web. - [Elendow](http://www.elendow.com) for testing and helping on web development. From 22e72cb0a1795c642505ad86106e26effbe18310 Mon Sep 17 00:00:00 2001 From: RDR8 Date: Tue, 19 Dec 2017 02:27:12 -0600 Subject: [PATCH 095/139] Update CONTRIBUTING.md --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8dbc1ced..26f15156 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,7 +37,7 @@ Source code is extensively commented for that purpose, raylib primary learning m ### Using raylib develop branch -raylib [master branch](https://github.com/raysan5/raylib) contains latest raylib release but all +raylib [master branch](https://github.com/raysan5/raylib) contains the latest raylib release but all the future work is always done on [develop branch](https://github.com/raysan5/raylib/tree/develop), it's far ahead of master and I try to keep it always stable with latest library changes. @@ -50,7 +50,7 @@ For detailed information on building raylib and examples, please check [raylib W ### Opening new Issues -To open new issue for raylib (bug, enhacement, discussion...), just try to follow these rules: +To open new issue for raylib (bug, enhancement, discussion...), just try to follow these rules: - Make sure the issue has not already been reported before by searching on GitHub under Issues. - If you're unable to find an open issue addressing the problem, open a new one. Be sure to include a From 5290390494c23055c689c183aea6d88039b0d5fb Mon Sep 17 00:00:00 2001 From: Ray San Date: Tue, 19 Dec 2017 14:06:54 +0100 Subject: [PATCH 096/139] Expose GetTime() function to users Monotonic time since InitWindow() could be retrieved with this function. --- src/core.c | 57 +++++++++++++++++++++++++------------------------- src/gestures.h | 6 +++--- src/raylib.h | 2 +- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/src/core.c b/src/core.c index 8a2e40b3..6468539f 100644 --- a/src/core.c +++ b/src/core.c @@ -150,11 +150,11 @@ #include // which are required for hiding mouse #endif //#include // OpenGL functions (GLFW3 already includes gl.h) - //#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version! - + #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) - __stdcall unsigned int timeBeginPeriod(unsigned int uPeriod); - __stdcall unsigned int timeEndPeriod(unsigned int uPeriod); + // NOTE: Those functions require linking with winmm library + unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod); + unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #endif #endif @@ -351,7 +351,6 @@ extern void UnloadDefaultFont(void); // [Module: text] Unloads default fo static void InitGraphicsDevice(int width, int height); // Initialize graphics device static void SetupFramebufferSize(int displayWidth, int displayHeight); static void InitTimer(void); // Initialize timer -static double GetTime(void); // Returns time since InitTimer() was run static void Wait(float ms); // Wait for some milliseconds (stop program execution) static bool GetKeyStatus(int key); // Returns if a key has been pressed static bool GetMouseButtonStatus(int button); // Returns if a mouse button has been pressed @@ -421,6 +420,9 @@ void InitWindow(int width, int height, void *data) // Init graphics device (display device and OpenGL context) InitGraphicsDevice(width, height); + + // Init hi-res timer + InitTimer(); #if defined(SUPPORT_DEFAULT_FONT) // Load default font @@ -428,9 +430,6 @@ void InitWindow(int width, int height, void *data) LoadDefaultFont(); #endif - // Init hi-res timer - InitTimer(); - #if defined(PLATFORM_RPI) // Init raw input system InitMouse(); // Mouse init @@ -786,7 +785,7 @@ void ClearBackground(Color color) // Setup canvas (framebuffer) to start drawing void BeginDrawing(void) { - currentTime = GetTime(); // Number of elapsed seconds since InitTimer() was called + currentTime = GetTime(); // Number of elapsed seconds since InitTimer() updateTime = currentTime - previousTime; previousTime = currentTime; @@ -1060,6 +1059,24 @@ float GetFrameTime(void) return (float)frameTime; } +// Get elapsed time measure in seconds since InitTimer() +// NOTE: On PLATFORM_DESKTOP InitTimer() is called on InitWindow() +// NOTE: On PLATFORM_DESKTOP, timer is initialized on glfwInit() +double GetTime(void) +{ +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + return glfwGetTime(); // Elapsed time since glfwInit() +#endif + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + uint64_t time = (uint64_t)ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec; + + return (double)(time - baseTime)*1e-9; // Elapsed time since InitTimer() +#endif +} + // Converts Color to float array and normalizes float *ColorToFloat(Color color) { @@ -2118,22 +2135,6 @@ static void InitTimer(void) previousTime = GetTime(); // Get time as double } -// Get elapsed time measure (in seconds) -static double GetTime(void) -{ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - return glfwGetTime(); // Elapsed time since glfwInit() -#endif - -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - uint64_t time = (uint64_t)ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec; - - return (double)(time - baseTime)*1e-9; // Elapsed time since InitTimer() -#endif -} - // Wait for some milliseconds (stop program execution) // NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could // take longer than expected... for that reason we use the busy wait loop @@ -2602,6 +2603,9 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) { // Init graphics device (display device and OpenGL context) InitGraphicsDevice(screenWidth, screenHeight); + + // Init hi-res timer + InitTimer(); #if defined(SUPPORT_DEFAULT_FONT) // Load default font @@ -2624,9 +2628,6 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) } */ - // Init hi-res timer - InitTimer(); - // raylib logo appearing animation (if enabled) if (showLogo) { diff --git a/src/gestures.h b/src/gestures.h index 68bdc11b..58670ef5 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -522,7 +522,7 @@ static double GetCurrentTime(void) #if defined(_WIN32) unsigned long long int clockFrequency, currentTime; - QueryPerformanceFrequency(&clockFrequency); + QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation! QueryPerformanceCounter(¤tTime); time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds @@ -538,8 +538,8 @@ static double GetCurrentTime(void) #endif #if defined(__APPLE__) - //#define CLOCK_REALTIME CALENDAR_CLOCK - //#define CLOCK_MONOTONIC SYSTEM_CLOCK + //#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01 + //#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time clock_serv_t cclock; mach_timespec_t now; diff --git a/src/raylib.h b/src/raylib.h index a581929e..4100cee1 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -722,7 +722,7 @@ RLAPI Matrix GetCameraMatrix(Camera camera); // Returns cam RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) RLAPI int GetFPS(void); // Returns current FPS RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn -//RLAPI double GetCurrentTime(void); // Return current time in seconds +RLAPI double GetTime(void); // Returns elapsed time in seconds since InitWindow() // Color-related functions RLAPI int GetHexValue(Color color); // Returns hexadecimal value for a Color From b63ffcfa0f7dcedac190a49ec48fd71d7fe2faf1 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 20 Dec 2017 00:34:31 +0100 Subject: [PATCH 097/139] Some code tweaks Audio module requires a complete formatting review.... --- src/audio.c | 31 +++++++++++++++++-------------- src/audio.h | 25 ++++++++++++++++--------- src/raylib.h | 32 ++++++++++---------------------- 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/src/audio.c b/src/audio.c index 15f50a24..7a8e185b 100644 --- a/src/audio.c +++ b/src/audio.c @@ -153,7 +153,12 @@ // Types and Structures Definition //---------------------------------------------------------------------------------- -typedef enum { MUSIC_AUDIO_OGG = 0, MUSIC_AUDIO_FLAC, MUSIC_MODULE_XM, MUSIC_MODULE_MOD } MusicContextType; +typedef enum { + MUSIC_AUDIO_OGG = 0, + MUSIC_AUDIO_FLAC, + MUSIC_MODULE_XM, + MUSIC_MODULE_MOD +} MusicContextType; // Music type (file streaming from memory) typedef struct MusicData { @@ -179,7 +184,13 @@ typedef struct MusicData { } MusicData; #if defined(AUDIO_STANDALONE) -typedef enum { LOG_INFO = 0, LOG_ERROR, LOG_WARNING, LOG_DEBUG, LOG_OTHER } TraceLogType; +typedef enum { + LOG_INFO = 0, + LOG_ERROR, + LOG_WARNING, + LOG_DEBUG, + LOG_OTHER +} TraceLogType; #endif //---------------------------------------------------------------------------------- @@ -215,9 +226,8 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioBufferUsage; -typedef struct AudioBuffer AudioBuffer; -struct AudioBuffer -{ +// Audio buffer structure +typedef struct AudioBuffer { mal_dsp dsp; // For format conversion. float volume; float pitch; @@ -231,10 +241,9 @@ struct AudioBuffer AudioBuffer* next; AudioBuffer* prev; unsigned char buffer[1]; -}; - -void StopAudioBuffer(AudioBuffer* audioBuffer); +} AudioBuffer; +void StopAudioBuffer(AudioBuffer *audioBuffer); static mal_context context; static mal_device device; @@ -400,12 +409,6 @@ void InitAudioDevice(void) // Device. Using the default device. Format is floating point because it simplifies mixing. mal_device_config deviceConfig = mal_device_config_init(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, OnSendAudioDataToDevice); - // Special case for PLATFORM_RPI. -//#if defined(PLATFORM_RPI) -// deviceConfig.alsa.noMMap = MAL_TRUE; -// deviceConfig.bufferSizeInFrames = 2048; -//#endif - result = mal_device_init(&context, mal_device_type_playback, NULL, &deviceConfig, NULL, &device); if (result != MAL_SUCCESS) { diff --git a/src/audio.h b/src/audio.h index 48ef7403..4c9faf25 100644 --- a/src/audio.h +++ b/src/audio.h @@ -81,9 +81,11 @@ typedef struct Wave { // Sound source type typedef struct Sound { - unsigned int source; // OpenAL audio source id - unsigned int buffer; // OpenAL audio buffer id - int format; // OpenAL audio format specifier + void *audioBuffer; // Pointer to internal data used by the audio system + + unsigned int source; // Audio source id + unsigned int buffer; // Audio buffer id + int format; // Audio format specifier } Sound; // Music type (file streaming from memory) @@ -97,9 +99,11 @@ typedef struct AudioStream { 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) + void *audioBuffer; // Pointer to internal data used by the audio system. + + int format; // Audio format specifier + unsigned int source; // Audio source id + unsigned int buffers[2]; // Audio buffers (double buffering) } AudioStream; #ifdef __cplusplus @@ -147,12 +151,12 @@ void ResumeMusicStream(Music music); // Resume playin bool IsMusicPlaying(Music music); // Check if music is playing void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) -void SetMusicLoopCount(Music music, float count); // Set music loop count (loop repeats) +void SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats) float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) -// Raw audio stream functions -AudioStream InitAudioStream(unsigned int sampleRate, +// AudioStream management functions +AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data) void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data @@ -161,7 +165,10 @@ bool IsAudioBufferProcessed(AudioStream stream); // Check if any void PlayAudioStream(AudioStream stream); // Play audio stream void PauseAudioStream(AudioStream stream); // Pause audio stream void ResumeAudioStream(AudioStream stream); // Resume audio stream +bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing void StopAudioStream(AudioStream stream); // Stop audio stream +void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) +void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) #ifdef __cplusplus } diff --git a/src/raylib.h b/src/raylib.h index 4100cee1..b0ff1fc1 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -470,11 +470,11 @@ typedef struct Wave { // Sound source type typedef struct Sound { - void* audioBuffer; // A pointer to internal data used by the audio system. + void *audioBuffer; // Pointer to internal data used by the audio system - unsigned int source; // OpenAL audio source id - unsigned int buffer; // OpenAL audio buffer id - int format; // OpenAL audio format specifier + unsigned int source; // Audio source id + unsigned int buffer; // Audio buffer id + int format; // Audio format specifier } Sound; // Music type (file streaming from memory) @@ -488,11 +488,11 @@ typedef struct AudioStream { unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) unsigned int channels; // Number of channels (1-mono, 2-stereo) - void* audioBuffer; // A pointer to internal data used by the audio system. + void *audioBuffer; // Pointer to internal data used by the audio system. - int format; // OpenAL audio format specifier - unsigned int source; // OpenAL audio source id - unsigned int buffers[2]; // OpenAL audio buffers (double buffering) + int format; // Audio format specifier + unsigned int source; // Audio source id + unsigned int buffers[2]; // Audio buffers (double buffering) } AudioStream; // Head-Mounted-Display device parameters @@ -656,18 +656,6 @@ typedef enum { HMD_SONY_PSVR } VrDeviceType; -// RRESData type -typedef enum { - RRES_TYPE_RAW = 0, - RRES_TYPE_IMAGE, - RRES_TYPE_WAVE, - RRES_TYPE_VERTEX, - RRES_TYPE_TEXT, - RRES_TYPE_FONT_IMAGE, - RRES_TYPE_FONT_CHARDATA, // CharInfo data array - RRES_TYPE_DIRECTORY -} RRESDataType; - #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -1131,8 +1119,8 @@ RLAPI void PauseAudioStream(AudioStream stream); // Pause a RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream -RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) -RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) +RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) +RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) #ifdef __cplusplus } From 1320044e94126a527e8ebe0b3833cce487566925 Mon Sep 17 00:00:00 2001 From: Ray San Date: Wed, 20 Dec 2017 11:37:43 +0100 Subject: [PATCH 098/139] Review code formatting --- src/audio.c | 280 +++++++++++++++++++++++++--------------------------- 1 file changed, 135 insertions(+), 145 deletions(-) diff --git a/src/audio.c b/src/audio.c index 7a8e185b..4855333f 100644 --- a/src/audio.c +++ b/src/audio.c @@ -227,7 +227,8 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioBufferUsage; // Audio buffer structure -typedef struct AudioBuffer { +typedef struct AudioBuffer AudioBuffer; +struct AudioBuffer { mal_dsp dsp; // For format conversion. float volume; float pitch; @@ -238,10 +239,10 @@ typedef struct AudioBuffer { bool isSubBufferProcessed[2]; unsigned int frameCursorPos; unsigned int bufferSizeInFrames; - AudioBuffer* next; - AudioBuffer* prev; + AudioBuffer *next; + AudioBuffer *prev; unsigned char buffer[1]; -} AudioBuffer; +}; void StopAudioBuffer(AudioBuffer *audioBuffer); @@ -250,48 +251,46 @@ static mal_device device; static mal_bool32 isAudioInitialized = MAL_FALSE; static float masterVolume = 1; static mal_mutex audioLock; -static AudioBuffer* firstAudioBuffer = NULL; // Audio buffers are tracked in a linked list. -static AudioBuffer* lastAudioBuffer = NULL; +static AudioBuffer *firstAudioBuffer = NULL; // Audio buffers are tracked in a linked list. +static AudioBuffer *lastAudioBuffer = NULL; static void TrackAudioBuffer(AudioBuffer* audioBuffer) { mal_mutex_lock(&audioLock); + { - if (firstAudioBuffer == NULL) { - firstAudioBuffer = audioBuffer; - } else { + if (firstAudioBuffer == NULL) firstAudioBuffer = audioBuffer; + else + { lastAudioBuffer->next = audioBuffer; audioBuffer->prev = lastAudioBuffer; } lastAudioBuffer = audioBuffer; } + mal_mutex_unlock(&audioLock); } static void UntrackAudioBuffer(AudioBuffer* audioBuffer) { mal_mutex_lock(&audioLock); + { - if (audioBuffer->prev == NULL) { - firstAudioBuffer = audioBuffer->next; - } else { - audioBuffer->prev->next = audioBuffer->next; - } + if (audioBuffer->prev == NULL) firstAudioBuffer = audioBuffer->next; + else audioBuffer->prev->next = audioBuffer->next; - if (audioBuffer->next == NULL) { - lastAudioBuffer = audioBuffer->prev; - } else { - audioBuffer->next->prev = audioBuffer->prev; - } + if (audioBuffer->next == NULL) lastAudioBuffer = audioBuffer->prev; + else audioBuffer->next->prev = audioBuffer->prev; audioBuffer->prev = NULL; audioBuffer->next = NULL; } + mal_mutex_unlock(&audioLock); } -static void OnLog_MAL(mal_context* pContext, mal_device* pDevice, const char* message) +static void OnLog_MAL(mal_context *pContext, mal_device *pDevice, const char *message) { (void)pContext; (void)pDevice; @@ -303,17 +302,19 @@ static void OnLog_MAL(mal_context* pContext, mal_device* pDevice, const char* me // framesOut is both an input and an output. It will be initially filled with zeros outside of this function. static void MixFrames(float* framesOut, const float* framesIn, mal_uint32 frameCount, float localVolume) { - for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { - for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel) { - float* frameOut = framesOut + (iFrame * device.channels); - const float* frameIn = framesIn + (iFrame * device.channels); + for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) + { + for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel) + { + float *frameOut = framesOut + (iFrame*device.channels); + const float *frameIn = framesIn + (iFrame*device.channels); - frameOut[iChannel] += frameIn[iChannel] * masterVolume * localVolume; + frameOut[iChannel] += frameIn[iChannel]*masterVolume*localVolume; } } } -static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameCount, void* pFramesOut) +static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameCount, void *pFramesOut) { // This is where all of the mixing takes place. (void)pDevice; @@ -328,27 +329,28 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC for (AudioBuffer* audioBuffer = firstAudioBuffer; audioBuffer != NULL; audioBuffer = audioBuffer->next) { // Ignore stopped or paused sounds. - if (!audioBuffer->playing || audioBuffer->paused) { - continue; - } + if (!audioBuffer->playing || audioBuffer->paused) continue; mal_uint32 framesRead = 0; - for (;;) { - if (framesRead > frameCount) { + for (;;) + { + if (framesRead > frameCount) + { TraceLog(LOG_DEBUG, "Mixed too many frames from audio buffer"); break; } - if (framesRead == frameCount) { - break; - } + + if (framesRead == frameCount) break; // Just read as much data as we can from the stream. mal_uint32 framesToRead = (frameCount - framesRead); - while (framesToRead > 0) { + while (framesToRead > 0) + { float tempBuffer[1024]; // 512 frames for stereo. mal_uint32 framesToReadRightNow = framesToRead; - if (framesToReadRightNow > sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS) { + if (framesToReadRightNow > sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS) + { framesToReadRightNow = sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS; } @@ -357,9 +359,10 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC mal_bool32 flushDSP = !audioBuffer->looping; mal_uint32 framesJustRead = mal_dsp_read_frames_ex(&audioBuffer->dsp, framesToReadRightNow, tempBuffer, flushDSP); - if (framesJustRead > 0) { - float* framesOut = (float*)pFramesOut + (framesRead * device.channels); - float* framesIn = tempBuffer; + if (framesJustRead > 0) + { + float *framesOut = (float *)pFramesOut + (framesRead*device.channels); + float *framesIn = tempBuffer; MixFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume); framesToRead -= framesJustRead; @@ -367,11 +370,15 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC } // If we weren't able to read all the frames we requested, break. - if (framesJustRead < framesToReadRightNow) { - if (!audioBuffer->looping) { + if (framesJustRead < framesToReadRightNow) + { + if (!audioBuffer->looping) + { StopAudioBuffer(audioBuffer); break; - } else { + } + else + { // Should never get here, but just for safety, move the cursor position back to the start and continue the loop. audioBuffer->frameCursorPos = 0; continue; @@ -381,12 +388,11 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device* pDevice, mal_uint32 frameC // If for some reason we weren't able to read every frame we'll need to break from the loop. Not doing this could // theoretically put us into an infinite loop. - if (framesToRead > 0) { - break; - } + if (framesToRead > 0) break; } } } + mal_mutex_unlock(&audioLock); return frameCount; // We always output the same number of frames that were originally requested. @@ -488,7 +494,8 @@ void InitAudioDevice(void) void CloseAudioDevice(void) { #if USE_MINI_AL - if (!isAudioInitialized) { + if (!isAudioInitialized) + { TraceLog(LOG_WARNING, "Could not close audio device because it is not currently initialized"); return; } @@ -551,11 +558,13 @@ void SetMasterVolume(float volume) #if USE_MINI_AL static mal_uint32 AudioBuffer_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) { - AudioBuffer* audioBuffer = (AudioBuffer*)pUserData; + AudioBuffer *audioBuffer = (AudioBuffer *)pUserData; - mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames / 2; - mal_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos / subBufferSizeInFrames; - if (currentSubBufferIndex > 1) { + mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2; + mal_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames; + + if (currentSubBufferIndex > 1) + { TraceLog(LOG_DEBUG, "Frame cursor position moved too far forward in audio stream"); return 0; } @@ -565,7 +574,7 @@ static mal_uint32 AudioBuffer_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCount, vo isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0]; isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1]; - mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn) * audioBuffer->dsp.config.channelsIn; + mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn)*audioBuffer->dsp.config.channelsIn; // Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0. mal_uint32 framesRead = 0; @@ -573,49 +582,47 @@ static mal_uint32 AudioBuffer_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCount, vo { // We break from this loop differently depending on the buffer's usage. For static buffers, we simply fill as much data as we can. For // streaming buffers we only fill the halves of the buffer that are processed. Unprocessed halves must keep their audio data in-tact. - if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) { - if (framesRead >= frameCount) { - break; - } - } else { - if (isSubBufferProcessed[currentSubBufferIndex]) { - break; - } + if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) + { + if (framesRead >= frameCount) break; + } + else + { + if (isSubBufferProcessed[currentSubBufferIndex]) break; } mal_uint32 totalFramesRemaining = (frameCount - framesRead); - if (totalFramesRemaining == 0) { - break; - } + if (totalFramesRemaining == 0) break; mal_uint32 framesRemainingInOutputBuffer; - if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) { + if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) + { framesRemainingInOutputBuffer = audioBuffer->bufferSizeInFrames - audioBuffer->frameCursorPos; - } else { + } + else + { mal_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames * currentSubBufferIndex; framesRemainingInOutputBuffer = subBufferSizeInFrames - (audioBuffer->frameCursorPos - firstFrameIndexOfThisSubBuffer); } - - mal_uint32 framesToRead = totalFramesRemaining; - if (framesToRead > framesRemainingInOutputBuffer) { - framesToRead = framesRemainingInOutputBuffer; - } + if (framesToRead > framesRemainingInOutputBuffer) framesToRead = framesRemainingInOutputBuffer; - memcpy((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), audioBuffer->buffer + (audioBuffer->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes); + memcpy((unsigned char *)pFramesOut + (framesRead*frameSizeInBytes), audioBuffer->buffer + (audioBuffer->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes); audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead) % audioBuffer->bufferSizeInFrames; framesRead += framesToRead; // If we've read to the end of the buffer, mark it as processed. - if (framesToRead == framesRemainingInOutputBuffer) { + if (framesToRead == framesRemainingInOutputBuffer) + { audioBuffer->isSubBufferProcessed[currentSubBufferIndex] = true; isSubBufferProcessed[currentSubBufferIndex] = true; currentSubBufferIndex = (currentSubBufferIndex + 1) % 2; // We need to break from this loop if we're not looping. - if (!audioBuffer->looping) { + if (!audioBuffer->looping) + { StopAudioBuffer(audioBuffer); break; } @@ -624,24 +631,23 @@ static mal_uint32 AudioBuffer_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCount, vo // Zero-fill excess. mal_uint32 totalFramesRemaining = (frameCount - framesRead); - if (totalFramesRemaining > 0) { + if (totalFramesRemaining > 0) + { memset((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes); // For static buffers we can fill the remaining frames with silence for safety, but we don't want // to report those frames as "read". The reason for this is that the caller uses the return value // to know whether or not a non-looping sound has finished playback. - if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) { - framesRead += totalFramesRemaining; - } + if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) framesRead += totalFramesRemaining; } return framesRead; } // Create a new audio buffer. Initially filled with silence. -AudioBuffer* CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage) +AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage) { - AudioBuffer* audioBuffer = (AudioBuffer*)calloc(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*mal_get_sample_size_in_bytes(format)), 1); + AudioBuffer *audioBuffer = (AudioBuffer *)calloc(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*mal_get_sample_size_in_bytes(format)), 1); if (audioBuffer == NULL) { TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to allocate memory for audio buffer"); @@ -658,7 +664,8 @@ AudioBuffer* CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint3 dspConfig.sampleRateIn = sampleRate; dspConfig.sampleRateOut = DEVICE_SAMPLE_RATE; mal_result resultMAL = mal_dsp_init(&dspConfig, AudioBuffer_OnDSPRead, audioBuffer, &audioBuffer->dsp); - if (resultMAL != MAL_SUCCESS) { + if (resultMAL != MAL_SUCCESS) + { TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create data conversion pipeline"); free(audioBuffer); return NULL; @@ -683,7 +690,7 @@ AudioBuffer* CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint3 } // Delete an audio buffer. -void DeleteAudioBuffer(AudioBuffer* audioBuffer) +void DeleteAudioBuffer(AudioBuffer *audioBuffer) { if (audioBuffer == NULL) { @@ -696,7 +703,7 @@ void DeleteAudioBuffer(AudioBuffer* audioBuffer) } // Check if an audio buffer is playing. -bool IsAudioBufferPlaying(AudioBuffer* audioBuffer) +bool IsAudioBufferPlaying(AudioBuffer *audioBuffer) { if (audioBuffer == NULL) { @@ -711,7 +718,7 @@ bool IsAudioBufferPlaying(AudioBuffer* audioBuffer) // // This will restart the buffer from the start. Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position // should be maintained. -void PlayAudioBuffer(AudioBuffer* audioBuffer) +void PlayAudioBuffer(AudioBuffer *audioBuffer) { if (audioBuffer == NULL) { @@ -725,7 +732,7 @@ void PlayAudioBuffer(AudioBuffer* audioBuffer) } // Stop an audio buffer. -void StopAudioBuffer(AudioBuffer* audioBuffer) +void StopAudioBuffer(AudioBuffer *audioBuffer) { if (audioBuffer == NULL) { @@ -734,10 +741,7 @@ void StopAudioBuffer(AudioBuffer* audioBuffer) } // Don't do anything if the audio buffer is already stopped. - if (!IsAudioBufferPlaying(audioBuffer)) - { - return; - } + if (!IsAudioBufferPlaying(audioBuffer)) return; audioBuffer->playing = false; audioBuffer->paused = false; @@ -747,7 +751,7 @@ void StopAudioBuffer(AudioBuffer* audioBuffer) } // Pause an audio buffer. -void PauseAudioBuffer(AudioBuffer* audioBuffer) +void PauseAudioBuffer(AudioBuffer *audioBuffer) { if (audioBuffer == NULL) { @@ -759,7 +763,7 @@ void PauseAudioBuffer(AudioBuffer* audioBuffer) } // Resume an audio buffer. -void ResumeAudioBuffer(AudioBuffer* audioBuffer) +void ResumeAudioBuffer(AudioBuffer *audioBuffer) { if (audioBuffer == NULL) { @@ -771,7 +775,7 @@ void ResumeAudioBuffer(AudioBuffer* audioBuffer) } // Set volume for an audio buffer. -void SetAudioBufferVolume(AudioBuffer* audioBuffer, float volume) +void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume) { if (audioBuffer == NULL) { @@ -783,7 +787,7 @@ void SetAudioBufferVolume(AudioBuffer* audioBuffer, float volume) } // Set pitch for an audio buffer. -void SetAudioBufferPitch(AudioBuffer* audioBuffer, float pitch) +void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch) { if (audioBuffer == NULL) { @@ -874,23 +878,13 @@ Sound LoadSoundFromWave(Wave wave) mal_uint32 frameCountIn = wave.sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so. mal_uint32 frameCount = mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn); - if (frameCount == 0) { - TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to get frame count for format conversion"); - } - + if (frameCount == 0) TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to get frame count for format conversion"); AudioBuffer* audioBuffer = CreateAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, frameCount, AUDIO_BUFFER_USAGE_STATIC); - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create audio buffer"); - } - + if (audioBuffer == NULL) TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create audio buffer"); frameCount = mal_convert_frames(audioBuffer->buffer, audioBuffer->dsp.config.formatIn, audioBuffer->dsp.config.channelsIn, audioBuffer->dsp.config.sampleRateIn, wave.data, formatIn, wave.channels, wave.sampleRate, frameCountIn); - if (frameCount == 0) - { - TraceLog(LOG_ERROR, "LoadSoundFromWave() : Format conversion failed"); - } + if (frameCount == 0) TraceLog(LOG_ERROR, "LoadSoundFromWave() : Format conversion failed"); sound.audioBuffer = audioBuffer; #else @@ -965,7 +959,7 @@ void UnloadWave(Wave wave) void UnloadSound(Sound sound) { #if USE_MINI_AL - DeleteAudioBuffer((AudioBuffer*)sound.audioBuffer); + DeleteAudioBuffer((AudioBuffer *)sound.audioBuffer); #else alSourceStop(sound.source); @@ -981,7 +975,7 @@ void UnloadSound(Sound sound) void UpdateSound(Sound sound, const void *data, int samplesCount) { #if USE_MINI_AL - AudioBuffer* audioBuffer = (AudioBuffer*)sound.audioBuffer; + AudioBuffer *audioBuffer = (AudioBuffer *)sound.audioBuffer; if (audioBuffer == NULL) { TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound - no audio buffer"); @@ -1021,7 +1015,7 @@ void UpdateSound(Sound sound, const void *data, int samplesCount) void PlaySound(Sound sound) { #if USE_MINI_AL - PlayAudioBuffer((AudioBuffer*)sound.audioBuffer); + PlayAudioBuffer((AudioBuffer *)sound.audioBuffer); #else alSourcePlay(sound.source); // Play the sound #endif @@ -1046,7 +1040,7 @@ void PlaySound(Sound sound) void PauseSound(Sound sound) { #if USE_MINI_AL - PauseAudioBuffer((AudioBuffer*)sound.audioBuffer); + PauseAudioBuffer((AudioBuffer *)sound.audioBuffer); #else alSourcePause(sound.source); #endif @@ -1056,7 +1050,7 @@ void PauseSound(Sound sound) void ResumeSound(Sound sound) { #if USE_MINI_AL - ResumeAudioBuffer((AudioBuffer*)sound.audioBuffer); + ResumeAudioBuffer((AudioBuffer *)sound.audioBuffer); #else ALenum state; @@ -1070,7 +1064,7 @@ void ResumeSound(Sound sound) void StopSound(Sound sound) { #if USE_MINI_AL - StopAudioBuffer((AudioBuffer*)sound.audioBuffer); + StopAudioBuffer((AudioBuffer *)sound.audioBuffer); #else alSourceStop(sound.source); #endif @@ -1080,7 +1074,7 @@ void StopSound(Sound sound) bool IsSoundPlaying(Sound sound) { #if USE_MINI_AL - return IsAudioBufferPlaying((AudioBuffer*)sound.audioBuffer); + return IsAudioBufferPlaying((AudioBuffer *)sound.audioBuffer); #else bool playing = false; ALint state; @@ -1096,7 +1090,7 @@ bool IsSoundPlaying(Sound sound) void SetSoundVolume(Sound sound, float volume) { #if USE_MINI_AL - SetAudioBufferVolume((AudioBuffer*)sound.audioBuffer, volume); + SetAudioBufferVolume((AudioBuffer *)sound.audioBuffer, volume); #else alSourcef(sound.source, AL_GAIN, volume); #endif @@ -1106,7 +1100,7 @@ void SetSoundVolume(Sound sound, float volume) void SetSoundPitch(Sound sound, float pitch) { #if USE_MINI_AL - SetAudioBufferPitch((AudioBuffer*)sound.audioBuffer, pitch); + SetAudioBufferPitch((AudioBuffer *)sound.audioBuffer, pitch); #else alSourcef(sound.source, AL_PITCH, pitch); #endif @@ -1121,15 +1115,17 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) mal_uint32 frameCountIn = wave->sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so. mal_uint32 frameCount = mal_convert_frames(NULL, formatOut, channels, sampleRate, NULL, formatIn, wave->channels, wave->sampleRate, frameCountIn); - if (frameCount == 0) { + if (frameCount == 0) + { TraceLog(LOG_ERROR, "WaveFormat() : Failed to get frame count for format conversion."); return; } - void* data = malloc(frameCount * channels * (sampleSize/8)); + void *data = malloc(frameCount*channels*(sampleSize/8)); frameCount = mal_convert_frames(data, formatOut, channels, sampleRate, wave->data, formatIn, wave->channels, wave->sampleRate, frameCountIn); - if (frameCount == 0) { + if (frameCount == 0) + { TraceLog(LOG_ERROR, "WaveFormat() : Format conversion failed."); return; } @@ -1404,7 +1400,7 @@ void UnloadMusicStream(Music music) void PlayMusicStream(Music music) { #if USE_MINI_AL - AudioBuffer* audioBuffer = (AudioBuffer*)music->stream.audioBuffer; + AudioBuffer *audioBuffer = (AudioBuffer *)music->stream.audioBuffer; if (audioBuffer == NULL) { TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer"); @@ -1416,9 +1412,9 @@ void PlayMusicStream(Music music) // // just make sure to play again on window restore // if (IsMusicPlaying(music)) PlayMusicStream(music); mal_uint32 frameCursorPos = audioBuffer->frameCursorPos; - { - PlayAudioStream(music->stream); // <-- This resets the cursor position. - } + + PlayAudioStream(music->stream); // <-- This resets the cursor position. + audioBuffer->frameCursorPos = frameCursorPos; #else alSourcePlay(music->stream.source); @@ -1502,7 +1498,7 @@ void UpdateMusicStream(Music music) #if USE_MINI_AL bool streamEnding = false; - unsigned int subBufferSizeInFrames = ((AudioBuffer*)music->stream.audioBuffer)->bufferSizeInFrames / 2; + unsigned int subBufferSizeInFrames = ((AudioBuffer *)music->stream.audioBuffer)->bufferSizeInFrames/2; // NOTE: Using dynamic allocation because it could require more than 16KB void *pcm = calloc(subBufferSizeInFrames*music->stream.sampleSize/8*music->stream.channels, 1); @@ -1566,10 +1562,7 @@ void UpdateMusicStream(Music music) } else { - if (music->loopCount == -1) - { - PlayMusicStream(music); - } + if (music->loopCount == -1) PlayMusicStream(music); } } else @@ -1756,11 +1749,9 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un // The size of a streaming buffer must be at least double the size of a period. unsigned int periodSize = device.bufferSizeInFrames / device.periods; unsigned int subBufferSize = AUDIO_BUFFER_SIZE; - if (subBufferSize < periodSize) { - subBufferSize = periodSize; - } + if (subBufferSize < periodSize) subBufferSize = periodSize; - AudioBuffer* audioBuffer = CreateAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM); + AudioBuffer *audioBuffer = CreateAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM); if (audioBuffer == NULL) { TraceLog(LOG_ERROR, "InitAudioStream() : Failed to create audio buffer"); @@ -1825,7 +1816,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un void CloseAudioStream(AudioStream stream) { #if USE_MINI_AL - DeleteAudioBuffer((AudioBuffer*)stream.audioBuffer); + DeleteAudioBuffer((AudioBuffer *)stream.audioBuffer); #else // Stop playing channel alSourceStop(stream.source); @@ -1879,23 +1870,22 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) } mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2; - unsigned char *subBuffer = audioBuffer->buffer + ((subBufferSizeInFrames * stream.channels * (stream.sampleSize/8)) * subBufferToUpdate); + unsigned char *subBuffer = audioBuffer->buffer + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate); // Does this API expect a whole buffer to be updated in one go? Assuming so, but if not will need to change this logic. if (subBufferSizeInFrames >= (mal_uint32)samplesCount) { mal_uint32 framesToWrite = subBufferSizeInFrames; - if (framesToWrite > (mal_uint32)samplesCount) { - framesToWrite = (mal_uint32)samplesCount; - } + if (framesToWrite > (mal_uint32)samplesCount) framesToWrite = (mal_uint32)samplesCount; - mal_uint32 bytesToWrite = framesToWrite * stream.channels * (stream.sampleSize/8); + mal_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8); memcpy(subBuffer, data, bytesToWrite); // Any leftover frames should be filled with zeros. mal_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite; - if (leftoverFrameCount > 0) { - memset(subBuffer + bytesToWrite, 0, leftoverFrameCount * stream.channels * (stream.sampleSize/8)); + if (leftoverFrameCount > 0) + { + memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8)); } audioBuffer->isSubBufferProcessed[subBufferToUpdate] = false; @@ -1929,7 +1919,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) bool IsAudioBufferProcessed(AudioStream stream) { #if USE_MINI_AL - AudioBuffer* audioBuffer = (AudioBuffer*)stream.audioBuffer; + AudioBuffer *audioBuffer = (AudioBuffer *)stream.audioBuffer; if (audioBuffer == NULL) { TraceLog(LOG_ERROR, "IsAudioBufferProcessed() : No audio buffer"); @@ -1951,7 +1941,7 @@ bool IsAudioBufferProcessed(AudioStream stream) void PlayAudioStream(AudioStream stream) { #if USE_MINI_AL - PlayAudioBuffer((AudioBuffer*)stream.audioBuffer); + PlayAudioBuffer((AudioBuffer *)stream.audioBuffer); #else alSourcePlay(stream.source); #endif @@ -1961,7 +1951,7 @@ void PlayAudioStream(AudioStream stream) void PauseAudioStream(AudioStream stream) { #if USE_MINI_AL - PauseAudioBuffer((AudioBuffer*)stream.audioBuffer); + PauseAudioBuffer((AudioBuffer *)stream.audioBuffer); #else alSourcePause(stream.source); #endif @@ -1971,7 +1961,7 @@ void PauseAudioStream(AudioStream stream) void ResumeAudioStream(AudioStream stream) { #if USE_MINI_AL - ResumeAudioBuffer((AudioBuffer*)stream.audioBuffer); + ResumeAudioBuffer((AudioBuffer *)stream.audioBuffer); #else ALenum state; alGetSourcei(stream.source, AL_SOURCE_STATE, &state); @@ -1984,7 +1974,7 @@ void ResumeAudioStream(AudioStream stream) bool IsAudioStreamPlaying(AudioStream stream) { #if USE_MINI_AL - return IsAudioBufferPlaying((AudioBuffer*)stream.audioBuffer); + return IsAudioBufferPlaying((AudioBuffer *)stream.audioBuffer); #else bool playing = false; ALint state; @@ -2001,7 +1991,7 @@ bool IsAudioStreamPlaying(AudioStream stream) void StopAudioStream(AudioStream stream) { #if USE_MINI_AL - StopAudioBuffer((AudioBuffer*)stream.audioBuffer); + StopAudioBuffer((AudioBuffer *)stream.audioBuffer); #else alSourceStop(stream.source); #endif @@ -2010,7 +2000,7 @@ void StopAudioStream(AudioStream stream) void SetAudioStreamVolume(AudioStream stream, float volume) { #if USE_MINI_AL - SetAudioBufferVolume((AudioBuffer*)stream.audioBuffer, volume); + SetAudioBufferVolume((AudioBuffer *)stream.audioBuffer, volume); #else alSourcef(stream.source, AL_GAIN, volume); #endif @@ -2019,7 +2009,7 @@ void SetAudioStreamVolume(AudioStream stream, float volume) void SetAudioStreamPitch(AudioStream stream, float pitch) { #if USE_MINI_AL - SetAudioBufferPitch((AudioBuffer*)stream.audioBuffer, pitch); + SetAudioBufferPitch((AudioBuffer *)stream.audioBuffer, pitch); #else alSourcef(stream.source, AL_PITCH, pitch); #endif From 61afd07bd7b3a96c6f0f460b668f52cf1a8bd90f Mon Sep 17 00:00:00 2001 From: Ray San Date: Wed, 20 Dec 2017 12:34:18 +0100 Subject: [PATCH 099/139] Force OpenAL backend on some platforms OpenAL audio backend is being forced on HTML5 and OSX --- src/Makefile | 27 ++++++++++++++++++++++++--- src/audio.c | 29 +++++++++++++++++------------ src/audio.h | 19 ++++++++++++------- 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/Makefile b/src/Makefile index 00f5fa2f..1d1aa75c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -47,12 +47,20 @@ API_VERSION = 1 PLATFORM ?= PLATFORM_DESKTOP RAYLIB_PATH = .. +# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) +RAYLIB_LIBTYPE ?= STATIC + # Included raylib audio module on compilation # NOTE: Some programs like tools could not require audio support INCLUDE_AUDIO_MODULE ?= YES -# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) -RAYLIB_LIBTYPE ?= STATIC +# Force OpenAL Soft backend for audio +FORCE_OPENAL_BACKEND ?= FALSE + +# OpenAL Soft audio backend forced on HTML5 and OSX (see below) +ifeq ($(PLATFORM),PLATFORM_WEB) + FORCE_OPENAL_BACKEND = TRUE +endif # Use cross-compiler for PLATFORM_RPI ifeq ($(PLATFORM),PLATFORM_RPI) @@ -95,6 +103,13 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif endif +# Force OpenAL Soft audio backend for OSX platform +# NOTE 1: mini_al library does not support CoreAudio yet +# NOTE 2: Required OpenAL libraries should be available on OSX +ifeq ($(PLATFORM_OS),OSX) + FORCE_OPENAL_BACKEND = TRUE +endif + ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH = C:/emsdk @@ -269,6 +284,10 @@ ifeq ($(RAYLIB_LIBTYPE),SHARED) CFLAGS += -fPIC -DBUILD_LIBTYPE_SHARED endif +ifeq ($(FORCE_OPENAL_BACKEND),TRUE) + CFLAGS += -DFORCE_OPENAL_BACKEND +endif + # Define include paths for required headers # NOTE: Several external required libraries (stb and others) INCLUDE_PATHS = -I. -Iexternal -Iexternal/glfw/include @@ -329,8 +348,10 @@ endif ifeq ($(INCLUDE_AUDIO_MODULE),YES) OBJS += audio.o - OBJS += mini_al.o OBJS += stb_vorbis.o +ifeq ($(FORCE_OPENAL_BACKEND),FALSE) + OBJS += mini_al.o +endif endif # Default target entry diff --git a/src/audio.c b/src/audio.c index 4855333f..b8ca60fd 100644 --- a/src/audio.c +++ b/src/audio.c @@ -16,6 +16,9 @@ * Define to use the module as standalone library (independently of raylib). * Required types and functions are defined in the same module. * +* #define FORCE_OPENAL_BACKEND +* Force OpenAL Soft audio backend usage +* * #define SUPPORT_FILEFORMAT_WAV * #define SUPPORT_FILEFORMAT_OGG * #define SUPPORT_FILEFORMAT_XM @@ -24,19 +27,24 @@ * Selected desired fileformats to be supported for loading. Some of those formats are * supported by default, to remove support, just comment unrequired #define in this module * -* LIMITATIONS: +* LIMITATIONS (only OpenAL Soft): * Only up to two channels supported: MONO and STEREO (for additional channels, use AL_EXT_MCFORMATS) * Only the following sample sizes supported: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32) * * DEPENDENCIES: -* OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html) +* mini_al - Audio device/context management (https://github.com/dr-soft/mini_al) * stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/) * jar_xm - XM module file loading * jar_mod - MOD audio file loading * dr_flac - FLAC audio file loading * +* *OpenAL Soft - Audio device management, still used on HTML5 and OSX platforms +* * CONTRIBUTORS: -* Joshua Reisenauer (github: @kd7tck): +* David Reid (github: @mackron) (Nov. 2017): +* - Complete port to mini_al library +* +* Joshua Reisenauer (github: @kd7tck) (2015) * - XM audio module support (jar_xm) * - MOD audio module support (jar_mod) * - Mixing channels support @@ -45,7 +53,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -72,8 +80,8 @@ #define SUPPORT_FILEFORMAT_MOD //------------------------------------------------- -#ifndef USE_MINI_AL -#define USE_MINI_AL 1 // Set to 1 to use mini_al; 0 to use OpenAL. +#if !defined(FORCE_OPENAL_BACKEND) + #define USE_MINI_AL 1 // Set to 1 to use mini_al; 0 to use OpenAL. #endif #if defined(AUDIO_STANDALONE) @@ -86,7 +94,7 @@ #include "external/mini_al.h" // Implemented in mini_al.c. Cannot implement this here because it conflicts with Win32 APIs such as CloseWindow(), etc. -#if !defined(USE_MINI_AL) || USE_MINI_AL == 0 +#if !defined(USE_MINI_AL) || (USE_MINI_AL == 0) #if defined(__APPLE__) #include "OpenAL/al.h" // OpenAL basic header #include "OpenAL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) @@ -480,11 +488,8 @@ void InitAudioDevice(void) alListenerf(AL_GAIN, 1.0f); - if (alIsExtensionPresent("AL_EXT_float32")) { - TraceLog(LOG_INFO, "AL_EXT_float32 supported"); - } else { - TraceLog(LOG_INFO, "AL_EXT_float32 not supported"); - } + if (alIsExtensionPresent("AL_EXT_float32")) TraceLog(LOG_INFO, "[EXTENSION] AL_EXT_float32 supported"); + else TraceLog(LOG_INFO, "[EXTENSION] AL_EXT_float32 not supported"); } } #endif diff --git a/src/audio.h b/src/audio.h index 4c9faf25..01c93741 100644 --- a/src/audio.h +++ b/src/audio.h @@ -10,19 +10,24 @@ * - Manage mixing channels * - Manage raw audio context * -* LIMITATIONS: +* LIMITATIONS (only OpenAL Soft): * Only up to two channels supported: MONO and STEREO (for additional channels, use AL_EXT_MCFORMATS) * Only the following sample sizes supported: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32) * * DEPENDENCIES: -* OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html) +* mini_al - Audio device/context management (https://github.com/dr-soft/mini_al) * stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/) -* jar_xm - XM module file loading (#define SUPPORT_FILEFORMAT_XM) -* jar_mod - MOD audio file loading (#define SUPPORT_FILEFORMAT_MOD) -* dr_flac - FLAC audio file loading (#define SUPPORT_FILEFORMAT_FLAC) +* jar_xm - XM module file loading +* jar_mod - MOD audio file loading +* dr_flac - FLAC audio file loading +* +* *OpenAL Soft - Audio device management, still used on HTML5 and OSX platforms * * CONTRIBUTORS: -* Joshua Reisenauer (github: @kd7tck): +* David Reid (github: @mackron) (Nov. 2017): +* - Complete port to mini_al library +* +* Joshua Reisenauer (github: @kd7tck) (2015) * - XM audio module support (jar_xm) * - MOD audio module support (jar_mod) * - Mixing channels support @@ -31,7 +36,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. From e8bb53ed3520d2219cd7513b9c1fc20908dbf6f6 Mon Sep 17 00:00:00 2001 From: Ray San Date: Wed, 20 Dec 2017 12:35:12 +0100 Subject: [PATCH 100/139] Corrected issue on OpenGL ES compilation --- src/rlgl.c | 16 ++++++---------- src/rlgl.h | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/rlgl.c b/src/rlgl.c index 96932686..8f8a97c1 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -35,7 +35,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -1137,9 +1137,8 @@ void rlglInit(int width, int height) glGetFloatv(0x84FF, &maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT } - if(strcmp(extList[i], (const char *)"GL_EXT_debug_marker") == 0) { - debugMarkerSupported = true; - } + // Debug marker support + if(strcmp(extList[i], (const char *)"GL_EXT_debug_marker") == 0) debugMarkerSupported = true; // Clamp mirror wrap mode supported if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true; @@ -1296,7 +1295,9 @@ int rlGetVersion(void) // Set debug marker void rlSetDebugMarker(const char *text) { - if(debugMarkerSupported) glInsertEventMarkerEXT(0, text); // 0 terminated string +#if defined(GRAPHICS_API_OPENGL_33) + if (debugMarkerSupported) glInsertEventMarkerEXT(0, text); +#endif } // Load OpenGL extensions @@ -4232,8 +4233,3 @@ void TraceLog(int msgType, const char *text, ...) if (msgType == LOG_ERROR) exit(1); } #endif - -void rlSetMarker(const char *text) { - if(debugMarkerSupported) - glInsertEventMarkerEXT(0, text); //0 terminated string -} diff --git a/src/rlgl.h b/src/rlgl.h index 2437487d..d3982eb7 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -422,7 +422,7 @@ void rlglClose(void); // De-inititialize rlgl (buffers void rlglDraw(void); // Update and Draw default buffers (lines, triangles, quads) int rlGetVersion(void); // Returns current OpenGL version -void rlDebugSetMarker(const char *text); // Set debug marker for analysis +void rlSetDebugMarker(const char *text); // Set debug marker for analysis void rlLoadExtensions(void *loader); // Load OpenGL extensions Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates From 27c274bc3c5ca343de66a9f76e55c79696aed833 Mon Sep 17 00:00:00 2001 From: Ray San Date: Wed, 20 Dec 2017 12:36:47 +0100 Subject: [PATCH 101/139] Corrected issue with SaveImageAs() That function depends on SavePNG() and forces platform check on textures module, that behaviour should be changed, platform definition should be only required on core module... --- src/textures.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/textures.c b/src/textures.c index 01b8e4fc..9c41ae7d 100644 --- a/src/textures.c +++ b/src/textures.c @@ -34,7 +34,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -552,14 +552,16 @@ void UpdateTexture(Texture2D texture, const void *pixels) } // Save image to a PNG file -void SaveImageAs(const char* fileName, Image image) +void SaveImageAs(const char *fileName, Image image) { +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) // NOTE: Getting Color array as RGBA unsigned char values - unsigned char* imgData = (unsigned char*)GetImageData(image); + unsigned char *imgData = (unsigned char *)GetImageData(image); SavePNG(fileName, imgData, image.width, image.height, 4); free(imgData); TraceLog(LOG_INFO, "Image saved: %s", fileName); +#endif } // Convert image data to desired format From 00c34a035c6cf32fb688dd06da39db32fa66bc70 Mon Sep 17 00:00:00 2001 From: Ray San Date: Wed, 20 Dec 2017 12:37:08 +0100 Subject: [PATCH 102/139] Updated copyright year --- src/gestures.h | 2 +- src/models.c | 2 +- src/shapes.c | 2 +- src/text.c | 2 +- src/utils.c | 2 +- src/utils.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gestures.h b/src/gestures.h index 58670ef5..58f046cb 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -24,7 +24,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/models.c b/src/models.c index 4b8a6731..002ffac3 100644 --- a/src/models.c +++ b/src/models.c @@ -17,7 +17,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/shapes.c b/src/shapes.c index 0b34f921..9f405419 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -13,7 +13,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/text.c b/src/text.c index f577be19..eaf450b0 100644 --- a/src/text.c +++ b/src/text.c @@ -17,7 +17,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/utils.c b/src/utils.c index aaa5bdb4..72d4f2da 100644 --- a/src/utils.c +++ b/src/utils.c @@ -25,7 +25,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/utils.h b/src/utils.h index a1801245..f4a1a01a 100644 --- a/src/utils.h +++ b/src/utils.h @@ -5,7 +5,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. From 9b7a24331d3cf70ba82ba6afb91f6414963188aa Mon Sep 17 00:00:00 2001 From: Martinfx Date: Sat, 23 Dec 2017 18:12:19 +0100 Subject: [PATCH 103/139] Added next bsd os --- src/rglfw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rglfw.c b/src/rglfw.c index 0b577e3a..c1cb47bc 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -38,7 +38,7 @@ #define _GLFW_X11 #endif #endif -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__) #define _GLFW_X11 #endif #ifdef __APPLE__ @@ -83,7 +83,7 @@ #include "external/glfw/src/x11_window.c" #include "external/glfw/src/glx_context.c" #endif - + #include "external/glfw/src/linux_joystick.c" #include "external/glfw/src/posix_thread.c" #include "external/glfw/src/posix_time.c" @@ -92,7 +92,7 @@ #include "external/glfw/src/osmesa_context.c" #endif -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__) #include "external/glfw/src/x11_init.c" #include "external/glfw/src/x11_monitor.c" #include "external/glfw/src/x11_window.c" @@ -113,7 +113,7 @@ #include "external/glfw/src/cocoa_window.m" #include "external/glfw/src/cocoa_time.c" #include "external/glfw/src/posix_thread.c" - #include "external/glfw/src/nsgl_context.m" - #include "external/glfw/src/egl_context.c" + #include "external/glfw/src/nsgl_context.m" + #include "external/glfw/src/egl_context.c" #include "external/glfw/src/osmesa_context.c" #endif From dae426d9c6591b95f7d468af69e3d6bbe411d9dc Mon Sep 17 00:00:00 2001 From: Martinfx Date: Sat, 23 Dec 2017 18:29:44 +0100 Subject: [PATCH 104/139] Fixed path for FreeBSD --- examples/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Makefile b/examples/Makefile index 2c627459..fe3ff205 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -51,7 +51,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) UNAMEOS=$(shell uname) ifeq ($(UNAMEOS),FreeBSD) PLATFORM_OS=FREEBSD - LIBPATH=linux + LIBPATH=freebsd endif ifeq ($(UNAMEOS),Darwin) PLATFORM_OS=OSX From b5a1282c6bd76c6bad311fefe5e0d437e4036914 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 23 Dec 2017 18:52:35 +0100 Subject: [PATCH 105/139] Updated VS2015 projects Removed GLFW3 and OpenAL Soft dependencies --- project/vs2015/examples/core_basic_window.vcxproj | 2 +- project/vs2015/examples/core_basic_window_cpp.vcxproj | 2 +- project/vs2015/raylib/raylib.dll.vcxproj | 6 ++++-- project/vs2015/raylib/raylib.vcxproj | 2 ++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/project/vs2015/examples/core_basic_window.vcxproj b/project/vs2015/examples/core_basic_window.vcxproj index 9a8fefdb..db6c54bf 100644 --- a/project/vs2015/examples/core_basic_window.vcxproj +++ b/project/vs2015/examples/core_basic_window.vcxproj @@ -67,7 +67,7 @@ Console true $(SolutionDir)..\..\release\libs\win32\msvc;%(AdditionalLibraryDirectories) - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;glfw3.lib;%(AdditionalDependencies) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) diff --git a/project/vs2015/examples/core_basic_window_cpp.vcxproj b/project/vs2015/examples/core_basic_window_cpp.vcxproj index 71eb50f2..9fba1068 100644 --- a/project/vs2015/examples/core_basic_window_cpp.vcxproj +++ b/project/vs2015/examples/core_basic_window_cpp.vcxproj @@ -66,7 +66,7 @@ Console true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;glfw3.lib;%(AdditionalDependencies) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) $(SolutionDir)..\..\release\libs\win32\msvc;%(AdditionalLibraryDirectories) diff --git a/project/vs2015/raylib/raylib.dll.vcxproj b/project/vs2015/raylib/raylib.dll.vcxproj index 418151b0..c6d283d5 100644 --- a/project/vs2015/raylib/raylib.dll.vcxproj +++ b/project/vs2015/raylib/raylib.dll.vcxproj @@ -64,7 +64,7 @@ Windows $(SolutionDir)..\..\release\libs\win32\msvc;%(AdditionalLibraryDirectories) - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;glfw3dll.lib;openal32dll.lib;%(AdditionalDependencies) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) %(AdditionalLibraryDirectories) @@ -88,7 +88,7 @@ true true $(SolutionDir)..\..\release\libs\win32\msvc;%(AdditionalLibraryDirectories) - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;glfw3dll.lib;openal32dll.lib;%(AdditionalDependencies) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -97,8 +97,10 @@ + + diff --git a/project/vs2015/raylib/raylib.vcxproj b/project/vs2015/raylib/raylib.vcxproj index 8a7bde9d..ac71e25a 100644 --- a/project/vs2015/raylib/raylib.vcxproj +++ b/project/vs2015/raylib/raylib.vcxproj @@ -90,8 +90,10 @@ + + From f44dbf21cf4cb5e5f65be34c909192f03a5678c6 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 24 Dec 2017 15:59:03 +0100 Subject: [PATCH 106/139] Review physac timming system --- src/physac.h | 142 +++++++++++++++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 61 deletions(-) diff --git a/src/physac.h b/src/physac.h index ef78aab8..a04d3cb3 100644 --- a/src/physac.h +++ b/src/physac.h @@ -43,16 +43,15 @@ * NOTE 2: Physac requires static C library linkage to avoid dependency on MinGW DLL (-static -lpthread) * * Use the following code to compile: -* gcc -o physac_sample.exe physac_sample.c -s $(RAYLIB_DIR)\raylib\raylib_icon -static -lraylib -lpthread \ -* -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm -std=c99 -Wl,--subsystem,windows -Wl,-allow-multiple-definition +* gcc -o $(NAME_PART).exe $(FILE_NAME) -s icon\physac_icon -static -lraylib -lpthread -lopengl32 -lgdi32 -std=c99 * * VERY THANKS TO: -* Ramón Santamaria (@raysan5) +* Ramon Santamaria (github: @raysan5) * * * LICENSE: zlib/libpng * -* Copyright (c) 2016-2017 Victor Fisac +* Copyright (c) 2016-2017 Victor Fisac (github: @victorfisac) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -235,22 +234,6 @@ PHYSACDEF void ClosePhysics(void); #if defined(PHYSAC_IMPLEMENTATION) -#if defined(_WIN32) - // Functions required to query time on Windows - int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); - int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); -#elif (defined(__linux__) || defined(__APPLE__) || defined(PLATFORM_WEB)) - #if _POSIX_C_SOURCE < 199309L - #undef _POSIX_C_SOURCE - #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. - #endif - //#define _DEFAULT_SOURCE // Enables BSD function definitions and C99 POSIX compliance - #include // Required for: timespec - #include // Required for: clock_gettime() - #include -#endif - - #if !defined(PHYSAC_NO_THREADS) #include // Required for: pthread_t, pthread_create() #endif @@ -261,8 +244,27 @@ PHYSACDEF void ClosePhysics(void); #include // Required for: malloc(), free(), srand(), rand() #include // Required for: cosf(), sinf(), fabs(), sqrtf() +#include // Required for: uint64_t -#include "raymath.h" // Required for: Vector2Add(), Vector2Subtract() +#if !defined(PHYSAC_STANDALONE) + #include "raymath.h" // Required for: Vector2Add(), Vector2Subtract() +#endif + +// Time management functionality +#if defined(_WIN32) + // Functions required to query time on Windows + int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); + int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); +#elif defined(__linux__) + #if _POSIX_C_SOURCE < 199309L + #undef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. + #endif + #include // Required for: timespec + #include // Required for: clock_gettime() +#elif defined(__APPLE__) // macOS also defines __MACH__ + #include // Required for: mach_absolute_time() +#endif //---------------------------------------------------------------------------------- // Defines and Macros @@ -285,12 +287,13 @@ static pthread_t physicsThreadId; // Physics thread id #endif static unsigned int usedMemory = 0; // Total allocated dynamic memory static bool physicsThreadEnabled = false; // Physics thread enabled state -static double currentTime = 0; // Current time in milliseconds -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(__linux__) || defined(__APPLE__) || defined(PLATFORM_WEB) -static double baseTime = 0; // Android and RPI platforms base time -#endif + +static double baseTime = 0; // Offset time for MONOTONIC clock static double startTime = 0; // Start time in milliseconds static double deltaTime = 0; // Delta time used for physics steps +static double currentTime = 0; // Current time in milliseconds +static uint64_t frequency = 0.0; // Hi-res clock frequency + static double accumulator = 0; // Physics time step delta time accumulator static unsigned int stepsCount = 0; // Total physics steps processed static Vector2 gravityForce = { 0, 9.81f/1000 }; // Physics world gravity force @@ -324,8 +327,10 @@ static int Clip(Vector2 normal, float clip, Vector2 *faceA, Vector2 *faceB); static bool BiasGreaterThan(float valueA, float valueB); // Check if values are between bias range static Vector2 TriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3); // Returns the barycenter of a triangle given by 3 points -static void InitTimer(void); // Initializes hi-resolution timer -static double GetCurrentTime(void); // Get current time in milliseconds +static void InitTimer(void); // Initializes hi-resolution MONOTONIC timer +static uint64_t GetTimeCount(void); // Get hi-res MONOTONIC time measure in seconds +static double GetCurrentTime(void); // // Get hi-res MONOTONIC time measure in seconds + static int GetRandomNumber(int min, int max); // Returns a random number between min and max (both included) // Math functions @@ -341,10 +346,10 @@ static Vector2 Vector2Add(Vector2 v1, Vector2 v2); static Vector2 Vector2Subtract(Vector2 v1, Vector2 v2); // Returns the subtract of two given vectors #endif -static Mat2 Mat2Radians(float radians); // Creates a matrix 2x2 from a given radians value +static inline Mat2 Mat2Radians(float radians); // Creates a matrix 2x2 from a given radians value static void Mat2Set(Mat2 *matrix, float radians); // Set values from radians to a created matrix 2x2 -static Mat2 Mat2Transpose(Mat2 matrix); // Returns the transpose of a given matrix 2x2 -static Vector2 Mat2MultiplyVector2(Mat2 matrix, Vector2 vector); // Multiplies a vector by a matrix 2x2 +static inline Mat2 Mat2Transpose(Mat2 matrix); // Returns the transpose of a given matrix 2x2 +static inline Vector2 Mat2MultiplyVector2(Mat2 matrix, Vector2 vector); // Multiplies a vector by a matrix 2x2 //---------------------------------------------------------------------------------- // Module Functions Definition @@ -352,15 +357,15 @@ static Vector2 Mat2MultiplyVector2(Mat2 matrix, Vector2 vector); // Initializes physics values, pointers and creates physics loop thread PHYSACDEF void InitPhysics(void) { - #if defined(PHYSAC_DEBUG) - printf("[PHYSAC] physics module initialized successfully\n"); - #endif - #if !defined(PHYSAC_NO_THREADS) // NOTE: if defined, user will need to create a thread for PhysicsThread function manually // Create physics thread using POSIXS thread libraries pthread_create(&physicsThreadId, NULL, &PhysicsLoop, NULL); #endif + + #if defined(PHYSAC_DEBUG) + printf("[PHYSAC] physics module initialized successfully\n"); + #endif } // Returns true if physics thread is currently enabled @@ -1024,7 +1029,7 @@ static PolygonData CreateRectanglePolygon(Vector2 pos, Vector2 size) static void *PhysicsLoop(void *arg) { #if defined(PHYSAC_DEBUG) - printf("[PHYSAC] physics thread created with successfully\n"); + printf("[PHYSAC] physics thread created successfully\n"); #endif // Initialize physics loop thread values @@ -1884,42 +1889,56 @@ static Vector2 TriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3) return result; } -// Initializes hi-resolution timer +// Initializes hi-resolution MONOTONIC timer static void InitTimer(void) { srand(time(NULL)); // Initialize random seed + +#if defined(_WIN32) + QueryPerformanceFrequency((unsigned long long int *) &frequency); +#endif - #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) - struct timespec now; - if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) baseTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; - #endif +#if defined(__linux__) + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) frequency = 1000000000; +#endif - startTime = GetCurrentTime(); +#if defined(__APPLE__) + mach_timebase_info_data_t timebase; + mach_timebase_info(&timebase); + frequency = (timebase.denom*1e9)/timebase.numer; +#endif + + baseTime = GetTimeCount(); // Get MONOTONIC clock time offset + startTime = GetCurrentTime(); // Get current time +} + +// Get hi-res MONOTONIC time measure in seconds +static uint64_t GetTimeCount(void) +{ + uint64_t value; + +#if defined(_WIN32) + QueryPerformanceCounter((unsigned long long int *) &value); +#endif + +#if defined(__linux__) + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + value = (uint64_t)now.tv_sec*(uint64_t)1000000000 + (uint64_t)now.tv_nsec; +#endif + +#if defined(__APPLE__) + value = mach_absolute_time(); +#endif + + return value; } // Get current time in milliseconds static double GetCurrentTime(void) { - double time = 0; - - #if defined(_WIN32) - unsigned long long int clockFrequency, currentTime; - - QueryPerformanceFrequency(&clockFrequency); - QueryPerformanceCounter(¤tTime); - - time = (double)((double)currentTime/clockFrequency)*1000; - #endif - - #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(__linux__) || defined(__APPLE__) || defined(PLATFORM_WEB) - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - uint64_t temp = (uint64_t)ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec; - - time = (double)((double)(temp - baseTime)*1e-6); - #endif - - return time; + return (double)(GetTimeCount() - baseTime)/frequency*1000; } // Returns a random number between min and max (both included) @@ -2000,6 +2019,7 @@ static inline Vector2 Vector2Add(Vector2 v1, Vector2 v2) static inline Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) { return (Vector2){ v1.x - v2.x, v1.y - v2.y }; +} #endif // Creates a matrix 2x2 from a given radians value From e5744283432e712f163e30ee6999300f3c09b244 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 24 Dec 2017 16:12:52 +0100 Subject: [PATCH 107/139] Some formatting tweaks --- src/core.c | 2 +- src/rglfw.c | 23 +++++++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/core.c b/src/core.c index 6468539f..05c794ad 100644 --- a/src/core.c +++ b/src/core.c @@ -124,7 +124,7 @@ #include // Required for: strrchr(), strcmp() //#include // Macros for reporting and retrieving error conditions through error codes -#ifdef _WIN32 +#if defined(_WIN32) #include // Required for: _getch(), _chdir() #define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir() #define CHDIR _chdir diff --git a/src/rglfw.c b/src/rglfw.c index c1cb47bc..e1b5392e 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -7,7 +7,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -26,29 +26,28 @@ * **********************************************************************************************/ - //#define _GLFW_BUILD_DLL // To build shared version //http://www.glfw.org/docs/latest/compile.html#compile_manual -#ifdef _WIN32 +#if defined(_WIN32) #define _GLFW_WIN32 #endif -#ifdef __linux__ - #ifndef _GLFW_WAYLAND // Required for Wayland windowing +#if defined(__linux__) + #if !defined(_GLFW_WAYLAND) // Required for Wayland windowing #define _GLFW_X11 #endif #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__) #define _GLFW_X11 #endif -#ifdef __APPLE__ +#if defined(__APPLE__) #define _GLFW_COCOA #define _GLFW_USE_CHDIR // To chdir to the Resources subdirectory of the application bundle during glfwInit #define _GLFW_USE_MENUBAR // To create and populate the menu bar when the first window is created #define _GLFW_USE_RETINA // To have windows use the full resolution of Retina displays #endif -// NOTE: _GLFW_WAYLAND and _GLFW_MIR experimental platforms not supported at this moment +// NOTE: _GLFW_MIR experimental platform not supported at this moment #include "external/glfw/src/context.c" #include "external/glfw/src/init.c" @@ -57,7 +56,7 @@ #include "external/glfw/src/vulkan.c" #include "external/glfw/src/window.c" -#ifdef _WIN32 +#if defined(_WIN32) #include "external/glfw/src/win32_init.c" #include "external/glfw/src/win32_joystick.c" #include "external/glfw/src/win32_monitor.c" @@ -69,15 +68,15 @@ #include "external/glfw/src/osmesa_context.c" #endif -#ifdef __linux__ - #ifdef _GLFW_WAYLAND +#if defined(__linux__) + #if defined(_GLFW_WAYLAND) #include "external/glfw/src/wl_init.c" #include "external/glfw/src/wl_monitor.c" #include "external/glfw/src/wl_window.c" #include "external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c" #include "external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c" #endif - #ifdef _GLFW_X11 + #if defined(_GLFW_X11) #include "external/glfw/src/x11_init.c" #include "external/glfw/src/x11_monitor.c" #include "external/glfw/src/x11_window.c" @@ -106,7 +105,7 @@ #include "external/glfw/src/osmesa_context.c" #endif -#ifdef __APPLE__ +#if defined(__APPLE__) #include "external/glfw/src/cocoa_init.m" #include "external/glfw/src/cocoa_joystick.m" #include "external/glfw/src/cocoa_monitor.m" From e517d8fd168b361719c214d57463ef3ee461d425 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 24 Dec 2017 16:47:33 +0100 Subject: [PATCH 108/139] Added function SetTraceLogTypes() Trace log messages could be configured with this function to select wich ones are shown --- src/core.c | 4 ++-- src/raylib.h | 13 +++++++------ src/utils.c | 38 +++++++++++++++++++++++--------------- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/core.c b/src/core.c index 05c794ad..7d7e188c 100644 --- a/src/core.c +++ b/src/core.c @@ -329,7 +329,7 @@ static double updateTime, drawTime; // Time measures for update and draw static double frameTime = 0.0; // Time measure for one frame static double targetTime = 0.0; // Desired time for one frame, if 0 not applied -static char configFlags = 0; // Configuration flags (bit based) +static unsigned char configFlags = 0; // Configuration flags (bit based) static bool showLogo = false; // Track if showing logo at init is enabled #if defined(SUPPORT_GIF_RECORDING) @@ -1138,7 +1138,7 @@ void ShowLogo(void) } // Setup window configuration flags (view FLAGS) -void SetConfigFlags(char flags) +void SetConfigFlags(unsigned char flags) { configFlags = flags; diff --git a/src/raylib.h b/src/raylib.h index b0ff1fc1..d3d58afa 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -514,11 +514,11 @@ typedef struct VrDeviceInfo { //---------------------------------------------------------------------------------- // Trace log type typedef enum { - LOG_INFO = 0, - LOG_WARNING, - LOG_ERROR, - LOG_DEBUG, - LOG_OTHER + LOG_INFO = 1, + LOG_WARNING = 2, + LOG_ERROR = 4, + LOG_DEBUG = 8, + LOG_OTHER = 16 } LogType; // Shader location point type @@ -727,7 +727,8 @@ RLAPI Matrix MatrixIdentity(void); // Returns ide // Misc. functions RLAPI void ShowLogo(void); // Activate raylib logo at startup (can be done with flags) -RLAPI void SetConfigFlags(char flags); // Setup window configuration flags (view FLAGS) +RLAPI void SetConfigFlags(unsigned char flags); // Setup window configuration flags (view FLAGS) +RLAPI void SetTraceLogTypes(unsigned char types); // Enable trace log message types (bit flags based) RLAPI void TraceLog(int logType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (saved a .png) RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) diff --git a/src/utils.c b/src/utils.c index 72d4f2da..b262118c 100644 --- a/src/utils.c +++ b/src/utils.c @@ -16,9 +16,6 @@ * Show TraceLog() output messages * NOTE: By default LOG_DEBUG traces not shown * -* #define SUPPORT_TRACELOG_DEBUG -* Show TraceLog() LOG_DEBUG messages -* * DEPENDENCIES: * stb_image_write - BMP/PNG writting functions * @@ -45,7 +42,6 @@ **********************************************************************************************/ #define SUPPORT_TRACELOG // Output tracelog messages -//#define SUPPORT_TRACELOG_DEBUG // Avoid LOG_DEBUG messages tracing #include "raylib.h" // WARNING: Required for: LogType enum #include "utils.h" @@ -63,12 +59,16 @@ #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) #define STB_IMAGE_WRITE_IMPLEMENTATION - #include "external/stb_image_write.h" // Required for: stbi_write_bmp(), stbi_write_png() + #include "external/stb_image_write.h" // Required for: stbi_write_bmp(), stbi_write_png() #endif //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- + +// Log types messages supported flags (bit based) +static unsigned char logTypeFlags = LOG_INFO | LOG_WARNING | LOG_ERROR; + #if defined(PLATFORM_ANDROID) AAssetManager *assetManager; #endif @@ -87,16 +87,17 @@ static int android_close(void *cookie); // Module Functions Definition - Utilities //---------------------------------------------------------------------------------- +// Enable trace log message types (bit flags based) +void SetTraceLogTypes(unsigned char types) +{ + logTypeFlags = types; +} + // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) void TraceLog(int msgType, const char *text, ...) { #if defined(SUPPORT_TRACELOG) static char buffer[128]; - int traceDebugMsgs = 0; - -#if defined(SUPPORT_TRACELOG_DEBUG) - traceDebugMsgs = 1; -#endif switch(msgType) { @@ -116,14 +117,21 @@ void TraceLog(int msgType, const char *text, ...) #if defined(PLATFORM_ANDROID) switch(msgType) { - case LOG_INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", buffer, args); break; - case LOG_ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", buffer, args); break; - case LOG_WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", buffer, args); break; - case LOG_DEBUG: if (traceDebugMsgs) __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", buffer, args); break; + case LOG_INFO: if (logTypeFlags & LOG_INFO) __android_log_vprint(ANDROID_LOG_INFO, "raylib", buffer, args); break; + case LOG_WARNING: if (logTypeFlags & LOG_WARNING) __android_log_vprint(ANDROID_LOG_WARN, "raylib", buffer, args); break; + case LOG_ERROR: if (logTypeFlags & LOG_ERROR) __android_log_vprint(ANDROID_LOG_ERROR, "raylib", buffer, args); break; + case LOG_DEBUG: if (logTypeFlags & LOG_DEBUG) __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", buffer, args); break; default: break; } #else - if ((msgType != LOG_DEBUG) || ((msgType == LOG_DEBUG) && (traceDebugMsgs))) vprintf(buffer, args); + switch(msgType) + { + case LOG_INFO: if (logTypeFlags & LOG_INFO) vprintf(buffer, args); break; + case LOG_WARNING: if (logTypeFlags & LOG_WARNING) vprintf(buffer, args); break; + case LOG_ERROR: if (logTypeFlags & LOG_ERROR) vprintf(buffer, args); break; + case LOG_DEBUG: if (logTypeFlags & LOG_DEBUG) vprintf(buffer, args); break; + default: break; + } #endif va_end(args); From 0bd06eec5100da648e1d3dc9bd0fd796b240e079 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 24 Dec 2017 16:49:54 +0100 Subject: [PATCH 109/139] Renamed function to SetTraceLog() I think is clearer this way... --- src/raylib.h | 2 +- src/utils.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index d3d58afa..75dafa42 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -728,7 +728,7 @@ RLAPI Matrix MatrixIdentity(void); // Returns ide // Misc. functions RLAPI void ShowLogo(void); // Activate raylib logo at startup (can be done with flags) RLAPI void SetConfigFlags(unsigned char flags); // Setup window configuration flags (view FLAGS) -RLAPI void SetTraceLogTypes(unsigned char types); // Enable trace log message types (bit flags based) +RLAPI void SetTraceLog(unsigned char types); // Enable trace log message types (bit flags based) RLAPI void TraceLog(int logType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (saved a .png) RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) diff --git a/src/utils.c b/src/utils.c index b262118c..743ef98c 100644 --- a/src/utils.c +++ b/src/utils.c @@ -88,7 +88,7 @@ static int android_close(void *cookie); //---------------------------------------------------------------------------------- // Enable trace log message types (bit flags based) -void SetTraceLogTypes(unsigned char types) +void SetTraceLog(unsigned char types) { logTypeFlags = types; } From c93bca8c272af83ae752afb46db2b54d85dca454 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 28 Dec 2017 17:58:09 +0100 Subject: [PATCH 110/139] Review Makefile config flags Support external GLFW usage Renamed some flags for consistency --- examples/Makefile | 6 ++++++ src/Makefile | 38 +++++++++++++++++++++++--------------- src/audio.c | 6 +++--- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index fe3ff205..c9081b2e 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -33,6 +33,9 @@ ifeq ($(PLATFORM),PLATFORM_RPI) RAYLIB_PATH ?= /home/pi/raylib endif +# Use external GLFW library instead of rglfw module +USE_EXTERNAL_GLFW ?= FALSE + # Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) RAYLIB_LIBTYPE ?= STATIC @@ -235,6 +238,9 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) # On XWindow requires also below libraries LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor endif + ifeq ($(USE_EXTERNAL_GLFW),TRUE) + LDLIBS += -lglfw + endif endif ifeq ($(PLATFORM),PLATFORM_RPI) # Libraries for Raspberry Pi compiling diff --git a/src/Makefile b/src/Makefile index 1d1aa75c..de9a639e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -52,21 +52,24 @@ RAYLIB_LIBTYPE ?= STATIC # Included raylib audio module on compilation # NOTE: Some programs like tools could not require audio support -INCLUDE_AUDIO_MODULE ?= YES +INCLUDE_AUDIO_MODULE ?= TRUE # Force OpenAL Soft backend for audio -FORCE_OPENAL_BACKEND ?= FALSE +USE_OPENAL_BACKEND ?= FALSE + +# Use external GLFW library instead of rglfw module +USE_EXTERNAL_GLFW ?= FALSE # OpenAL Soft audio backend forced on HTML5 and OSX (see below) ifeq ($(PLATFORM),PLATFORM_WEB) - FORCE_OPENAL_BACKEND = TRUE + USE_OPENAL_BACKEND = TRUE endif # Use cross-compiler for PLATFORM_RPI ifeq ($(PLATFORM),PLATFORM_RPI) - RPI_CROSS_COMPILE ?= NO + USE_RPI_CROSS_COMPILER ?= FALSE - ifeq ($(RPI_CROSS_COMPILE),YES) + ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) RPI_TOOLCHAIN ?= C:/SysGCC/Raspberry RPI_TOOLCHAIN_SYSROOT ?= $(RPI_TOOLCHAIN)/arm-linux-gnueabihf/sysroot endif @@ -107,7 +110,7 @@ endif # NOTE 1: mini_al library does not support CoreAudio yet # NOTE 2: Required OpenAL libraries should be available on OSX ifeq ($(PLATFORM_OS),OSX) - FORCE_OPENAL_BACKEND = TRUE + USE_OPENAL_BACKEND = TRUE endif ifeq ($(PLATFORM),PLATFORM_WEB) @@ -201,7 +204,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif endif ifeq ($(PLATFORM),PLATFORM_RPI) - ifeq ($(RPI_CROSS_COMPILE),YES) + ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) # Define RPI cross-compiler #CC = armv6j-hardfloat-linux-gnueabi-gcc CC = $(RPI_TOOLCHAIN)/bin/arm-linux-gnueabihf-gcc @@ -226,7 +229,7 @@ endif AR = ar ifeq ($(PLATFORM),PLATFORM_RPI) - ifeq ($(RPI_CROSS_COMPILE),YES) + ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) # Define RPI cross-archiver #CC = armv6j-hardfloat-linux-gnueabi-gcc AR = $(RPI_TOOLCHAIN)/bin/arm-linux-gnueabihf-ar @@ -284,8 +287,8 @@ ifeq ($(RAYLIB_LIBTYPE),SHARED) CFLAGS += -fPIC -DBUILD_LIBTYPE_SHARED endif -ifeq ($(FORCE_OPENAL_BACKEND),TRUE) - CFLAGS += -DFORCE_OPENAL_BACKEND +ifeq ($(USE_OPENAL_BACKEND),TRUE) + CFLAGS += -DUSE_OPENAL_BACKEND endif # Define include paths for required headers @@ -297,6 +300,9 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) INCLUDE_PATHS += -I/usr/local/include LDFLAGS += -L. -Lsrc -L/usr/local/lib -L$(RAYLIB_RELEASE_PATH) endif + ifeq ($(USE_EXTERNAL_GLFW),TRUE) + LDFLAGS += -lglfw + endif endif # Define additional directories containing required header files @@ -343,15 +349,17 @@ OBJS = core.o \ utils.o ifeq ($(PLATFORM),PLATFORM_DESKTOP) - OBJS += rglfw.o + ifeq ($(USE_EXTERNAL_GLFW),FALSE) + OBJS += rglfw.o + endif endif -ifeq ($(INCLUDE_AUDIO_MODULE),YES) +ifeq ($(INCLUDE_AUDIO_MODULE),TRUE) OBJS += audio.o OBJS += stb_vorbis.o -ifeq ($(FORCE_OPENAL_BACKEND),FALSE) - OBJS += mini_al.o -endif + ifeq ($(USE_OPENAL_BACKEND),FALSE) + OBJS += mini_al.o + endif endif # Default target entry diff --git a/src/audio.c b/src/audio.c index b8ca60fd..17b8ea22 100644 --- a/src/audio.c +++ b/src/audio.c @@ -16,8 +16,8 @@ * Define to use the module as standalone library (independently of raylib). * Required types and functions are defined in the same module. * -* #define FORCE_OPENAL_BACKEND -* Force OpenAL Soft audio backend usage +* #define USE_OPENAL_BACKEND +* Use OpenAL Soft audio backend usage * * #define SUPPORT_FILEFORMAT_WAV * #define SUPPORT_FILEFORMAT_OGG @@ -80,7 +80,7 @@ #define SUPPORT_FILEFORMAT_MOD //------------------------------------------------- -#if !defined(FORCE_OPENAL_BACKEND) +#if !defined(USE_OPENAL_BACKEND) #define USE_MINI_AL 1 // Set to 1 to use mini_al; 0 to use OpenAL. #endif From b19e155b3419b50bd546632f9b77793bc95824d1 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 28 Dec 2017 17:58:37 +0100 Subject: [PATCH 111/139] Support UNCOMPRESSED_R32G32B32A32 texture format --- src/raylib.h | 1 + src/rlgl.c | 4 +++- src/rlgl.h | 1 + src/textures.c | 32 ++++++++++++++++++++++++++++++-- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 75dafa42..e71ff47b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -582,6 +582,7 @@ typedef enum { UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) UNCOMPRESSED_R8G8B8A8, // 32 bpp UNCOMPRESSED_R32G32B32, // 32 bit per channel (float) - HDR + UNCOMPRESSED_R32G32B32A32, // 32 bit per channel (float) - HDR COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) COMPRESSED_DXT3_RGBA, // 8 bpp diff --git a/src/rlgl.c b/src/rlgl.c index 8f8a97c1..58e9187d 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1421,6 +1421,7 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi #endif #if defined(GRAPHICS_API_OPENGL_ES2) case UNCOMPRESSED_R32G32B32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; // NOTE: Requires extension OES_texture_float + case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; // NOTE: Requires extension OES_texture_float case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mipmapCount); break; case COMPRESSED_DXT1_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, mipmapCount); break; case COMPRESSED_DXT3_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, mipmapCount); break; // NOTE: Not supported by WebGL @@ -1468,13 +1469,14 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); } break; - + // Supported texture formats: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml case UNCOMPRESSED_R5G6B5: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (unsigned short *)data); break; case UNCOMPRESSED_R8G8B8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)data); break; case UNCOMPRESSED_R5G5B5A1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break; case UNCOMPRESSED_R4G4B4A4: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, (unsigned short *)data); break; case UNCOMPRESSED_R8G8B8A8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data); break; case UNCOMPRESSED_R32G32B32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; + case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mipmapCount); break; case COMPRESSED_DXT1_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, mipmapCount); break; case COMPRESSED_DXT3_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, mipmapCount); break; diff --git a/src/rlgl.h b/src/rlgl.h index d3982eb7..0e4a5d74 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -260,6 +260,7 @@ typedef unsigned char byte; UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) UNCOMPRESSED_R8G8B8A8, // 32 bpp UNCOMPRESSED_R32G32B32, // 32 bit per channel (float) - HDR + UNCOMPRESSED_R32G32B32A32, // 32 bit per channel (float) - HDR COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) COMPRESSED_DXT3_RGBA, // 8 bpp diff --git a/src/textures.c b/src/textures.c index 9c41ae7d..34f2c323 100644 --- a/src/textures.c +++ b/src/textures.c @@ -227,10 +227,11 @@ Image LoadImage(const char *fileName) image.mipmaps = 1; if (imgBpp == 3) image.format = UNCOMPRESSED_R32G32B32; + else if (imgBpp == 4) image.format = UNCOMPRESSED_R32G32B32A32; else { // TODO: Support different number of channels at 32 bit float - TraceLog(LOG_WARNING, "[%s] Image fileformat not supported (only 3 channel 32 bit floats)", fileName); + TraceLog(LOG_WARNING, "[%s] Image fileformat not supported", fileName); UnloadImage(image); } } @@ -329,6 +330,7 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int case UNCOMPRESSED_R4G4B4A4: image.data = (unsigned short *)malloc(size); break; // 16 bpp (4 bit alpha) case UNCOMPRESSED_R8G8B8A8: image.data = (unsigned char *)malloc(size*4); size *= 4; break; // 32 bpp case UNCOMPRESSED_R32G32B32: image.data = (float *)malloc(size*12); size *= 12; break; // 4 byte per channel (12 byte) + case UNCOMPRESSED_R32G32B32A32: image.data = (float *)malloc(size*16); size *= 16; break; // 4 byte per channel (16 byte) default: TraceLog(LOG_WARNING, "Image format not suported"); break; } @@ -679,7 +681,7 @@ void ImageFormat(Image *image, int newFormat) { image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char)); - for (int i = 0; i < image->width*image->height*4; i += 4) + for (int i = 0; i < image->width*image->height*3; i += 3) { ((unsigned char *)image->data)[i] = pixels[k].r; ((unsigned char *)image->data)[i + 1] = pixels[k].g; @@ -688,6 +690,31 @@ void ImageFormat(Image *image, int newFormat) k++; } } break; + case UNCOMPRESSED_R32G32B32: + { + image->data = (float *)malloc(image->width*image->height*3*sizeof(float)); + + for (int i = 0; i < image->width*image->height*3; i += 3) + { + ((float *)image->data)[i] = (float)pixels[k].r/255.0f; + ((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f; + ((float *)image->data)[i + 2] = (float)pixels[k].b/255.0f; + k++; + } + } break; + case UNCOMPRESSED_R32G32B32A32: + { + image->data = (float *)malloc(image->width*image->height*4*sizeof(float)); + + for (int i = 0; i < image->width*image->height*4; i += 4) + { + ((float *)image->data)[i] = (float)pixels[k].r/255.0f; + ((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f; + ((float *)image->data)[i + 2] = (float)pixels[k].b/255.0f; + ((float *)image->data)[i + 3] = (float)pixels[k].a/255.0f; + k++; + } + } break; default: break; } @@ -806,6 +833,7 @@ Image ImageCopy(Image image) case UNCOMPRESSED_R8G8B8: byteSize *= 3; break; // 24 bpp (3 bytes) case UNCOMPRESSED_R8G8B8A8: byteSize *= 4; break; // 32 bpp (4 bytes) case UNCOMPRESSED_R32G32B32: byteSize *= 12; break; // 4 byte per channel (12 bytes) + case UNCOMPRESSED_R32G32B32A32: byteSize *= 16; break; // 4 byte per channel (16 bytes) case COMPRESSED_DXT3_RGBA: case COMPRESSED_DXT5_RGBA: case COMPRESSED_ETC2_EAC_RGBA: From 7965f983baa91afa7ac8019574a14e4814c91cf2 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 28 Dec 2017 18:14:39 +0100 Subject: [PATCH 112/139] Support Wayland display on Linux desktop --- examples/Makefile | 18 ++++++++++++------ src/Makefile | 16 +++++++++++++++- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index c9081b2e..2eff1133 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -29,15 +29,19 @@ PLATFORM ?= PLATFORM_DESKTOP RAYLIB_PATH ?= .. PROJECT_NAME ?= raylib_example -ifeq ($(PLATFORM),PLATFORM_RPI) - RAYLIB_PATH ?= /home/pi/raylib -endif +# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) +RAYLIB_LIBTYPE ?= STATIC # Use external GLFW library instead of rglfw module USE_EXTERNAL_GLFW ?= FALSE -# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) -RAYLIB_LIBTYPE ?= STATIC +# Use Wayland display server protocol on Linux desktop +# by default it uses X11 windowing system +USE_WAYLAND_DISPLAY ?= FALSE + +ifeq ($(PLATFORM),PLATFORM_RPI) + RAYLIB_PATH ?= /home/pi/raylib +endif # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -223,7 +227,9 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) #LDLIBS += -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor # On Wayland windowing system, additional libraries requires - #LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon + ifeq ($(USE_WAYLAND_DISPLAY),TRUE) + LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon + endif endif ifeq ($(PLATFORM_OS),OSX) # Libraries for OSX 10.9 desktop compiling diff --git a/src/Makefile b/src/Makefile index de9a639e..2ee9f909 100644 --- a/src/Makefile +++ b/src/Makefile @@ -54,12 +54,16 @@ RAYLIB_LIBTYPE ?= STATIC # NOTE: Some programs like tools could not require audio support INCLUDE_AUDIO_MODULE ?= TRUE -# Force OpenAL Soft backend for audio +# Use OpenAL Soft backend for audio USE_OPENAL_BACKEND ?= FALSE # Use external GLFW library instead of rglfw module USE_EXTERNAL_GLFW ?= FALSE +# Use Wayland display server protocol on Linux desktop +# by default it uses X11 windowing system +USE_WAYLAND_DISPLAY ?= FALSE + # OpenAL Soft audio backend forced on HTML5 and OSX (see below) ifeq ($(PLATFORM),PLATFORM_WEB) USE_OPENAL_BACKEND = TRUE @@ -287,10 +291,20 @@ ifeq ($(RAYLIB_LIBTYPE),SHARED) CFLAGS += -fPIC -DBUILD_LIBTYPE_SHARED endif +# Use OpenAL Soft backend instead of mini_al ifeq ($(USE_OPENAL_BACKEND),TRUE) CFLAGS += -DUSE_OPENAL_BACKEND endif +# Use Wayland display on Linux desktop +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS), LINUX) + ifeq ($(USE_WAYLAND_DISPLAY),TRUE) + CFLAGS += -D_GLFW_WAYLAND + endif + endif +endif + # Define include paths for required headers # NOTE: Several external required libraries (stb and others) INCLUDE_PATHS = -I. -Iexternal -Iexternal/glfw/include From e7cf03b1e4c1aa7872bda7b35a7d064815332759 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 28 Dec 2017 19:27:02 +0100 Subject: [PATCH 113/139] Minor tweaks --- src/models.c | 6 ++---- src/rlgl.c | 8 ++++---- src/textures.c | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/models.c b/src/models.c index 002ffac3..1f37e345 100644 --- a/src/models.c +++ b/src/models.c @@ -45,9 +45,7 @@ #include "raylib.h" -#if defined(PLATFORM_ANDROID) - #include "utils.h" // Android fopen function map -#endif +#include "utils.h" // Required for: fopen() Android mapping #include // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets() #include // Required for: malloc(), free() @@ -57,7 +55,7 @@ #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 #define PAR_SHAPES_IMPLEMENTATION -#include "external/par_shapes.h" +#include "external/par_shapes.h" // Shapes 3d parametric generation //---------------------------------------------------------------------------------- // Defines and Macros diff --git a/src/rlgl.c b/src/rlgl.c index 58e9187d..4bbebf03 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1109,7 +1109,7 @@ void rlglInit(int width, int height) if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) texNPOTSupported = true; // Check texture float support - if (strcmp(extList[i], (const char *)"OES_texture_float") == 0) texFloatSupported = true; + if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) texFloatSupported = true; #endif // DDS texture compression support @@ -1137,11 +1137,11 @@ void rlglInit(int width, int height) glGetFloatv(0x84FF, &maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT } - // Debug marker support - if(strcmp(extList[i], (const char *)"GL_EXT_debug_marker") == 0) debugMarkerSupported = true; - // Clamp mirror wrap mode supported if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true; + + // Debug marker support + if(strcmp(extList[i], (const char *)"GL_EXT_debug_marker") == 0) debugMarkerSupported = true; } #ifdef _MSC_VER diff --git a/src/textures.c b/src/textures.c index 34f2c323..fd2fae0d 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1681,7 +1681,7 @@ Image GenImageCellular(int width, int height, int tileSize) // Generate GPU mipmaps for a texture void GenTextureMipmaps(Texture2D *texture) { -#if PLATFORM_WEB +#if defined(PLATFORM_WEB) // Calculate next power-of-two values int potWidth = (int)powf(2, ceilf(logf((float)texture->width)/logf(2))); int potHeight = (int)powf(2, ceilf(logf((float)texture->height)/logf(2))); From e69424c86fb2e754ebf5dcb95c9bdb2ebd4f0dbc Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 31 Dec 2017 23:50:22 +0100 Subject: [PATCH 114/139] Reviewed text input --- examples/text/text_input_box.c | 2 +- src/core.c | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/examples/text/text_input_box.c b/examples/text/text_input_box.c index 54eebf40..5f8d1c01 100644 --- a/examples/text/text_input_box.c +++ b/examples/text/text_input_box.c @@ -52,7 +52,7 @@ int main() letterCount++; } - if (key == KEY_BACKSPACE) + if (IsKeyPressed(KEY_BACKSPACE)) { letterCount--; name[letterCount] = '\0'; diff --git a/src/core.c b/src/core.c index 7d7e188c..60bc58b8 100644 --- a/src/core.c +++ b/src/core.c @@ -2432,7 +2432,9 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i else { currentKeyState[key] = action; - if (action == GLFW_PRESS) lastKeyPressed = key; + + // NOTE: lastKeyPressed already registered on CharCallback() + //if (action == GLFW_PRESS) lastKeyPressed = key; } } @@ -2498,12 +2500,15 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) #endif } -// GLFW3 Char Key Callback, runs on key pressed (get char value) +// GLFW3 Char Key Callback, runs on key down (get unicode char value) static void CharCallback(GLFWwindow *window, unsigned int key) -{ +{ + // NOTE: Registers any key down considering OS keyboard layout but + // do not detects action events, those should be managed by user... + // https://github.com/glfw/glfw/issues/668#issuecomment-166794907 + // http://www.glfw.org/docs/latest/input_guide.html#input_char + lastKeyPressed = key; - - //TraceLog(LOG_INFO, "Char Callback Key pressed: %i\n", key); } // GLFW3 CursorEnter Callback, when cursor enters the window From e1baae02498aab2f4dd84c44732717bb963d18d1 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 1 Jan 2018 16:54:32 +0100 Subject: [PATCH 115/139] Removed function DrawRectangleT() Functionality integrated in DrawRectangle() and selectable with config flag USE_DEFAULT_FONT_TEXTURE --- src/raylib.h | 3 +- src/shapes.c | 180 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 110 insertions(+), 73 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index e71ff47b..3e2dbe0c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -830,14 +830,13 @@ RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color colo RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version) RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle +RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version) RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a vertical-gradient-filled rectangle RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a horizontal-gradient-filled rectangle RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw a gradient-filled rectangle with custom vertex colors -RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version) RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline -RLAPI void DrawRectangleT(int posX, int posY, int width, int height, Color color); // Draw rectangle using text character RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version) diff --git a/src/shapes.c b/src/shapes.c index 9f405419..80ba64fa 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -10,6 +10,10 @@ * #define SUPPORT_TRIANGLES_ONLY * Draw shapes using only TRIANGLES, vertex are accumulated in TRIANGLES arrays * +* #define USE_DEFAULT_FONT_TEXTURE +* Draw rectangle shapes using font texture white character instead of default white texture +* Allows drawing rectangles and text with a single draw call, very useful for GUI systems! +* * * LICENSE: zlib/libpng * @@ -245,6 +249,78 @@ void DrawRectangle(int posX, int posY, int width, int height, Color color) DrawRectangleV(position, size, color); } +// Draw a color-filled rectangle (Vector version) +// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw) +void DrawRectangleV(Vector2 position, Vector2 size, Color color) +{ + if (rlGetVersion() == OPENGL_11) + { + rlBegin(RL_TRIANGLES); + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex2i(position.x, position.y); + rlVertex2i(position.x, position.y + size.y); + rlVertex2i(position.x + size.x, position.y + size.y); + + rlVertex2i(position.x, position.y); + rlVertex2i(position.x + size.x, position.y + size.y); + rlVertex2i(position.x + size.x, position.y); + rlEnd(); + } + else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20)) + { +#if defined(USE_DEFAULT_FONT_TEXTURE) + // Draw rectangle using font texture white character + rlEnableTexture(GetDefaultFont().texture.id); + + rlBegin(RL_QUADS); + rlColor4ub(color.r, color.g, color.b, color.a); + rlNormal3f(0.0f, 0.0f, 1.0f); + + // NOTE: Default raylib font character 95 is a white square + rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, + (float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); + rlVertex2f(rec.x, rec.y); + + rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, + (float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); + rlVertex2f(rec.x, rec.y + rec.height); + + rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, + (float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); + rlVertex2f(rec.x + rec.width, rec.y + rec.height); + + rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, + (float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); + rlVertex2f(rec.x + rec.width, rec.y); + rlEnd(); + + rlDisableTexture(); +#else + rlEnableTexture(GetTextureDefault().id); // Default white texture + + rlBegin(RL_QUADS); + rlColor4ub(color.r, color.g, color.b, color.a); + rlNormal3f(0.0f, 0.0f, 1.0f); + + rlTexCoord2f(0.0f, 0.0f); + rlVertex2f(position.x, position.y); + + rlTexCoord2f(0.0f, 1.0f); + rlVertex2f(position.x, position.y + size.y); + + rlTexCoord2f(1.0f, 1.0f); + rlVertex2f(position.x + size.x, position.y + size.y); + + rlTexCoord2f(1.0f, 0.0f); + rlVertex2f(position.x + size.x, position.y); + rlEnd(); + + rlDisableTexture(); +#endif + } +} + // Draw a color-filled rectangle void DrawRectangleRec(Rectangle rec, Color color) { @@ -292,6 +368,37 @@ void DrawRectangleGradientH(int posX, int posY, int width, int height, Color col // NOTE: Colors refer to corners, starting at top-lef corner and counter-clockwise void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4) { +#if defined(USE_DEFAULT_FONT_TEXTURE) + // Draw rectangle using font texture white character + rlEnableTexture(GetDefaultFont().texture.id); + + rlBegin(RL_QUADS); + rlNormal3f(0.0f, 0.0f, 1.0f); + + // NOTE: Default raylib font character 95 is a white square + rlColor4ub(col1.r, col1.g, col1.b, col1.a); + rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, + (float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); + rlVertex2f(rec.x, rec.y); + + rlColor4ub(col2.r, col2.g, col2.b, col2.a); + rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, + (float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); + rlVertex2f(rec.x, rec.y + rec.height); + + rlColor4ub(col3.r, col3.g, col3.b, col3.a); + rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, + (float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); + rlVertex2f(rec.x + rec.width, rec.y + rec.height); + + rlColor4ub(col4.r, col4.g, col4.b, col4.a); + rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, + (float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); + rlVertex2f(rec.x + rec.width, rec.y); + rlEnd(); + + rlDisableTexture(); +#else rlEnableTexture(GetTextureDefault().id); // Default white texture rlBegin(RL_QUADS); @@ -313,70 +420,9 @@ void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, rlTexCoord2f(1.0f, 0.0f); rlVertex2f(rec.x + rec.width, rec.y); rlEnd(); - - // Draw rectangle using font texture white character - /* - rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, - (float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); - rlVertex2f(rec.x, rec.y); - - rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, - (float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); - rlVertex2f(rec.x, rec.y + rec.height); - - rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, - (float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); - rlVertex2f(rec.x + rec.width, rec.y + rec.height); - - rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, - (float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); - rlVertex2f(rec.x + rec.width, rec.y); - */ - + rlDisableTexture(); -} - -// Draw a color-filled rectangle (Vector version) -// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw) -void DrawRectangleV(Vector2 position, Vector2 size, Color color) -{ - if (rlGetVersion() == OPENGL_11) - { - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2i(position.x, position.y); - rlVertex2i(position.x, position.y + size.y); - rlVertex2i(position.x + size.x, position.y + size.y); - - rlVertex2i(position.x, position.y); - rlVertex2i(position.x + size.x, position.y + size.y); - rlVertex2i(position.x + size.x, position.y); - rlEnd(); - } - else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20)) - { - rlEnableTexture(GetTextureDefault().id); // Default white texture - - rlBegin(RL_QUADS); - rlColor4ub(color.r, color.g, color.b, color.a); - rlNormal3f(0.0f, 0.0f, 1.0f); - - rlTexCoord2f(0.0f, 0.0f); - rlVertex2f(position.x, position.y); - - rlTexCoord2f(0.0f, 1.0f); - rlVertex2f(position.x, position.y + size.y); - - rlTexCoord2f(1.0f, 1.0f); - rlVertex2f(position.x + size.x, position.y + size.y); - - rlTexCoord2f(1.0f, 0.0f); - rlVertex2f(position.x + size.x, position.y); - rlEnd(); - - rlDisableTexture(); - } +#endif } // Draw rectangle outline @@ -409,14 +455,6 @@ void DrawRectangleLines(int posX, int posY, int width, int height, Color color) } } -// Draw rectangle using text character (char: 127) -// NOTE: Useful to avoid changing to default white texture -void DrawRectangleT(int posX, int posY, int width, int height, Color color) -{ - DrawTexturePro(GetDefaultFont().texture, GetDefaultFont().chars[95].rec, - (Rectangle){ posX, posY, width, height }, (Vector2){ 0, 0 }, 0.0f, color); -} - // Draw a triangle void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color) { From 1a82e1ab26d3db6f9c9c2f633df1e2980524ebfa Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 2 Jan 2018 02:26:05 +0100 Subject: [PATCH 116/139] Added function GetFileName() Review comments --- src/core.c | 13 ++++++++++++- src/raylib.h | 7 ++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/core.c b/src/core.c index 60bc58b8..371a22ee 100644 --- a/src/core.c +++ b/src/core.c @@ -1174,7 +1174,7 @@ bool IsFileExtension(const char *fileName, const char *ext) return result; } -// Get the extension for a filename +// Get pointer to extension for a filename string const char *GetExtension(const char *fileName) { const char *dot = strrchr(fileName, '.'); @@ -1184,6 +1184,17 @@ const char *GetExtension(const char *fileName) return (dot + 1); } +// Get pointer to filename for a path string +const char *GetFileName(const char *filePath) +{ + const char *fileName = strrchr(filePath, '\\'); + + if (!fileName || fileName == filePath) return filePath; + + return fileName + 1; +} + + // Get directory for a given fileName (with path) const char *GetDirectoryPath(const char *fileName) { diff --git a/src/raylib.h b/src/raylib.h index 3e2dbe0c..75bd883d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -736,9 +736,10 @@ RLAPI int GetRandomValue(int min, int max); // Returns a r // Files management functions RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension -RLAPI const char *GetExtension(const char *fileName); // Get file extension -RLAPI const char *GetDirectoryPath(const char *fileName); // Get directory for a given fileName (with path) -RLAPI const char *GetWorkingDirectory(void); // Get current working directory +RLAPI const char *GetExtension(const char *fileName); // Get pointer to extension for a filename string +RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string +RLAPI const char *GetDirectoryPath(const char *fileName); // Get full path for a given fileName (uses static string) +RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) RLAPI bool ChangeDirectory(const char *dir); // Change working directory, returns true if success RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window RLAPI char **GetDroppedFiles(int *count); // Get dropped files names From b760f16f9b3a967675b5cccd39a5172634f3f2d4 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 6 Jan 2018 02:43:38 +0100 Subject: [PATCH 117/139] Reviewed framebuffers cleaning Issues when dealing with FBOs --- src/core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/core.c b/src/core.c index 371a22ee..77aa3b7e 100644 --- a/src/core.c +++ b/src/core.c @@ -83,7 +83,7 @@ #define SUPPORT_MOUSE_GESTURES #define SUPPORT_CAMERA_SYSTEM #define SUPPORT_GESTURES_SYSTEM -#define SUPPORT_BUSY_WAIT_LOOP +//#define SUPPORT_BUSY_WAIT_LOOP #define SUPPORT_GIF_RECORDING //------------------------------------------------- @@ -778,8 +778,8 @@ void DisableCursor() // Set background color (framebuffer clear color) void ClearBackground(Color color) { - // Clear full framebuffer (not only render area) to color - rlClearColor(color.r, color.g, color.b, color.a); + rlClearColor(color.r, color.g, color.b, color.a); // Set clear color + rlClearScreenBuffers(); // Clear current framebuffers } // Setup canvas (framebuffer) to start drawing @@ -789,7 +789,6 @@ void BeginDrawing(void) updateTime = currentTime - previousTime; previousTime = currentTime; - rlClearScreenBuffers(); // Clear current framebuffers rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlMultMatrixf(MatrixToFloat(downscaleView)); // If downscale required, apply it here @@ -928,8 +927,6 @@ void BeginTextureMode(RenderTexture2D target) rlEnableRenderTexture(target.id); // Enable render target - rlClearScreenBuffers(); // Clear render texture buffers - // Set viewport to framebuffer size rlViewport(0, 0, target.texture.width, target.texture.height); From 0e48396369f7cb3c41a69c9d7dba01328e0dd51c Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 6 Jan 2018 02:44:47 +0100 Subject: [PATCH 118/139] Corrected issue with new functionality Using default font texture as base white texture for rectangles reduces draw calls considerably, actually, raygui can be drawn with a single pass! --- src/shapes.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/shapes.c b/src/shapes.c index 80ba64fa..fac14760 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -36,6 +36,8 @@ * **********************************************************************************************/ +#define USE_DEFAULT_FONT_TEXTURE + #include "raylib.h" #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 @@ -280,19 +282,19 @@ void DrawRectangleV(Vector2 position, Vector2 size, Color color) // NOTE: Default raylib font character 95 is a white square rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, (float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); - rlVertex2f(rec.x, rec.y); + rlVertex2f(position.x, position.y); rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, (float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); - rlVertex2f(rec.x, rec.y + rec.height); + rlVertex2f(position.x, position.y + size.y); rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, (float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); - rlVertex2f(rec.x + rec.width, rec.y + rec.height); + rlVertex2f(position.x + size.x, position.y + size.y); rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, (float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); - rlVertex2f(rec.x + rec.width, rec.y); + rlVertex2f(position.x + size.x, position.y); rlEnd(); rlDisableTexture(); From 7fa28611607c210789054056095588b17c5bdaac Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 6 Jan 2018 02:50:20 +0100 Subject: [PATCH 119/139] Added function: GetPixelDataSize() Just found I need that function... --- src/raylib.h | 1 + src/textures.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/raylib.h b/src/raylib.h index 75bd883d..01699ae7 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -869,6 +869,7 @@ RLAPI void UnloadImage(Image image); RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array +RLAPI int GetImageDataSize(Image image); // Get image data size in bytes RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data RLAPI void SaveImageAs(const char *fileName, Image image); // Save image to a PNG file diff --git a/src/textures.c b/src/textures.c index fd2fae0d..9abee62b 100644 --- a/src/textures.c +++ b/src/textures.c @@ -515,6 +515,43 @@ Color *GetImageData(Image image) return pixels; } +// Get pixel data size in bytes (image or texture) +// NOTE: Size depends on pixel format +int GetPixelDataSize(int width, int height, int format) +{ + int dataSize = 0; // Size in bytes + int bpp = 0; // Bits per pixel + + switch (format) + { + case UNCOMPRESSED_GRAYSCALE: bpp = 8; break; + case UNCOMPRESSED_GRAY_ALPHA: + case UNCOMPRESSED_R5G6B5: + case UNCOMPRESSED_R5G5B5A1: + case UNCOMPRESSED_R4G4B4A4: bpp = 16; break; + case UNCOMPRESSED_R8G8B8A8: bpp = 32; break; + case UNCOMPRESSED_R8G8B8: bpp = 24; break; + case UNCOMPRESSED_R32G32B32: bpp = 32*3; break; + case UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break; + case COMPRESSED_DXT1_RGB: + case COMPRESSED_DXT1_RGBA: + case COMPRESSED_ETC1_RGB: + case COMPRESSED_ETC2_RGB: + case COMPRESSED_PVRT_RGB: + case COMPRESSED_PVRT_RGBA: bpp = 4; break; + case COMPRESSED_DXT3_RGBA: + case COMPRESSED_DXT5_RGBA: + case COMPRESSED_ETC2_EAC_RGBA: + case COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break; + case COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; + default: break; + } + + dataSize = width*height*bpp/8; // Total data size in bytes + + return dataSize; +} + // Get pixel data from GPU texture and return an Image // NOTE: Compressed texture formats not supported Image GetTextureData(Texture2D texture) From 1f0f8c33fa8c1033dcf3037524504f2317f5777a Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 6 Jan 2018 02:51:28 +0100 Subject: [PATCH 120/139] Added function declaration --- src/raylib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raylib.h b/src/raylib.h index 01699ae7..a2f28661 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -869,7 +869,7 @@ RLAPI void UnloadImage(Image image); RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array -RLAPI int GetImageDataSize(Image image); // Get image data size in bytes +RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data RLAPI void SaveImageAs(const char *fileName, Image image); // Save image to a PNG file From 7caa3201d51a04b739122ffadac476493bd05395 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 6 Jan 2018 13:43:48 +0100 Subject: [PATCH 121/139] Improved pixel formats support - Renamed enum TextureFormat to PixelFormat for consistency - Added support for pixel format UNCOMPRESSED_R32 - Using GetPixelDataSize() where required --- src/raylib.h | 15 ++++++------ src/rlgl.c | 2 ++ src/rlgl.h | 9 ++++---- src/textures.c | 63 +++++++++++++++----------------------------------- 4 files changed, 33 insertions(+), 56 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index a2f28661..c44653e8 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -341,7 +341,7 @@ typedef struct Image { int width; // Image base width int height; // Image base height int mipmaps; // Mipmap levels, 1 by default - int format; // Data format (TextureFormat type) + int format; // Data format (PixelFormat type) } Image; // Texture2D type @@ -351,7 +351,7 @@ typedef struct Texture2D { int width; // Texture base width int height; // Texture base height int mipmaps; // Mipmap levels, 1 by default - int format; // Data format (TextureFormat type) + int format; // Data format (PixelFormat type) } Texture2D; // RenderTexture2D type, for texture rendering @@ -571,18 +571,19 @@ typedef enum { #define MAP_DIFFUSE MAP_ALBEDO #define MAP_SPECULAR MAP_METALNESS -// Texture formats +// Pixel formats // NOTE: Support depends on OpenGL version and platform typedef enum { UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) - UNCOMPRESSED_GRAY_ALPHA, // 16 bpp (2 channels) + UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) UNCOMPRESSED_R5G6B5, // 16 bpp UNCOMPRESSED_R8G8B8, // 24 bpp UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) UNCOMPRESSED_R8G8B8A8, // 32 bpp - UNCOMPRESSED_R32G32B32, // 32 bit per channel (float) - HDR - UNCOMPRESSED_R32G32B32A32, // 32 bit per channel (float) - HDR + UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) COMPRESSED_DXT3_RGBA, // 8 bpp @@ -594,7 +595,7 @@ typedef enum { COMPRESSED_PVRT_RGBA, // 4 bpp COMPRESSED_ASTC_4x4_RGBA, // 8 bpp COMPRESSED_ASTC_8x8_RGBA // 2 bpp -} TextureFormat; +} PixelFormat; // Texture parameters: filter mode // NOTE 1: Filtering considers mipmaps if available in the texture diff --git a/src/rlgl.c b/src/rlgl.c index 4bbebf03..e7ab7cd7 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1420,6 +1420,7 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi case COMPRESSED_DXT5_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, mipmapCount); break; #endif #if defined(GRAPHICS_API_OPENGL_ES2) + case UNCOMPRESSED_R32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; // NOTE: Requires extension OES_texture_float case UNCOMPRESSED_R32G32B32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; // NOTE: Requires extension OES_texture_float case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; // NOTE: Requires extension OES_texture_float case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mipmapCount); break; @@ -1475,6 +1476,7 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi case UNCOMPRESSED_R5G5B5A1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break; case UNCOMPRESSED_R4G4B4A4: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, (unsigned short *)data); break; case UNCOMPRESSED_R8G8B8A8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data); break; + case UNCOMPRESSED_R32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; case UNCOMPRESSED_R32G32B32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mipmapCount); break; diff --git a/src/rlgl.h b/src/rlgl.h index 0e4a5d74..68d8d4eb 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -169,7 +169,7 @@ typedef unsigned char byte; int width; // Texture base width int height; // Texture base height int mipmaps; // Mipmap levels, 1 by default - int format; // Data format (TextureFormat) + int format; // Data format (PixelFormat) } Texture2D; // RenderTexture2D type, for texture rendering @@ -259,8 +259,9 @@ typedef unsigned char byte; UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) UNCOMPRESSED_R8G8B8A8, // 32 bpp - UNCOMPRESSED_R32G32B32, // 32 bit per channel (float) - HDR - UNCOMPRESSED_R32G32B32A32, // 32 bit per channel (float) - HDR + UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) COMPRESSED_DXT3_RGBA, // 8 bpp @@ -272,7 +273,7 @@ typedef unsigned char byte; COMPRESSED_PVRT_RGBA, // 4 bpp COMPRESSED_ASTC_4x4_RGBA, // 8 bpp COMPRESSED_ASTC_8x8_RGBA // 2 bpp - } TextureFormat; + } PixelFormat; // Texture parameters: filter mode // NOTE 1: Filtering considers mipmaps if available in the texture diff --git a/src/textures.c b/src/textures.c index 9abee62b..7ea54c2c 100644 --- a/src/textures.c +++ b/src/textures.c @@ -226,11 +226,11 @@ Image LoadImage(const char *fileName) image.mipmaps = 1; - if (imgBpp == 3) image.format = UNCOMPRESSED_R32G32B32; + if (imgBpp == 1) image.format = UNCOMPRESSED_R32; + else if (imgBpp == 3) image.format = UNCOMPRESSED_R32G32B32; else if (imgBpp == 4) image.format = UNCOMPRESSED_R32G32B32A32; else { - // TODO: Support different number of channels at 32 bit float TraceLog(LOG_WARNING, "[%s] Image fileformat not supported", fileName); UnloadImage(image); } @@ -318,21 +318,9 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int { if (headerSize > 0) fseek(rawFile, headerSize, SEEK_SET); - unsigned int size = width*height; - - switch (format) - { - case UNCOMPRESSED_GRAYSCALE: image.data = (unsigned char *)malloc(size); break; // 8 bit per pixel (no alpha) - case UNCOMPRESSED_GRAY_ALPHA: image.data = (unsigned char *)malloc(size*2); size *= 2; break; // 16 bpp (2 channels) - case UNCOMPRESSED_R5G6B5: image.data = (unsigned short *)malloc(size); break; // 16 bpp - case UNCOMPRESSED_R8G8B8: image.data = (unsigned char *)malloc(size*3); size *= 3; break; // 24 bpp - case UNCOMPRESSED_R5G5B5A1: image.data = (unsigned short *)malloc(size); break; // 16 bpp (1 bit alpha) - case UNCOMPRESSED_R4G4B4A4: image.data = (unsigned short *)malloc(size); break; // 16 bpp (4 bit alpha) - case UNCOMPRESSED_R8G8B8A8: image.data = (unsigned char *)malloc(size*4); size *= 4; break; // 32 bpp - case UNCOMPRESSED_R32G32B32: image.data = (float *)malloc(size*12); size *= 12; break; // 4 byte per channel (12 byte) - case UNCOMPRESSED_R32G32B32A32: image.data = (float *)malloc(size*16); size *= 16; break; // 4 byte per channel (16 byte) - default: TraceLog(LOG_WARNING, "Image format not suported"); break; - } + unsigned int size = GetPixelDataSize(width, height, format); + + image.data = malloc(size); // Allocate required memory in bytes // NOTE: fread() returns num read elements instead of bytes, // to get bytes we need to read (1 byte size, elements) instead of (x byte size, 1 element) @@ -531,6 +519,7 @@ int GetPixelDataSize(int width, int height, int format) case UNCOMPRESSED_R4G4B4A4: bpp = 16; break; case UNCOMPRESSED_R8G8B8A8: bpp = 32; break; case UNCOMPRESSED_R8G8B8: bpp = 24; break; + case UNCOMPRESSED_R32: bpp = 32; break; case UNCOMPRESSED_R32G32B32: bpp = 32*3; break; case UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break; case COMPRESSED_DXT1_RGB: @@ -727,6 +716,15 @@ void ImageFormat(Image *image, int newFormat) k++; } } break; + case UNCOMPRESSED_R32: + { + image->data = (float *)malloc(image->width*image->height*sizeof(float)); + + for (int i = 0; i < image->width*image->height; i++) + { + ((float *)image->data)[i] = (float)((float)pixels[i].r*0.299f/255.0f + (float)pixels[i].g*0.587f/255.0f + (float)pixels[i].b*0.114f/255.0f); + } + } break; case UNCOMPRESSED_R32G32B32: { image->data = (float *)malloc(image->width*image->height*3*sizeof(float)); @@ -858,39 +856,14 @@ Image ImageCopy(Image image) { Image newImage = { 0 }; - int byteSize = image.width*image.height; + int size = GetPixelDataSize(image.width, image.height, image.format); - switch (image.format) - { - case UNCOMPRESSED_GRAYSCALE: break; // 8 bpp (1 byte) - case UNCOMPRESSED_GRAY_ALPHA: // 16 bpp - case UNCOMPRESSED_R5G6B5: // 16 bpp - case UNCOMPRESSED_R5G5B5A1: // 16 bpp - case UNCOMPRESSED_R4G4B4A4: byteSize *= 2; break; // 16 bpp (2 bytes) - case UNCOMPRESSED_R8G8B8: byteSize *= 3; break; // 24 bpp (3 bytes) - case UNCOMPRESSED_R8G8B8A8: byteSize *= 4; break; // 32 bpp (4 bytes) - case UNCOMPRESSED_R32G32B32: byteSize *= 12; break; // 4 byte per channel (12 bytes) - case UNCOMPRESSED_R32G32B32A32: byteSize *= 16; break; // 4 byte per channel (16 bytes) - case COMPRESSED_DXT3_RGBA: - case COMPRESSED_DXT5_RGBA: - case COMPRESSED_ETC2_EAC_RGBA: - case COMPRESSED_ASTC_4x4_RGBA: break; // 8 bpp (1 byte) - case COMPRESSED_DXT1_RGB: - case COMPRESSED_DXT1_RGBA: - case COMPRESSED_ETC1_RGB: - case COMPRESSED_ETC2_RGB: - case COMPRESSED_PVRT_RGB: - case COMPRESSED_PVRT_RGBA: byteSize /= 2; break; // 4 bpp - case COMPRESSED_ASTC_8x8_RGBA: byteSize /= 4; break;// 2 bpp - default: TraceLog(LOG_WARNING, "Image format not recognized"); break; - } - - newImage.data = malloc(byteSize); + newImage.data = malloc(size); if (newImage.data != NULL) { // NOTE: Size must be provided in bytes - memcpy(newImage.data, image.data, byteSize); + memcpy(newImage.data, image.data, size); newImage.width = image.width; newImage.height = image.height; From b97134c3e157f241cef485b34b8fb0e09575e7bc Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 6 Jan 2018 18:17:38 +0100 Subject: [PATCH 122/139] Review float pixel format textures support --- src/rlgl.c | 8 ++++---- src/textures.c | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/rlgl.c b/src/rlgl.c index e7ab7cd7..b893d5e5 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1420,9 +1420,9 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi case COMPRESSED_DXT5_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, mipmapCount); break; #endif #if defined(GRAPHICS_API_OPENGL_ES2) - case UNCOMPRESSED_R32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; // NOTE: Requires extension OES_texture_float + case UNCOMPRESSED_R32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_FLOAT, (float *)data); break; // NOTE: Requires extension OES_texture_float case UNCOMPRESSED_R32G32B32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; // NOTE: Requires extension OES_texture_float - case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; // NOTE: Requires extension OES_texture_float + case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, (float *)data); break; // NOTE: Requires extension OES_texture_float case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mipmapCount); break; case COMPRESSED_DXT1_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, mipmapCount); break; case COMPRESSED_DXT3_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, mipmapCount); break; // NOTE: Not supported by WebGL @@ -1476,9 +1476,9 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi case UNCOMPRESSED_R5G5B5A1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break; case UNCOMPRESSED_R4G4B4A4: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, (unsigned short *)data); break; case UNCOMPRESSED_R8G8B8A8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data); break; - case UNCOMPRESSED_R32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; + case UNCOMPRESSED_R32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, width, height, 0, GL_RED, GL_FLOAT, (float *)data); break; case UNCOMPRESSED_R32G32B32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; - case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGB, GL_FLOAT, (float *)data); break; + case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, (float *)data); break; case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mipmapCount); break; case COMPRESSED_DXT1_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, mipmapCount); break; case COMPRESSED_DXT3_RGBA: if (texCompDXTSupported) LoadTextureCompressed((unsigned char *)data, width, height, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, mipmapCount); break; diff --git a/src/textures.c b/src/textures.c index 7ea54c2c..fe75bd74 100644 --- a/src/textures.c +++ b/src/textures.c @@ -417,6 +417,7 @@ void UnloadRenderTexture(RenderTexture2D target) } // Get pixel data from image in the form of Color struct array +// TODO: Support float pixel data retrieval Color *GetImageData(Image image) { Color *pixels = (Color *)malloc(image.width*image.height*sizeof(Color)); @@ -719,7 +720,7 @@ void ImageFormat(Image *image, int newFormat) case UNCOMPRESSED_R32: { image->data = (float *)malloc(image->width*image->height*sizeof(float)); - + for (int i = 0; i < image->width*image->height; i++) { ((float *)image->data)[i] = (float)((float)pixels[i].r*0.299f/255.0f + (float)pixels[i].g*0.587f/255.0f + (float)pixels[i].b*0.114f/255.0f); From e4be917d1b36a65286ca49b85328187ea8c190ad Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 7 Jan 2018 00:51:26 +0100 Subject: [PATCH 123/139] Added new image functions - Added: ImageAlphaClear() - Added: ImageAlphaPremultiply() - Reorganized some functions --- src/raylib.h | 6 +- src/textures.c | 378 +++++++++++++++++++++++++++---------------------- 2 files changed, 212 insertions(+), 172 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index c44653e8..b482ab3b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -876,14 +876,16 @@ RLAPI void UpdateTexture(Texture2D texture, const void *pixels); RLAPI void SaveImageAs(const char *fileName, Image image); // Save image to a PNG file // Image manipulation functions +RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image -RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) -RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) +RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color +RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) RLAPI void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm) +RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) RLAPI Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image diff --git a/src/textures.c b/src/textures.c index fe75bd74..44a9fef2 100644 --- a/src/textures.c +++ b/src/textures.c @@ -593,6 +593,74 @@ void SaveImageAs(const char *fileName, Image image) #endif } +// Copy an image to a new image +Image ImageCopy(Image image) +{ + Image newImage = { 0 }; + + int size = GetPixelDataSize(image.width, image.height, image.format); + + newImage.data = malloc(size); + + if (newImage.data != NULL) + { + // NOTE: Size must be provided in bytes + memcpy(newImage.data, image.data, size); + + newImage.width = image.width; + newImage.height = image.height; + newImage.mipmaps = image.mipmaps; + newImage.format = image.format; + } + + return newImage; +} + +// Convert image to POT (power-of-two) +// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) +void ImageToPOT(Image *image, Color fillColor) +{ + Color *pixels = GetImageData(*image); // Get pixels data + + // Calculate next power-of-two values + // NOTE: Just add the required amount of pixels at the right and bottom sides of image... + int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2))); + int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2))); + + // Check if POT texture generation is required (if texture is not already POT) + if ((potWidth != image->width) || (potHeight != image->height)) + { + Color *pixelsPOT = NULL; + + // Generate POT array from NPOT data + pixelsPOT = (Color *)malloc(potWidth*potHeight*sizeof(Color)); + + for (int j = 0; j < potHeight; j++) + { + for (int i = 0; i < potWidth; i++) + { + if ((j < image->height) && (i < image->width)) pixelsPOT[j*potWidth + i] = pixels[j*image->width + i]; + else pixelsPOT[j*potWidth + i] = fillColor; + } + } + + TraceLog(LOG_WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight); + + free(pixels); // Free pixels data + free(image->data); // Free old image data + + int format = image->format; // Store image data format to reconvert later + + // TODO: Image width and height changes... do we want to store new values or keep the old ones? + // NOTE: Issues when using image.width and image.height for sprite animations... + *image = LoadImageEx(pixelsPOT, potWidth, potHeight); + + free(pixelsPOT); // Free POT pixels data + + ImageFormat(image, format); // Reconvert image to previous format + } +} + // Convert image data to desired format void ImageFormat(Image *image, int newFormat) { @@ -806,75 +874,45 @@ void ImageAlphaMask(Image *image, Image alphaMask) } } -// Convert image to POT (power-of-two) -// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) -void ImageToPOT(Image *image, Color fillColor) +// Clear alpha channel to desired color +// NOTE: Threshold defines the alpha limit, 0.0f to 1.0f +void ImageAlphaClear(Image *image, Color color, float threshold) { - Color *pixels = GetImageData(*image); // Get pixels data + Color *pixels = GetImageData(*image); + + for (int i = 0; i < image->width*image->height; i++) if (pixels[i].a <= (unsigned char)(threshold*255.0f)) pixels[i] = color; - // Calculate next power-of-two values - // NOTE: Just add the required amount of pixels at the right and bottom sides of image... - int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2))); - int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2))); + UnloadImage(*image); + + int prevFormat = image->format; + *image = LoadImageEx(pixels, image->width, image->height); + + ImageFormat(image, prevFormat); +} - // Check if POT texture generation is required (if texture is not already POT) - if ((potWidth != image->width) || (potHeight != image->height)) +// Premultiply alpha channel +void ImageAlphaPremultiply(Image *image) +{ + float alpha = 0.0f; + Color *pixels = GetImageData(*image); + + for (int i = 0; i < image->width*image->height; i++) { - Color *pixelsPOT = NULL; - - // Generate POT array from NPOT data - pixelsPOT = (Color *)malloc(potWidth*potHeight*sizeof(Color)); - - for (int j = 0; j < potHeight; j++) - { - for (int i = 0; i < potWidth; i++) - { - if ((j < image->height) && (i < image->width)) pixelsPOT[j*potWidth + i] = pixels[j*image->width + i]; - else pixelsPOT[j*potWidth + i] = fillColor; - } - } - - TraceLog(LOG_WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight); - - free(pixels); // Free pixels data - free(image->data); // Free old image data - - int format = image->format; // Store image data format to reconvert later - - // TODO: Image width and height changes... do we want to store new values or keep the old ones? - // NOTE: Issues when using image.width and image.height for sprite animations... - *image = LoadImageEx(pixelsPOT, potWidth, potHeight); - - free(pixelsPOT); // Free POT pixels data - - ImageFormat(image, format); // Reconvert image to previous format + alpha = (float)pixels[i].a/255.0f; + pixels[i].r = (unsigned char)((float)pixels[i].r*alpha); + pixels[i].g = (unsigned char)((float)pixels[i].g*alpha); + pixels[i].b = (unsigned char)((float)pixels[i].b*alpha); } + + UnloadImage(*image); + + int prevFormat = image->format; + *image = LoadImageEx(pixels, image->width, image->height); + + ImageFormat(image, prevFormat); } #if defined(SUPPORT_IMAGE_MANIPULATION) -// Copy an image to a new image -Image ImageCopy(Image image) -{ - Image newImage = { 0 }; - - int size = GetPixelDataSize(image.width, image.height, image.format); - - newImage.data = malloc(size); - - if (newImage.data != NULL) - { - // NOTE: Size must be provided in bytes - memcpy(newImage.data, image.data, size); - - newImage.width = image.width; - newImage.height = image.height; - newImage.mipmaps = image.mipmaps; - newImage.format = image.format; - } - - return newImage; -} - // Crop an image to area defined by a rectangle // NOTE: Security checks are performed in case rectangle goes out of bounds void ImageCrop(Image *image, Rectangle crop) @@ -982,6 +1020,115 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight) free(pixels); } +// Dither image data to 16bpp or lower (Floyd-Steinberg dithering) +// NOTE: In case selected bpp do not represent an known 16bit format, +// dithered data is stored in the LSB part of the unsigned short +void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) +{ + if (image->format >= COMPRESSED_DXT1_RGB) + { + TraceLog(LOG_WARNING, "Compressed data formats can not be dithered"); + return; + } + + if ((rBpp+gBpp+bBpp+aBpp) > 16) + { + TraceLog(LOG_WARNING, "Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp)); + } + else + { + Color *pixels = GetImageData(*image); + + free(image->data); // free old image data + + if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8)) + { + TraceLog(LOG_WARNING, "Image format is already 16bpp or lower, dithering could have no effect"); + } + + // Define new image format, check if desired bpp match internal known format + if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = UNCOMPRESSED_R5G6B5; + else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = UNCOMPRESSED_R5G5B5A1; + else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = UNCOMPRESSED_R4G4B4A4; + else + { + image->format = 0; + TraceLog(LOG_WARNING, "Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp); + } + + // NOTE: We will store the dithered data as unsigned short (16bpp) + image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); + + Color oldPixel = WHITE; + Color newPixel = WHITE; + + int rError, gError, bError; + unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition + + #define MIN(a,b) (((a)<(b))?(a):(b)) + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + oldPixel = pixels[y*image->width + x]; + + // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) + newPixel.r = oldPixel.r >> (8 - rBpp); // R bits + newPixel.g = oldPixel.g >> (8 - gBpp); // G bits + newPixel.b = oldPixel.b >> (8 - bBpp); // B bits + newPixel.a = oldPixel.a >> (8 - aBpp); // A bits (not used on dithering) + + // NOTE: Error must be computed between new and old pixel but using same number of bits! + // We want to know how much color precision we have lost... + rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp)); + gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp)); + bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp)); + + pixels[y*image->width + x] = newPixel; + + // NOTE: Some cases are out of the array and should be ignored + if (x < (image->width - 1)) + { + pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff); + pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff); + pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff); + } + + if ((x > 0) && (y < (image->height - 1))) + { + pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff); + pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff); + pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff); + } + + if (y < (image->height - 1)) + { + pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff); + pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff); + pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff); + } + + if ((x < (image->width - 1)) && (y < (image->height - 1))) + { + pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff); + pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff); + pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff); + } + + rPixel = (unsigned short)newPixel.r; + gPixel = (unsigned short)newPixel.g; + bPixel = (unsigned short)newPixel.b; + aPixel = (unsigned short)newPixel.a; + + ((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel; + } + } + + free(pixels); + } +} + // Draw an image (source) within an image (destination) // TODO: Feel this function could be simplified... void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) @@ -1205,115 +1352,6 @@ void ImageFlipHorizontal(Image *image) image->data = processed.data; } -// Dither image data to 16bpp or lower (Floyd-Steinberg dithering) -// NOTE: In case selected bpp do not represent an known 16bit format, -// dithered data is stored in the LSB part of the unsigned short -void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) -{ - if (image->format >= COMPRESSED_DXT1_RGB) - { - TraceLog(LOG_WARNING, "Compressed data formats can not be dithered"); - return; - } - - if ((rBpp+gBpp+bBpp+aBpp) > 16) - { - TraceLog(LOG_WARNING, "Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp)); - } - else - { - Color *pixels = GetImageData(*image); - - free(image->data); // free old image data - - if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8)) - { - TraceLog(LOG_WARNING, "Image format is already 16bpp or lower, dithering could have no effect"); - } - - // Define new image format, check if desired bpp match internal known format - if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = UNCOMPRESSED_R5G6B5; - else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = UNCOMPRESSED_R5G5B5A1; - else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = UNCOMPRESSED_R4G4B4A4; - else - { - image->format = 0; - TraceLog(LOG_WARNING, "Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp); - } - - // NOTE: We will store the dithered data as unsigned short (16bpp) - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - - Color oldPixel = WHITE; - Color newPixel = WHITE; - - int rError, gError, bError; - unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition - - #define MIN(a,b) (((a)<(b))?(a):(b)) - - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { - oldPixel = pixels[y*image->width + x]; - - // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) - newPixel.r = oldPixel.r >> (8 - rBpp); // R bits - newPixel.g = oldPixel.g >> (8 - gBpp); // G bits - newPixel.b = oldPixel.b >> (8 - bBpp); // B bits - newPixel.a = oldPixel.a >> (8 - aBpp); // A bits (not used on dithering) - - // NOTE: Error must be computed between new and old pixel but using same number of bits! - // We want to know how much color precision we have lost... - rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp)); - gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp)); - bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp)); - - pixels[y*image->width + x] = newPixel; - - // NOTE: Some cases are out of the array and should be ignored - if (x < (image->width - 1)) - { - pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff); - pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff); - pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff); - } - - if ((x > 0) && (y < (image->height - 1))) - { - pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff); - pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff); - pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff); - } - - if (y < (image->height - 1)) - { - pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff); - pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff); - pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff); - } - - if ((x < (image->width - 1)) && (y < (image->height - 1))) - { - pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff); - pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff); - pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff); - } - - rPixel = (unsigned short)newPixel.r; - gPixel = (unsigned short)newPixel.g; - bPixel = (unsigned short)newPixel.b; - aPixel = (unsigned short)newPixel.a; - - ((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel; - } - } - - free(pixels); - } -} - // Modify image color: tint void ImageColorTint(Image *image, Color color) { From 4dcc02ff1ef4d6ab6c10ece84c47892f12290908 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 7 Jan 2018 23:54:11 +0100 Subject: [PATCH 124/139] Launch draw call if buffer limits reached Note that this solution is a temporal patch, not properly tested and prone to fail, specially if matrix are pushed into the stack... --- src/rlgl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/rlgl.c b/src/rlgl.c index b893d5e5..de81fde1 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -644,6 +644,14 @@ void rlEnd(void) // as well as depth buffer bit-depth (16bit or 24bit or 32bit) // Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits) currentDepth += (1.0f/20000.0f); + + // TODO: Verify internal buffers limits + // NOTE: Before launching draw, verify no matrix are left in the stack! + // NOTE: Probably a lines/triangles margin should be left, rlEnd could be called + // after an undetermined number of triangles buffered (check shapes::DrawPoly()) + if ((lines.vCounter/2 >= MAX_LINES_BATCH - 2) || + (triangles.vCounter/3 >= MAX_TRIANGLES_BATCH - 16) || + (quads.vCounter/4 >= MAX_QUADS_BATCH - 2)) rlglDraw(); } // Define one vertex (position) From fcb0cae60583da6500c3adb1255b258d652fe22e Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 7 Jan 2018 23:55:23 +0100 Subject: [PATCH 125/139] Use busy wait loop If not using busy wait loop, linkage with WINMM in Windows platform is required --- src/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core.c b/src/core.c index 77aa3b7e..3cb9a4e4 100644 --- a/src/core.c +++ b/src/core.c @@ -83,7 +83,7 @@ #define SUPPORT_MOUSE_GESTURES #define SUPPORT_CAMERA_SYSTEM #define SUPPORT_GESTURES_SYSTEM -//#define SUPPORT_BUSY_WAIT_LOOP +#define SUPPORT_BUSY_WAIT_LOOP #define SUPPORT_GIF_RECORDING //------------------------------------------------- From c37d2d448d373ee6aaf6b202fbfacc8283d7e682 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Jan 2018 01:03:04 +0100 Subject: [PATCH 126/139] Corrected issue with matrices Matrix stack system should be reviewed but, in the meantime, currentMatrix should be reseted in order of 3d to work --- src/rlgl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rlgl.c b/src/rlgl.c index de81fde1..1c739d45 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -414,7 +414,7 @@ void rlPushMatrix(void) } stack[stackCounter] = *currentMatrix; -// rlLoadIdentity(); + rlLoadIdentity(); // TODO: Review matrix stack logic! stackCounter++; if (currentMatrixMode == RL_MODELVIEW) useTempBuffer = true; From 278d8575bdd09ba6536291e1b66dc9d32224fb2d Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 11 Jan 2018 10:22:32 +0100 Subject: [PATCH 127/139] Added new function: ImageAlphaCrop() --- src/raylib.h | 1 + src/textures.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/raylib.h b/src/raylib.h index b482ab3b..dc02370d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -881,6 +881,7 @@ RLAPI void ImageToPOT(Image *image, Color fillColor); RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color +RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) diff --git a/src/textures.c b/src/textures.c index 44a9fef2..665e5447 100644 --- a/src/textures.c +++ b/src/textures.c @@ -890,6 +890,51 @@ void ImageAlphaClear(Image *image, Color color, float threshold) ImageFormat(image, prevFormat); } +// Crop image depending on alpha value +void ImageAlphaCrop(Image *image, float threshold) +{ + Rectangle crop = { 0 }; + + Color *pixels = GetImageData(*image); + + int minx = 0; + int miny = 0; + + for (int i = 0; i < image->width*image->height; i++) + { + if (pixels[i].a > (unsigned char)(threshold*255.0f)) + { + minx = i%image->width; + miny = -(-((i/image->width) + 1) + 1); + + if (crop.y == 0) crop.y = miny; + + if (crop.x == 0) crop.x = minx; + else if (minx < crop.x) crop.x = minx; + + if (crop.width == 0) crop.width = minx; + else if (crop.width < minx) crop.width = minx; + + if (crop.height == 0) crop.height = miny; + else if (crop.height < miny) crop.height = miny; + } + } + + crop.width -= (crop.x - 1); + crop.height -= (crop.y - 1); + + TraceLog(LOG_INFO, "Crop rectangle: (%i, %i, %i, %i)", crop.x, crop.y, crop.width, crop.height); + + free(pixels); + + // NOTE: Added this weird check to avoid additional 1px crop to + // image data that has already been cropped... + if ((crop.x != 1) && + (crop.y != 1) && + (crop.width != image->width - 1) && + (crop.height != image->height - 1)) ImageCrop(image, crop); +} + // Premultiply alpha channel void ImageAlphaPremultiply(Image *image) { @@ -912,6 +957,8 @@ void ImageAlphaPremultiply(Image *image) ImageFormat(image, prevFormat); } + + #if defined(SUPPORT_IMAGE_MANIPULATION) // Crop an image to area defined by a rectangle // NOTE: Security checks are performed in case rectangle goes out of bounds From ddf6c65d00fb956dbec407a09d217ffee491b731 Mon Sep 17 00:00:00 2001 From: - <-> Date: Mon, 15 Jan 2018 12:52:58 +0100 Subject: [PATCH 128/139] Review Makefiles and templates --- examples/Makefile | 43 +++--- templates/advance_game/Makefile | 107 +++++++++---- templates/advance_game/Makefile.Android | 2 +- templates/advance_game/advance_game.c | 2 +- .../advance_game/screens/screen_ending.c | 2 +- .../advance_game/screens/screen_gameplay.c | 2 +- templates/advance_game/screens/screen_logo.c | 2 +- .../advance_game/screens/screen_options.c | 2 +- templates/advance_game/screens/screen_title.c | 2 +- templates/advance_game/screens/screens.h | 2 +- templates/simple_game/Makefile | 139 +++++++++++------ templates/simple_game/Makefile.Android | 2 +- templates/simple_game/simple_game.c | 4 +- templates/standard_game/Makefile | 141 +++++++++++------- templates/standard_game/Makefile.Android | 2 +- .../standard_game/screens/screen_ending.c | 4 +- .../standard_game/screens/screen_gameplay.c | 4 +- templates/standard_game/screens/screen_logo.c | 2 +- .../standard_game/screens/screen_options.c | 2 +- .../standard_game/screens/screen_title.c | 4 +- templates/standard_game/screens/screens.h | 4 +- templates/standard_game/standard_game.c | 4 +- 22 files changed, 309 insertions(+), 169 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 2eff1133..a5acbf3a 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -29,6 +29,11 @@ PLATFORM ?= PLATFORM_DESKTOP RAYLIB_PATH ?= .. PROJECT_NAME ?= raylib_example +# Default path for raylib on Raspberry Pi, if installed in different path, update it! +ifeq ($(PLATFORM),PLATFORM_RPI) + RAYLIB_PATH ?= /home/pi/raylib +endif + # Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) RAYLIB_LIBTYPE ?= STATIC @@ -39,9 +44,8 @@ USE_EXTERNAL_GLFW ?= FALSE # by default it uses X11 windowing system USE_WAYLAND_DISPLAY ?= FALSE -ifeq ($(PLATFORM),PLATFORM_RPI) - RAYLIB_PATH ?= /home/pi/raylib -endif +# NOTE: On PLATFORM_WEB OpenAL Soft backend is used by default (check raylib/src/Makefile) + # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -81,8 +85,8 @@ endif ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH = C:/emsdk - EMSCRIPTEN_VERSION = 1.37.21 - CLANG_VERSION=e1.37.21_64bit + EMSCRIPTEN_VERSION = 1.37.28 + CLANG_VERSION=e1.37.28_64bit PYTHON_VERSION=2.7.5.3_64bit NODE_VERSION=4.1.1_64bit export PATH=$(EMSDK_PATH);$(EMSDK_PATH)\clang\$(CLANG_VERSION);$(EMSDK_PATH)\node\$(NODE_VERSION)\bin;$(EMSDK_PATH)\python\$(PYTHON_VERSION);$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION);C:\raylib\MinGW\bin:$$(PATH) @@ -154,7 +158,7 @@ endif # -fgnu89-inline declaring inline functions support (GCC optimized) # -Wno-missing-braces ignore invalid warning (GCC bug 53119) # -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec -CFLAGS += -O1 -Wall -std=c99 -D_DEFAULT_SOURCE -fgnu89-inline -Wno-missing-braces +CFLAGS += -O1 -s -Wall -std=c99 -D_DEFAULT_SOURCE -fgnu89-inline -Wno-missing-braces # Additional flags for compiler (if desired) #CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes @@ -177,12 +181,17 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing # -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) # -s USE_PTHREADS=1 # multithreading support - CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling -s TOTAL_MEMORY=16777216 --preload-file resources + # --preload-file resources # specify a resources folder for data compilation + CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling --preload-file resources + + # Define a custom shell .html and output extension + CFLAGS += --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html + EXT = .html endif # Define include paths for required headers # NOTE: Several external required libraries (stb and others) -INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external +INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/release/include -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external # Define additional directories containing required header files ifeq ($(PLATFORM),PLATFORM_RPI) @@ -210,7 +219,7 @@ endif # if you want to link libraries (libname.so or libname.a), use the -lname ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) - # Libraries for Windows desktop compiling + # Libraries for Windows desktop compilation LDLIBS = -lraylib -lopengl32 -lgdi32 # Required for physac examples @@ -258,12 +267,6 @@ ifeq ($(PLATFORM),PLATFORM_WEB) LDLIBS = $(RAYLIB_RELEASE)/libraylib.bc endif -# Define output extension to generate a .html file using provided shell -ifeq ($(PLATFORM),PLATFORM_WEB) - EXT = .html - WEB_SHELL = --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html -endif - # Define all object files required EXAMPLES = \ core/core_basic_window \ @@ -273,6 +276,7 @@ EXAMPLES = \ core/core_input_gamepad \ core/core_random_values \ core/core_color_select \ + core/core_drop_files \ core/core_storage_values \ core/core_gestures_detection \ core/core_3d_mode \ @@ -314,9 +318,9 @@ EXAMPLES = \ models/models_cubicmap \ models/models_mesh_picking \ models/models_mesh_generation \ - models/models_yaw_pitch_roll \ models/models_material_pbr \ models/models_skybox \ + models/models_yaw_pitch_roll \ shaders/shaders_model_shader \ shaders/shaders_shapes_textures \ shaders/shaders_custom_uniform \ @@ -330,11 +334,7 @@ EXAMPLES = \ physac/physics_movement \ physac/physics_restitution \ physac/physics_shatter \ - fix_dylib \ - -ifneq ($(PLATFORM),PLATFORM_RPI) - EXAMPLES += core/core_drop_files -endif + CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST)) @@ -378,3 +378,4 @@ ifeq ($(PLATFORM),PLATFORM_WEB) del *.o *.html *.js endif @echo Cleaning done + diff --git a/templates/advance_game/Makefile b/templates/advance_game/Makefile index 9affa1ac..25bf78d4 100644 --- a/templates/advance_game/Makefile +++ b/templates/advance_game/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2017 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. @@ -29,10 +29,24 @@ PLATFORM ?= PLATFORM_DESKTOP RAYLIB_PATH = ..\.. PROJECT_NAME ?= advance_game -# Library type used for raylib and OpenAL Soft: STATIC (.a) or SHARED (.so/.dll) -# NOTE: Libraries should be provided in the selected form +# Default path for raylib on Raspberry Pi, if installed in different path, update it! +ifeq ($(PLATFORM),PLATFORM_RPI) + RAYLIB_PATH ?= /home/pi/raylib +endif + +# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) RAYLIB_LIBTYPE ?= STATIC +# Use external GLFW library instead of rglfw module +USE_EXTERNAL_GLFW ?= FALSE + +# Use Wayland display server protocol on Linux desktop +# by default it uses X11 windowing system +USE_WAYLAND_DISPLAY ?= FALSE + +# NOTE: On PLATFORM_WEB OpenAL Soft backend is used by default (check raylib/src/Makefile) + + # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected ifeq ($(PLATFORM),PLATFORM_DESKTOP) # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows @@ -44,12 +58,22 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(UNAMEOS),Linux) PLATFORM_OS=LINUX LIBPATH=linux - else + endif + UNAMEOS=$(shell uname) + ifeq ($(UNAMEOS),FreeBSD) + PLATFORM_OS=FREEBSD + LIBPATH=freebsd + endif ifeq ($(UNAMEOS),Darwin) PLATFORM_OS=OSX LIBPATH=osx endif - endif + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + UNAMEOS=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX endif endif @@ -61,8 +85,8 @@ endif ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH = C:/emsdk - EMSCRIPTEN_VERSION = 1.37.21 - CLANG_VERSION=e1.37.21_64bit + EMSCRIPTEN_VERSION = 1.37.28 + CLANG_VERSION=e1.37.28_64bit PYTHON_VERSION=2.7.5.3_64bit NODE_VERSION=4.1.1_64bit export PATH=$(EMSDK_PATH);$(EMSDK_PATH)\clang\$(CLANG_VERSION);$(EMSDK_PATH)\node\$(NODE_VERSION)\bin;$(EMSDK_PATH)\python\$(PYTHON_VERSION);$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION);C:\raylib\MinGW\bin:$$(PATH) @@ -80,6 +104,9 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),OSX) RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/osx endif + ifeq ($(PLATFORM_OS),FREEBSD) + RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/freebsd + endif endif ifeq ($(PLATFORM),PLATFORM_WEB) RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/html5 @@ -96,6 +123,10 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) # OSX default compiler CC = clang endif + ifeq ($(PLATFORM_OS),FREEBSD) + # FreeBSD default compiler + CC = clang + endif endif ifeq ($(PLATFORM),PLATFORM_RPI) ifeq ($(RPI_CROSS_COMPILE),YES) @@ -132,6 +163,11 @@ CFLAGS += -O1 -s -Wall -std=c99 -D_DEFAULT_SOURCE -fgnu89-inline -Wno-missing-br # Additional flags for compiler (if desired) #CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),WINDOWS) + # resources file contains windows exe icon + # -Wl,--subsystem,windows hides the console window + CFLAGS += $(RAYLIB_PATH)/src/resources -Wl,--subsystem,windows + endif ifeq ($(PLATFORM_OS),LINUX) CFLAGS += -no-pie -D_DEFAULT_SOURCE endif @@ -145,7 +181,12 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing # -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) # -s USE_PTHREADS=1 # multithreading support - CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling -s TOTAL_MEMORY=16777216 --preload-file resources + # --preload-file resources # specify a resources folder for data compilation + CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling --preload-file resources + + # Define a custom shell .html and output extension + CFLAGS += --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html + EXT = .html endif # Define include paths for required headers @@ -163,6 +204,13 @@ endif # Define library paths containing required libs LDFLAGS = -L. -L$(RAYLIB_RELEASE) -L$(RAYLIB_PATH)/src +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),FREEBSD) + INCLUDE_PATHS += -I/usr/local/include + LDFLAGS += -L. -Lsrc -L/usr/local/lib + endif +endif + ifeq ($(PLATFORM),PLATFORM_RPI) LDFLAGS += -L/opt/vc/lib endif @@ -173,20 +221,42 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) # Libraries for Windows desktop compilation LDLIBS = -lraylib -lopengl32 -lgdi32 + + # Required for physac examples + #LDLIBS += -static -lpthread endif ifeq ($(PLATFORM_OS),LINUX) # Libraries for Debian GNU/Linux desktop compiling # NOTE: Required packages: libegl1-mesa-dev - LDLIBS = -lraylib -lGL -lm -lpthread -ldl + LDLIBS = -lraylib -lGL -lm -lpthread -ldl -lrt - # On XWindow requires also below libraries - LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + # On X11 requires also below libraries + LDLIBS += -lX11 + # NOTE: It seems additional libraries are not required any more, latest GLFW just dlopen them + #LDLIBS += -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + + # On Wayland windowing system, additional libraries requires + ifeq ($(USE_WAYLAND_DISPLAY),TRUE) + LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon + endif endif ifeq ($(PLATFORM_OS),OSX) # Libraries for OSX 10.9 desktop compiling - # NOTE: Required packages: libegl1-mesa-dev + # NOTE: Required packages: libopenal-dev libegl1-mesa-dev LDLIBS = -lraylib -framework OpenGL -framework OpenAL -framework Cocoa endif + ifeq ($(PLATFORM_OS),FREEBSD) + # Libraries for FreeBSD desktop compiling + # NOTE: Required packages: mesa-libs + LDLIBS = -lraylib -lGL -lpthread -lm + + # On XWindow requires also below libraries + LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + endif + ifeq ($(USE_EXTERNAL_GLFW),TRUE) + # NOTE: It could require additional packages installed: libglfw3-dev + LDLIBS += -lglfw + endif endif ifeq ($(PLATFORM),PLATFORM_RPI) # Libraries for Raspberry Pi compiling @@ -198,19 +268,6 @@ ifeq ($(PLATFORM),PLATFORM_WEB) LDLIBS = $(RAYLIB_RELEASE)/libraylib.bc endif -# Define additional parameters and flags for windows -ifeq ($(PLATFORM_OS),WINDOWS) - # resources file contains raylib icon for windows .exe - # -Wl,--subsystem,windows hides the console window - CFLAGS += $(RAYLIB_PATH)/src/resources -Wl,--subsystem,windows -endif - -# Define output extension to generate a .html file using provided shell -ifeq ($(PLATFORM),PLATFORM_WEB) - EXT = .html - WEB_SHELL = --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html -endif - # Define all source files required PROJECT_SOURCE_FILES ?= advance_game.c \ screens/screen_logo.c \ diff --git a/templates/advance_game/Makefile.Android b/templates/advance_game/Makefile.Android index ef112b57..2fda5372 100644 --- a/templates/advance_game/Makefile.Android +++ b/templates/advance_game/Makefile.Android @@ -278,7 +278,7 @@ logcat: deploy: $(ANDROID_PLATFORM_TOOLS)/adb install -r $(PROJECT_NAME).apk $(ANDROID_PLATFORM_TOOLS)/adb logcat -c - $(ANDROID_PLATFORM_TOOLS)/adb logcat raylib:V *:W + $(ANDROID_PLATFORM_TOOLS)/adb logcat raylib:V *:S #$(ANDROID_PLATFORM_TOOLS)/adb logcat *:W diff --git a/templates/advance_game/advance_game.c b/templates/advance_game/advance_game.c index 5c9442a5..5499b2d8 100644 --- a/templates/advance_game/advance_game.c +++ b/templates/advance_game/advance_game.c @@ -8,7 +8,7 @@ * This game has been created using raylib (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/templates/advance_game/screens/screen_ending.c b/templates/advance_game/screens/screen_ending.c index 4cf31f87..66b5ddf9 100644 --- a/templates/advance_game/screens/screen_ending.c +++ b/templates/advance_game/screens/screen_ending.c @@ -4,7 +4,7 @@ * * Ending Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/screens/screen_gameplay.c b/templates/advance_game/screens/screen_gameplay.c index 35428a35..8943adb5 100644 --- a/templates/advance_game/screens/screen_gameplay.c +++ b/templates/advance_game/screens/screen_gameplay.c @@ -4,7 +4,7 @@ * * Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/screens/screen_logo.c b/templates/advance_game/screens/screen_logo.c index 25b61ac0..6282e83e 100644 --- a/templates/advance_game/screens/screen_logo.c +++ b/templates/advance_game/screens/screen_logo.c @@ -4,7 +4,7 @@ * * Logo Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/screens/screen_options.c b/templates/advance_game/screens/screen_options.c index 1f69a3b9..dc8d74fa 100644 --- a/templates/advance_game/screens/screen_options.c +++ b/templates/advance_game/screens/screen_options.c @@ -4,7 +4,7 @@ * * Options Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/screens/screen_title.c b/templates/advance_game/screens/screen_title.c index cb67bb1f..5727546a 100644 --- a/templates/advance_game/screens/screen_title.c +++ b/templates/advance_game/screens/screen_title.c @@ -4,7 +4,7 @@ * * Title Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/screens/screens.h b/templates/advance_game/screens/screens.h index aaa76c6d..adfc87f5 100644 --- a/templates/advance_game/screens/screens.h +++ b/templates/advance_game/screens/screens.h @@ -4,7 +4,7 @@ * * Screens Functions Declarations (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/simple_game/Makefile b/templates/simple_game/Makefile index 70411ea8..57fe53f8 100644 --- a/templates/simple_game/Makefile +++ b/templates/simple_game/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2017 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. @@ -29,16 +29,24 @@ PLATFORM ?= PLATFORM_DESKTOP RAYLIB_PATH ?= ..\.. PROJECT_NAME ?= simple_game -# Library type used for raylib and OpenAL Soft: STATIC (.a) or SHARED (.so/.dll) -# NOTE: Libraries should be provided in the selected form -RAYLIB_LIBTYPE ?= STATIC -OPENAL_LIBTYPE ?= STATIC - -# On PLATFORM_WEB force OpenAL Soft shared library -ifeq ($(PLATFORM),PLATFORM_WEB) - OPENAL_LIBTYPE = SHARED +# Default path for raylib on Raspberry Pi, if installed in different path, update it! +ifeq ($(PLATFORM),PLATFORM_RPI) + RAYLIB_PATH ?= /home/pi/raylib endif +# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) +RAYLIB_LIBTYPE ?= STATIC + +# Use external GLFW library instead of rglfw module +USE_EXTERNAL_GLFW ?= FALSE + +# Use Wayland display server protocol on Linux desktop +# by default it uses X11 windowing system +USE_WAYLAND_DISPLAY ?= FALSE + +# NOTE: On PLATFORM_WEB OpenAL Soft backend is used by default (check raylib/src/Makefile) + + # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected ifeq ($(PLATFORM),PLATFORM_DESKTOP) # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows @@ -50,12 +58,22 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(UNAMEOS),Linux) PLATFORM_OS=LINUX LIBPATH=linux - else + endif + UNAMEOS=$(shell uname) + ifeq ($(UNAMEOS),FreeBSD) + PLATFORM_OS=FREEBSD + LIBPATH=freebsd + endif ifeq ($(UNAMEOS),Darwin) PLATFORM_OS=OSX LIBPATH=osx endif - endif + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + UNAMEOS=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX endif endif @@ -67,8 +85,8 @@ endif ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH = C:/emsdk - EMSCRIPTEN_VERSION = 1.37.9 - CLANG_VERSION=e1.37.9_64bit + EMSCRIPTEN_VERSION = 1.37.28 + CLANG_VERSION=e1.37.28_64bit PYTHON_VERSION=2.7.5.3_64bit NODE_VERSION=4.1.1_64bit export PATH=$(EMSDK_PATH);$(EMSDK_PATH)\clang\$(CLANG_VERSION);$(EMSDK_PATH)\node\$(NODE_VERSION)\bin;$(EMSDK_PATH)\python\$(PYTHON_VERSION);$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION);C:\raylib\MinGW\bin:$$(PATH) @@ -86,6 +104,9 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),OSX) RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/osx endif + ifeq ($(PLATFORM_OS),FREEBSD) + RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/freebsd + endif endif ifeq ($(PLATFORM),PLATFORM_WEB) RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/html5 @@ -102,6 +123,10 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) # OSX default compiler CC = clang endif + ifeq ($(PLATFORM_OS),FREEBSD) + # FreeBSD default compiler + CC = clang + endif endif ifeq ($(PLATFORM),PLATFORM_RPI) ifeq ($(RPI_CROSS_COMPILE),YES) @@ -125,7 +150,7 @@ endif # Define compiler flags: # -O1 defines optimization level -# -Og enable debugging +# -g enable debugging # -s strip unnecessary data from build # -Wall turns on most, but not all, compiler warnings # -std=c99 defines C language mode (standard C from 1999 revision) @@ -138,6 +163,11 @@ CFLAGS += -O1 -s -Wall -std=c99 -D_DEFAULT_SOURCE -fgnu89-inline -Wno-missing-br # Additional flags for compiler (if desired) #CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),WINDOWS) + # resources file contains windows exe icon + # -Wl,--subsystem,windows hides the console window + CFLAGS += $(RAYLIB_PATH)/src/resources -Wl,--subsystem,windows + endif ifeq ($(PLATFORM_OS),LINUX) CFLAGS += -no-pie -D_DEFAULT_SOURCE endif @@ -151,7 +181,12 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing # -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) # -s USE_PTHREADS=1 # multithreading support - CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling -s TOTAL_MEMORY=16777216 --preload-file resources + # --preload-file resources # specify a resources folder for data compilation + CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling --preload-file resources + + # Define a custom shell .html and output extension + CFLAGS += --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html + EXT = .html endif # Define include paths for required headers @@ -169,6 +204,13 @@ endif # Define library paths containing required libs LDFLAGS = -L. -L$(RAYLIB_RELEASE) -L$(RAYLIB_PATH)/src +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),FREEBSD) + INCLUDE_PATHS += -I/usr/local/include + LDFLAGS += -L. -Lsrc -L/usr/local/lib + endif +endif + ifeq ($(PLATFORM),PLATFORM_RPI) LDFLAGS += -L/opt/vc/lib endif @@ -177,56 +219,55 @@ endif # if you want to link libraries (libname.so or libname.a), use the -lname ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) - # Libraries for Windows desktop compiling - # NOTE: GLFW3 and OpenAL Soft libraries should be installed - LDLIBS = -lraylib -lglfw3 -lopengl32 -lgdi32 - - # Define required flags and libs for OpenAL Soft STATIC/SHARED usage - # NOTE: ALLIBS flag only required for raylib Win32 SHARED library building - ifeq ($(OPENAL_LIBTYPE),STATIC) - LDLIBS += -lopenal32 -lwinmm - CFLAGS += -DAL_LIBTYPE_STATIC -Wl,-allow-multiple-definition - else - LDLIBS += -lopenal32dll - endif + # Libraries for Windows desktop compilation + LDLIBS = -lraylib -lopengl32 -lgdi32 + + # Required for physac examples + #LDLIBS += -static -lpthread endif ifeq ($(PLATFORM_OS),LINUX) # Libraries for Debian GNU/Linux desktop compiling - # NOTE: Required packages: libglfw3-dev libopenal-dev libegl1-mesa-dev - LDLIBS = -lraylib -lglfw3 -lGL -lopenal -lm -lpthread -ldl + # NOTE: Required packages: libegl1-mesa-dev + LDLIBS = -lraylib -lGL -lm -lpthread -ldl -lrt - # On XWindow requires also below libraries - LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + # On X11 requires also below libraries + LDLIBS += -lX11 + # NOTE: It seems additional libraries are not required any more, latest GLFW just dlopen them + #LDLIBS += -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + + # On Wayland windowing system, additional libraries requires + ifeq ($(USE_WAYLAND_DISPLAY),TRUE) + LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon + endif endif ifeq ($(PLATFORM_OS),OSX) # Libraries for OSX 10.9 desktop compiling - # NOTE: Required packages: libglfw3-dev libopenal-dev libegl1-mesa-dev - LDLIBS = -lraylib -lglfw -framework OpenGL -framework OpenAL -framework Cocoa + # NOTE: Required packages: libopenal-dev libegl1-mesa-dev + LDLIBS = -lraylib -framework OpenGL -framework OpenAL -framework Cocoa + endif + ifeq ($(PLATFORM_OS),FREEBSD) + # Libraries for FreeBSD desktop compiling + # NOTE: Required packages: mesa-libs + LDLIBS = -lraylib -lGL -lpthread -lm + + # On XWindow requires also below libraries + LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + endif + ifeq ($(USE_EXTERNAL_GLFW),TRUE) + # NOTE: It could require additional packages installed: libglfw3-dev + LDLIBS += -lglfw endif endif ifeq ($(PLATFORM),PLATFORM_RPI) # Libraries for Raspberry Pi compiling - # NOTE: Required packages: libopenal1 - LDLIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal + # NOTE: Required packages: libasound2-dev (ALSA) + LDLIBS = -lraylib -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -ldl endif ifeq ($(PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling LDLIBS = $(RAYLIB_RELEASE)/libraylib.bc endif -# Define additional parameters and flags for windows -ifeq ($(PLATFORM_OS),WINDOWS) - # resources file contains raylib icon for windows .exe - # -Wl,--subsystem,windows hides the console window - WINFLAGS = $(RAYLIB_PATH)/src/resources -Wl,--subsystem,windows -endif - -# Define output extension to generate a .html file using provided shell -ifeq ($(PLATFORM),PLATFORM_WEB) - EXT = .html - WEB_SHELL = --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html -endif - # Define all source files required PROJECT_SOURCE_FILES ?= simple_game.c @@ -249,7 +290,7 @@ all: # Project target defined by PROJECT_NAME $(PROJECT_NAME): $(OBJS) - $(CC) -o $(PROJECT_NAME)$(EXT) $(OBJS) $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) $(WINFLAGS) + $(CC) -o $(PROJECT_NAME)$(EXT) $(OBJS) $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) # Compile source files # NOTE: This pattern will compile every module defined on $(OBJS) diff --git a/templates/simple_game/Makefile.Android b/templates/simple_game/Makefile.Android index 1c868454..2fda5372 100644 --- a/templates/simple_game/Makefile.Android +++ b/templates/simple_game/Makefile.Android @@ -101,7 +101,7 @@ LDFLAGS += -L. -L$(PROJECT_BUILD_PATH)/obj -L$(PROJECT_BUILD_PATH)/lib/armeabi-v # Define any libraries to link into executable # if you want to link libraries (libname.so or libname.a), use the -lname -LDLIBS = -lraylib -lnative_app_glue -lopenal -llog -landroid -lEGL -lGLESv2 -lOpenSLES -latomic -lc -lm -ldl +LDLIBS = -lraylib -lnative_app_glue -llog -landroid -lEGL -lGLESv2 -lOpenSLES -latomic -lc -lm -ldl # Generate target objects list from PROJECT_SOURCE_FILES OBJS = $(patsubst %.c, $(PROJECT_BUILD_PATH)/obj/%.o, $(PROJECT_SOURCE_FILES)) diff --git a/templates/simple_game/simple_game.c b/templates/simple_game/simple_game.c index 45b00dec..50859221 100644 --- a/templates/simple_game/simple_game.c +++ b/templates/simple_game/simple_game.c @@ -5,10 +5,10 @@ * * * -* This game has been created using raylib v1.2 (www.raylib.com) +* This game has been created using raylib (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/templates/standard_game/Makefile b/templates/standard_game/Makefile index 201012e8..17e254bb 100644 --- a/templates/standard_game/Makefile +++ b/templates/standard_game/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2017 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. @@ -26,19 +26,27 @@ # Define required raylib variables # WARNING: To compile to HTML5, code must be redesigned to use emscripten.h and emscripten_set_main_loop() PLATFORM ?= PLATFORM_DESKTOP -RAYLIB_PATH ?= ..\.. +RAYLIB_PATH = ..\.. PROJECT_NAME ?= standard_game -# Library type used for raylib and OpenAL Soft: STATIC (.a) or SHARED (.so/.dll) -# NOTE: Libraries should be provided in the selected form -RAYLIB_LIBTYPE ?= STATIC -OPENAL_LIBTYPE ?= STATIC - -# On PLATFORM_WEB force OpenAL Soft shared library -ifeq ($(PLATFORM),PLATFORM_WEB) - OPENAL_LIBTYPE = SHARED +# Default path for raylib on Raspberry Pi, if installed in different path, update it! +ifeq ($(PLATFORM),PLATFORM_RPI) + RAYLIB_PATH ?= /home/pi/raylib endif +# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) +RAYLIB_LIBTYPE ?= STATIC + +# Use external GLFW library instead of rglfw module +USE_EXTERNAL_GLFW ?= FALSE + +# Use Wayland display server protocol on Linux desktop +# by default it uses X11 windowing system +USE_WAYLAND_DISPLAY ?= FALSE + +# NOTE: On PLATFORM_WEB OpenAL Soft backend is used by default (check raylib/src/Makefile) + + # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected ifeq ($(PLATFORM),PLATFORM_DESKTOP) # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows @@ -50,12 +58,22 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(UNAMEOS),Linux) PLATFORM_OS=LINUX LIBPATH=linux - else + endif + UNAMEOS=$(shell uname) + ifeq ($(UNAMEOS),FreeBSD) + PLATFORM_OS=FREEBSD + LIBPATH=freebsd + endif ifeq ($(UNAMEOS),Darwin) PLATFORM_OS=OSX LIBPATH=osx endif - endif + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + UNAMEOS=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX endif endif @@ -67,8 +85,8 @@ endif ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH = C:/emsdk - EMSCRIPTEN_VERSION = 1.37.9 - CLANG_VERSION=e1.37.9_64bit + EMSCRIPTEN_VERSION = 1.37.28 + CLANG_VERSION=e1.37.28_64bit PYTHON_VERSION=2.7.5.3_64bit NODE_VERSION=4.1.1_64bit export PATH=$(EMSDK_PATH);$(EMSDK_PATH)\clang\$(CLANG_VERSION);$(EMSDK_PATH)\node\$(NODE_VERSION)\bin;$(EMSDK_PATH)\python\$(PYTHON_VERSION);$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION);C:\raylib\MinGW\bin:$$(PATH) @@ -86,6 +104,9 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),OSX) RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/osx endif + ifeq ($(PLATFORM_OS),FREEBSD) + RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/freebsd + endif endif ifeq ($(PLATFORM),PLATFORM_WEB) RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/html5 @@ -102,6 +123,10 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) # OSX default compiler CC = clang endif + ifeq ($(PLATFORM_OS),FREEBSD) + # FreeBSD default compiler + CC = clang + endif endif ifeq ($(PLATFORM),PLATFORM_RPI) ifeq ($(RPI_CROSS_COMPILE),YES) @@ -125,7 +150,7 @@ endif # Define compiler flags: # -O1 defines optimization level -# -Og enable debugging +# -g enable debugging # -s strip unnecessary data from build # -Wall turns on most, but not all, compiler warnings # -std=c99 defines C language mode (standard C from 1999 revision) @@ -138,6 +163,11 @@ CFLAGS += -O1 -s -Wall -std=c99 -D_DEFAULT_SOURCE -fgnu89-inline -Wno-missing-br # Additional flags for compiler (if desired) #CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),WINDOWS) + # resources file contains windows exe icon + # -Wl,--subsystem,windows hides the console window + CFLAGS += $(RAYLIB_PATH)/src/resources -Wl,--subsystem,windows + endif ifeq ($(PLATFORM_OS),LINUX) CFLAGS += -no-pie -D_DEFAULT_SOURCE endif @@ -151,7 +181,12 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing # -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) # -s USE_PTHREADS=1 # multithreading support - CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling -s TOTAL_MEMORY=16777216 --preload-file resources + # --preload-file resources # specify a resources folder for data compilation + CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling --preload-file resources + + # Define a custom shell .html and output extension + CFLAGS += --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html + EXT = .html endif # Define include paths for required headers @@ -169,6 +204,13 @@ endif # Define library paths containing required libs LDFLAGS = -L. -L$(RAYLIB_RELEASE) -L$(RAYLIB_PATH)/src +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),FREEBSD) + INCLUDE_PATHS += -I/usr/local/include + LDFLAGS += -L. -Lsrc -L/usr/local/lib + endif +endif + ifeq ($(PLATFORM),PLATFORM_RPI) LDFLAGS += -L/opt/vc/lib endif @@ -177,56 +219,55 @@ endif # if you want to link libraries (libname.so or libname.a), use the -lname ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) - # Libraries for Windows desktop compiling - # NOTE: GLFW3 and OpenAL Soft libraries should be installed - LDLIBS = -lraylib -lglfw3 -lopengl32 -lgdi32 - - # Define required flags and libs for OpenAL Soft STATIC/SHARED usage - # NOTE: ALLIBS flag only required for raylib Win32 SHARED library building - ifeq ($(OPENAL_LIBTYPE),STATIC) - LDLIBS += -lopenal32 -lwinmm - CFLAGS += -DAL_LIBTYPE_STATIC -Wl,-allow-multiple-definition - else - LDLIBS += -lopenal32dll - endif + # Libraries for Windows desktop compilation + LDLIBS = -lraylib -lopengl32 -lgdi32 + + # Required for physac examples + #LDLIBS += -static -lpthread endif ifeq ($(PLATFORM_OS),LINUX) # Libraries for Debian GNU/Linux desktop compiling - # NOTE: Required packages: libglfw3-dev libopenal-dev libegl1-mesa-dev - LDLIBS = -lraylib -lglfw3 -lGL -lopenal -lm -lpthread -ldl + # NOTE: Required packages: libegl1-mesa-dev + LDLIBS = -lraylib -lGL -lm -lpthread -ldl -lrt - # On XWindow requires also below libraries - LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + # On X11 requires also below libraries + LDLIBS += -lX11 + # NOTE: It seems additional libraries are not required any more, latest GLFW just dlopen them + #LDLIBS += -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + + # On Wayland windowing system, additional libraries requires + ifeq ($(USE_WAYLAND_DISPLAY),TRUE) + LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon + endif endif ifeq ($(PLATFORM_OS),OSX) # Libraries for OSX 10.9 desktop compiling - # NOTE: Required packages: libglfw3-dev libopenal-dev libegl1-mesa-dev - LDLIBS = -lraylib -lglfw -framework OpenGL -framework OpenAL -framework Cocoa + # NOTE: Required packages: libopenal-dev libegl1-mesa-dev + LDLIBS = -lraylib -framework OpenGL -framework OpenAL -framework Cocoa + endif + ifeq ($(PLATFORM_OS),FREEBSD) + # Libraries for FreeBSD desktop compiling + # NOTE: Required packages: mesa-libs + LDLIBS = -lraylib -lGL -lpthread -lm + + # On XWindow requires also below libraries + LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + endif + ifeq ($(USE_EXTERNAL_GLFW),TRUE) + # NOTE: It could require additional packages installed: libglfw3-dev + LDLIBS += -lglfw endif endif ifeq ($(PLATFORM),PLATFORM_RPI) # Libraries for Raspberry Pi compiling - # NOTE: Required packages: libopenal1 - LDLIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal + # NOTE: Required packages: libasound2-dev (ALSA) + LDLIBS = -lraylib -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -ldl endif ifeq ($(PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling LDLIBS = $(RAYLIB_RELEASE)/libraylib.bc endif -# Define additional parameters and flags for windows -ifeq ($(PLATFORM_OS),WINDOWS) - # resources file contains raylib icon for windows .exe - # -Wl,--subsystem,windows hides the console window - WINFLAGS = $(RAYLIB_PATH)/src/resources -Wl,--subsystem,windows -endif - -# Define output extension to generate a .html file using provided shell -ifeq ($(PLATFORM),PLATFORM_WEB) - EXT = .html - WEB_SHELL = --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html -endif - # Define all source files required PROJECT_SOURCE_FILES ?= standard_game.c \ screens/screen_logo.c \ @@ -254,7 +295,7 @@ all: # Project target defined by PROJECT_NAME $(PROJECT_NAME): $(OBJS) - $(CC) -o $(PROJECT_NAME)$(EXT) $(OBJS) $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) $(WINFLAGS) + $(CC) -o $(PROJECT_NAME)$(EXT) $(OBJS) $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) # Compile source files # NOTE: This pattern will compile every module defined on $(OBJS) diff --git a/templates/standard_game/Makefile.Android b/templates/standard_game/Makefile.Android index 1c868454..2fda5372 100644 --- a/templates/standard_game/Makefile.Android +++ b/templates/standard_game/Makefile.Android @@ -101,7 +101,7 @@ LDFLAGS += -L. -L$(PROJECT_BUILD_PATH)/obj -L$(PROJECT_BUILD_PATH)/lib/armeabi-v # Define any libraries to link into executable # if you want to link libraries (libname.so or libname.a), use the -lname -LDLIBS = -lraylib -lnative_app_glue -lopenal -llog -landroid -lEGL -lGLESv2 -lOpenSLES -latomic -lc -lm -ldl +LDLIBS = -lraylib -lnative_app_glue -llog -landroid -lEGL -lGLESv2 -lOpenSLES -latomic -lc -lm -ldl # Generate target objects list from PROJECT_SOURCE_FILES OBJS = $(patsubst %.c, $(PROJECT_BUILD_PATH)/obj/%.o, $(PROJECT_SOURCE_FILES)) diff --git a/templates/standard_game/screens/screen_ending.c b/templates/standard_game/screens/screen_ending.c index 56d37d12..87196977 100644 --- a/templates/standard_game/screens/screen_ending.c +++ b/templates/standard_game/screens/screen_ending.c @@ -4,7 +4,7 @@ * * Ending Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -51,7 +51,7 @@ void UpdateEndingScreen(void) { // TODO: Update ENDING screen variables here! - // Press enter to return to TITLE screen + // Press enter or tap to return to TITLE screen if (IsKeyPressed(KEY_ENTER) || IsGestureDetected(GESTURE_TAP)) { finishScreen = 1; diff --git a/templates/standard_game/screens/screen_gameplay.c b/templates/standard_game/screens/screen_gameplay.c index e64d6c5f..7f108265 100644 --- a/templates/standard_game/screens/screen_gameplay.c +++ b/templates/standard_game/screens/screen_gameplay.c @@ -4,7 +4,7 @@ * * Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -51,7 +51,7 @@ void UpdateGameplayScreen(void) { // TODO: Update GAMEPLAY screen variables here! - // Press enter to change to ENDING screen + // Press enter or tap to change to ENDING screen if (IsKeyPressed(KEY_ENTER) || IsGestureDetected(GESTURE_TAP)) { finishScreen = 1; diff --git a/templates/standard_game/screens/screen_logo.c b/templates/standard_game/screens/screen_logo.c index 2cfa0ca4..c0b60571 100644 --- a/templates/standard_game/screens/screen_logo.c +++ b/templates/standard_game/screens/screen_logo.c @@ -4,7 +4,7 @@ * * Logo Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/standard_game/screens/screen_options.c b/templates/standard_game/screens/screen_options.c index 9ac852d9..9f6690d1 100644 --- a/templates/standard_game/screens/screen_options.c +++ b/templates/standard_game/screens/screen_options.c @@ -4,7 +4,7 @@ * * Options Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/standard_game/screens/screen_title.c b/templates/standard_game/screens/screen_title.c index 67a51a0f..328448ba 100644 --- a/templates/standard_game/screens/screen_title.c +++ b/templates/standard_game/screens/screen_title.c @@ -4,7 +4,7 @@ * * Title Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -51,7 +51,7 @@ void UpdateTitleScreen(void) { // TODO: Update TITLE screen variables here! - // Press enter to change to GAMEPLAY screen + // Press enter or tap to change to GAMEPLAY screen if (IsKeyPressed(KEY_ENTER) || IsGestureDetected(GESTURE_TAP)) { //finishScreen = 1; // OPTIONS diff --git a/templates/standard_game/screens/screens.h b/templates/standard_game/screens/screens.h index 9d558508..e961b533 100644 --- a/templates/standard_game/screens/screens.h +++ b/templates/standard_game/screens/screens.h @@ -4,7 +4,7 @@ * * Screens Functions Declarations (Init, Update, Draw, Unload) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -29,7 +29,7 @@ //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -typedef enum GameScreen { LOGO, TITLE, OPTIONS, GAMEPLAY, ENDING } GameScreen; +typedef enum GameScreen { LOGO = 0, TITLE, OPTIONS, GAMEPLAY, ENDING } GameScreen; //---------------------------------------------------------------------------------- // Global Variables Definition diff --git a/templates/standard_game/standard_game.c b/templates/standard_game/standard_game.c index d8264f71..cf059451 100644 --- a/templates/standard_game/standard_game.c +++ b/templates/standard_game/standard_game.c @@ -8,12 +8,12 @@ * This game has been created using raylib (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" -#include "screens/screens.h" // NOTE: Defines currentScreen +#include "screens/screens.h" // NOTE: Defines global variable: currentScreen #if defined(PLATFORM_ANDROID) #include "android_native_app_glue.h" From 493a67e6d5847879c3ce0a4b8975d0c3d6270a74 Mon Sep 17 00:00:00 2001 From: - <-> Date: Mon, 15 Jan 2018 12:53:14 +0100 Subject: [PATCH 129/139] Support canvas scaling with window --- templates/web_shell/shell.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/web_shell/shell.html b/templates/web_shell/shell.html index de3fde45..4dfefb8d 100644 --- a/templates/web_shell/shell.html +++ b/templates/web_shell/shell.html @@ -58,7 +58,7 @@ div.emscripten_border { border: 1px solid black; } /* the canvas *must not* have any border or padding, or mouse coords will be wrong */ - canvas.emscripten { border: 0px none; background: black; } + canvas.emscripten { border: 0px none; background: black; width: 100% } #emscripten_logo { display: inline-block; From f2a675ae53321b5909e9324d3bb81250e704e4f2 Mon Sep 17 00:00:00 2001 From: - <-> Date: Mon, 15 Jan 2018 13:54:06 +0100 Subject: [PATCH 130/139] Reviewed Makefiles... - Renamed VERSION to RAYLIB_VERSION - Renamed API_VERSION to RAYLIB_API_VERSION - Renamed RAYLIB_RELEASE to RAYLIB_RELEASE_PATH - Support Web Assembly compilation on PLATFORM_WEB --- examples/Makefile | 47 +++++++++++----------- src/Makefile | 67 ++++++++++++++++---------------- templates/advance_game/Makefile | 46 ++++++++++------------ templates/simple_game/Makefile | 46 ++++++++++------------ templates/standard_game/Makefile | 46 ++++++++++------------ 5 files changed, 118 insertions(+), 134 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index a5acbf3a..7ca2dc60 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -49,24 +49,20 @@ USE_WAYLAND_DISPLAY ?= FALSE # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected ifeq ($(PLATFORM),PLATFORM_DESKTOP) - # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! + # ifeq ($(UNAME),Msys) -> Windows ifeq ($(OS),Windows_NT) PLATFORM_OS=WINDOWS - LIBPATH=win32 else UNAMEOS=$(shell uname) ifeq ($(UNAMEOS),Linux) PLATFORM_OS=LINUX - LIBPATH=linux endif - UNAMEOS=$(shell uname) ifeq ($(UNAMEOS),FreeBSD) PLATFORM_OS=FREEBSD - LIBPATH=freebsd endif ifeq ($(UNAMEOS),Darwin) PLATFORM_OS=OSX - LIBPATH=osx endif endif endif @@ -77,11 +73,6 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif endif -ifeq ($(PLATFORM),PLATFORM_RPI) - # RPI cross-compiler - RPI_CROSS_COMPILE ?= NO -endif - ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH = C:/emsdk @@ -93,29 +84,32 @@ ifeq ($(PLATFORM),PLATFORM_WEB) EMSCRIPTEN=$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION) endif +RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/release/libs + # Define raylib release directory for compiled library ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/win32/mingw32 + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/win32/mingw32 endif ifeq ($(PLATFORM_OS),LINUX) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/linux + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/linux endif ifeq ($(PLATFORM_OS),OSX) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/osx + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/osx endif ifeq ($(PLATFORM_OS),FREEBSD) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/freebsd + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/freebsd endif endif -ifeq ($(PLATFORM),PLATFORM_WEB) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/html5 -endif ifeq ($(PLATFORM),PLATFORM_RPI) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/rpi + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/rpi +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/html5 endif # Define default C compiler: gcc +# NOTE: define g++ compiler if using C++ CC = gcc ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -129,9 +123,10 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif endif ifeq ($(PLATFORM),PLATFORM_RPI) - ifeq ($(RPI_CROSS_COMPILE),YES) - # RPI cross-compiler - CC = armv6j-hardfloat-linux-gnueabi-gcc + ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) + # Define RPI cross-compiler + #CC = armv6j-hardfloat-linux-gnueabi-gcc + CC = $(RPI_TOOLCHAIN)/bin/arm-linux-gnueabihf-gcc endif endif ifeq ($(PLATFORM),PLATFORM_WEB) @@ -181,8 +176,9 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing # -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) # -s USE_PTHREADS=1 # multithreading support + # -s WASM=1 # support Web Assembly (https://github.com/kripken/emscripten/wiki/WebAssembly) # --preload-file resources # specify a resources folder for data compilation - CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling --preload-file resources + CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 --profiling --preload-file resources # Define a custom shell .html and output extension CFLAGS += --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html @@ -202,7 +198,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif # Define library paths containing required libs -LDFLAGS = -L. -L$(RAYLIB_RELEASE) -L$(RAYLIB_PATH)/src +LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),FREEBSD) @@ -254,6 +250,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor endif ifeq ($(USE_EXTERNAL_GLFW),TRUE) + # NOTE: It could require additional packages installed: libglfw3-dev LDLIBS += -lglfw endif endif @@ -264,7 +261,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif ifeq ($(PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling - LDLIBS = $(RAYLIB_RELEASE)/libraylib.bc + LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.bc endif # Define all object files required diff --git a/src/Makefile b/src/Makefile index 2ee9f909..fbab6725 100644 --- a/src/Makefile +++ b/src/Makefile @@ -36,19 +36,18 @@ # #****************************************************************************** -# Please read the wiki to know how to compile raylib, because there are -# different methods. +# Please read the wiki to know how to compile raylib, because there are different methods. +# https://github.com/raysan5/raylib/wiki .PHONY: all clean install uninstall # Define required raylib variables -VERSION = 1.9.2 -API_VERSION = 1 -PLATFORM ?= PLATFORM_DESKTOP -RAYLIB_PATH = .. - +PLATFORM ?= PLATFORM_DESKTOP +RAYLIB_PATH = .. +RAYLIB_VERSION = 1.9.2 +RAYLIB_API_VERSION = 1 # Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) -RAYLIB_LIBTYPE ?= STATIC +RAYLIB_LIBTYPE ?= STATIC # Included raylib audio module on compilation # NOTE: Some programs like tools could not require audio support @@ -120,8 +119,8 @@ endif ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH = C:/emsdk - EMSCRIPTEN_VERSION = 1.37.21 - CLANG_VERSION=e1.37.21_64bit + EMSCRIPTEN_VERSION = 1.37.28 + CLANG_VERSION=e1.37.28_64bit PYTHON_VERSION=2.7.5.3_64bit NODE_VERSION=4.1.1_64bit export PATH=$(EMSDK_PATH);$(EMSDK_PATH)\clang\$(CLANG_VERSION);$(EMSDK_PATH)\node\$(NODE_VERSION)\bin;$(EMSDK_PATH)\python\$(PYTHON_VERSION);$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION);C:\raylib\MinGW\bin:$$(PATH) @@ -192,7 +191,7 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID) GRAPHICS = GRAPHICS_API_OPENGL_ES2 endif -# Default C compiler: gcc +# Define default C compiler: gcc # NOTE: define g++ compiler if using C++ CC = gcc @@ -259,7 +258,7 @@ endif # -std=gnu99 defines C language mode (GNU C from 1999 revision) # -fgnu89-inline declaring inline functions support (GCC optimized) # -Wno-missing-braces ignore invalid warning (GCC bug 53119) -# -D_DEFAULT_SOURCE use with -std=c99 +# -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec CFLAGS += -O1 -Wall -std=c99 -D_DEFAULT_SOURCE -fgnu89-inline -Wno-missing-braces # Additional flags for compiler (if desired) @@ -406,30 +405,30 @@ else ifeq ($(PLATFORM_OS),LINUX) # Compile raylib to shared library version for GNU/Linux. # WARNING: you should type "make clean" before doing this target - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).so $(OBJS) -Wl,-soname,libraylib.$(API_VERSION).so -lGL -lm -lpthread -ldl -lrt - @echo "raylib shared library generated (libraylib.$(VERSION).so)!" - cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.$(API_VERSION).so - cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.so + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).so $(OBJS) -Wl,-soname,libraylib.$(RAYLIB_API_VERSION).so -lGL -lm -lpthread -ldl -lrt + @echo "raylib shared library generated (libraylib.$(RAYLIB_VERSION).so)!" + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).so libraylib.$(RAYLIB_API_VERSION).so + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).so libraylib.so endif ifeq ($(PLATFORM_OS),OSX) - $(CC) -dynamiclib -o $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).dylib $(OBJS) -compatibility_version $(API_VERSION) -current_version $(VERSION) -framework OpenGL -framework OpenAL -framework IOKit -framework CoreVideo -framework Cocoa - install_name_tool -id "libraylib.$(VERSION).dylib" $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).dylib - @echo "raylib shared library generated (libraylib.$(VERSION).dylib)!" - cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).dylib libraylib.$(API_VERSION).dylib - cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).dylib libraylib.dylib + $(CC) -dynamiclib -o $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).dylib $(OBJS) -compatibility_version $(RAYLIB_API_VERSION) -current_version $(RAYLIB_VERSION) -framework OpenGL -framework OpenAL -framework IOKit -framework CoreVideo -framework Cocoa + install_name_tool -id "libraylib.$(VERSION).dylib" $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).dylib + @echo "raylib shared library generated (libraylib.$(RAYLIB_VERSION).dylib)!" + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).dylib libraylib.$(RAYLIB_API_VERSION).dylib + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).dylib libraylib.dylib endif ifeq ($(PLATFORM_OS),FREEBSD) # WARNING: you should type "gmake clean" before doing this target - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).so $(OBJS) -Wl,-soname,libraylib.$(API_VERSION).so -lGL -lpthread - @echo "raylib shared library generated (libraylib.$(VERSION).so)!" - cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.$(API_VERSION).so - cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.so + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).so $(OBJS) -Wl,-soname,libraylib.$(RAYLIB_API_VERSION).so -lGL -lpthread + @echo "raylib shared library generated (libraylib.$(RAYLIB_VERSION).so)!" + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).so libraylib.$(RAYLIB_API_VERSION).so + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).so libraylib.so endif ifeq ($(PLATFORM),PLATFORM_ANDROID) - $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).so $(OBJS) $(LDFLAGS) $(LDLIBS) - @echo "raylib shared library generated (libraylib.$(VERSION).so)!" - cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.$(API_VERSION).so - cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(VERSION).so libraylib.so + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).so $(OBJS) $(LDFLAGS) $(LDLIBS) + @echo "raylib shared library generated (libraylib.$(RAYLIB_VERSION).so)!" + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).so libraylib.$(RAYLIB_API_VERSION).so + cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).so libraylib.so endif else # Compile raylib static library @@ -495,8 +494,8 @@ ifeq ($(ROOT),root) # /usr/local/include/) are for libraries that are installed # manually (without a package manager). ifeq ($(RAYLIB_LIBTYPE),SHARED) - cp --update $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).so /usr/local/lib/libraylib.$(VERSION).so - cp --update $(RAYLIB_RELEASE_PATH)/libraylib.$(API_VERSION).so /usr/local/lib/libraylib.$(API_VERSION).so + cp --update $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).so /usr/local/lib/libraylib.$(RAYLIB_VERSION).so + cp --update $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_API_VERSION).so /usr/local/lib/libraylib.$(RAYLIB_API_VERSION).so cp --update $(RAYLIB_RELEASE_PATH)/libraylib.so /usr/local/lib/libraylib.so else cp --update raylib.h /usr/local/include/raylib.h @@ -518,8 +517,8 @@ ifeq ($(ROOT),root) rm --force /usr/local/include/raylib.h ifeq ($(RAYLIB_LIBTYPE),SHARED) rm --force /usr/local/lib/libraylib.so - rm --force /usr/local/lib/libraylib.$(API_VERSION).so - rm --force /usr/local/lib/libraylib.$(VERSION).so + rm --force /usr/local/lib/libraylib.$(RAYLIB_API_VERSION).so + rm --force /usr/local/lib/libraylib.$(RAYLIB_VERSION).so else rm --force /usr/local/lib/libraylib.a endif @@ -536,7 +535,7 @@ clean: ifeq ($(PLATFORM_OS),WINDOWS) del *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so external/stb_vorbis.o else - rm -f *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so $(RAYLIB_RELEASE_PATH)/libraylib.$(API_VERSION).so $(RAYLIB_RELEASE_PATH)/libraylib.$(VERSION).so external/stb_vorbis.o + rm -f *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_API_VERSION).so $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).so external/stb_vorbis.o endif ifeq ($(PLATFORM),PLATFORM_ANDROID) rm -rf $(ANDROID_TOOLCHAIN) diff --git a/templates/advance_game/Makefile b/templates/advance_game/Makefile index 25bf78d4..0ebeb52e 100644 --- a/templates/advance_game/Makefile +++ b/templates/advance_game/Makefile @@ -49,24 +49,20 @@ USE_WAYLAND_DISPLAY ?= FALSE # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected ifeq ($(PLATFORM),PLATFORM_DESKTOP) - # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! + # ifeq ($(UNAME),Msys) -> Windows ifeq ($(OS),Windows_NT) PLATFORM_OS=WINDOWS - LIBPATH=win32 else UNAMEOS=$(shell uname) ifeq ($(UNAMEOS),Linux) PLATFORM_OS=LINUX - LIBPATH=linux endif - UNAMEOS=$(shell uname) ifeq ($(UNAMEOS),FreeBSD) PLATFORM_OS=FREEBSD - LIBPATH=freebsd endif ifeq ($(UNAMEOS),Darwin) PLATFORM_OS=OSX - LIBPATH=osx endif endif endif @@ -77,11 +73,6 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif endif -ifeq ($(PLATFORM),PLATFORM_RPI) - # RPI cross-compiler - RPI_CROSS_COMPILE ?= NO -endif - ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH = C:/emsdk @@ -93,29 +84,32 @@ ifeq ($(PLATFORM),PLATFORM_WEB) EMSCRIPTEN=$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION) endif +RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/release/libs + # Define raylib release directory for compiled library ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/win32/mingw32 + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/win32/mingw32 endif ifeq ($(PLATFORM_OS),LINUX) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/linux + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/linux endif ifeq ($(PLATFORM_OS),OSX) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/osx + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/osx endif ifeq ($(PLATFORM_OS),FREEBSD) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/freebsd + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/freebsd endif endif -ifeq ($(PLATFORM),PLATFORM_WEB) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/html5 -endif ifeq ($(PLATFORM),PLATFORM_RPI) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/rpi + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/rpi +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/html5 endif # Define default C compiler: gcc +# NOTE: define g++ compiler if using C++ CC = gcc ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -129,9 +123,10 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif endif ifeq ($(PLATFORM),PLATFORM_RPI) - ifeq ($(RPI_CROSS_COMPILE),YES) - # RPI cross-compiler - CC = armv6j-hardfloat-linux-gnueabi-gcc + ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) + # Define RPI cross-compiler + #CC = armv6j-hardfloat-linux-gnueabi-gcc + CC = $(RPI_TOOLCHAIN)/bin/arm-linux-gnueabihf-gcc endif endif ifeq ($(PLATFORM),PLATFORM_WEB) @@ -181,8 +176,9 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing # -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) # -s USE_PTHREADS=1 # multithreading support + # -s WASM=1 # support Web Assembly (https://github.com/kripken/emscripten/wiki/WebAssembly) # --preload-file resources # specify a resources folder for data compilation - CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling --preload-file resources + CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 --profiling --preload-file resources # Define a custom shell .html and output extension CFLAGS += --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html @@ -202,7 +198,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif # Define library paths containing required libs -LDFLAGS = -L. -L$(RAYLIB_RELEASE) -L$(RAYLIB_PATH)/src +LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),FREEBSD) @@ -265,7 +261,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif ifeq ($(PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling - LDLIBS = $(RAYLIB_RELEASE)/libraylib.bc + LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.bc endif # Define all source files required diff --git a/templates/simple_game/Makefile b/templates/simple_game/Makefile index 57fe53f8..23cd0619 100644 --- a/templates/simple_game/Makefile +++ b/templates/simple_game/Makefile @@ -49,24 +49,20 @@ USE_WAYLAND_DISPLAY ?= FALSE # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected ifeq ($(PLATFORM),PLATFORM_DESKTOP) - # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! + # ifeq ($(UNAME),Msys) -> Windows ifeq ($(OS),Windows_NT) PLATFORM_OS=WINDOWS - LIBPATH=win32 else UNAMEOS=$(shell uname) ifeq ($(UNAMEOS),Linux) PLATFORM_OS=LINUX - LIBPATH=linux endif - UNAMEOS=$(shell uname) ifeq ($(UNAMEOS),FreeBSD) PLATFORM_OS=FREEBSD - LIBPATH=freebsd endif ifeq ($(UNAMEOS),Darwin) PLATFORM_OS=OSX - LIBPATH=osx endif endif endif @@ -77,11 +73,6 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif endif -ifeq ($(PLATFORM),PLATFORM_RPI) - # RPI cross-compiler - RPI_CROSS_COMPILE ?= NO -endif - ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH = C:/emsdk @@ -93,29 +84,32 @@ ifeq ($(PLATFORM),PLATFORM_WEB) EMSCRIPTEN=$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION) endif +RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/release/libs + # Define raylib release directory for compiled library ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/win32/mingw32 + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/win32/mingw32 endif ifeq ($(PLATFORM_OS),LINUX) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/linux + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/linux endif ifeq ($(PLATFORM_OS),OSX) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/osx + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/osx endif ifeq ($(PLATFORM_OS),FREEBSD) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/freebsd + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/freebsd endif endif -ifeq ($(PLATFORM),PLATFORM_WEB) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/html5 -endif ifeq ($(PLATFORM),PLATFORM_RPI) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/rpi + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/rpi +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/html5 endif # Define default C compiler: gcc +# NOTE: define g++ compiler if using C++ CC = gcc ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -129,9 +123,10 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif endif ifeq ($(PLATFORM),PLATFORM_RPI) - ifeq ($(RPI_CROSS_COMPILE),YES) - # RPI cross-compiler - CC = armv6j-hardfloat-linux-gnueabi-gcc + ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) + # Define RPI cross-compiler + #CC = armv6j-hardfloat-linux-gnueabi-gcc + CC = $(RPI_TOOLCHAIN)/bin/arm-linux-gnueabihf-gcc endif endif ifeq ($(PLATFORM),PLATFORM_WEB) @@ -181,8 +176,9 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing # -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) # -s USE_PTHREADS=1 # multithreading support + # -s WASM=1 # support Web Assembly (https://github.com/kripken/emscripten/wiki/WebAssembly) # --preload-file resources # specify a resources folder for data compilation - CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling --preload-file resources + CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 --profiling --preload-file resources # Define a custom shell .html and output extension CFLAGS += --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html @@ -202,7 +198,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif # Define library paths containing required libs -LDFLAGS = -L. -L$(RAYLIB_RELEASE) -L$(RAYLIB_PATH)/src +LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),FREEBSD) @@ -265,7 +261,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif ifeq ($(PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling - LDLIBS = $(RAYLIB_RELEASE)/libraylib.bc + LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.bc endif # Define all source files required diff --git a/templates/standard_game/Makefile b/templates/standard_game/Makefile index 17e254bb..b3e9c82a 100644 --- a/templates/standard_game/Makefile +++ b/templates/standard_game/Makefile @@ -49,24 +49,20 @@ USE_WAYLAND_DISPLAY ?= FALSE # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected ifeq ($(PLATFORM),PLATFORM_DESKTOP) - # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! + # ifeq ($(UNAME),Msys) -> Windows ifeq ($(OS),Windows_NT) PLATFORM_OS=WINDOWS - LIBPATH=win32 else UNAMEOS=$(shell uname) ifeq ($(UNAMEOS),Linux) PLATFORM_OS=LINUX - LIBPATH=linux endif - UNAMEOS=$(shell uname) ifeq ($(UNAMEOS),FreeBSD) PLATFORM_OS=FREEBSD - LIBPATH=freebsd endif ifeq ($(UNAMEOS),Darwin) PLATFORM_OS=OSX - LIBPATH=osx endif endif endif @@ -77,11 +73,6 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif endif -ifeq ($(PLATFORM),PLATFORM_RPI) - # RPI cross-compiler - RPI_CROSS_COMPILE ?= NO -endif - ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH = C:/emsdk @@ -93,29 +84,32 @@ ifeq ($(PLATFORM),PLATFORM_WEB) EMSCRIPTEN=$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION) endif +RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/release/libs + # Define raylib release directory for compiled library ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/win32/mingw32 + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/win32/mingw32 endif ifeq ($(PLATFORM_OS),LINUX) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/linux + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/linux endif ifeq ($(PLATFORM_OS),OSX) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/osx + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/osx endif ifeq ($(PLATFORM_OS),FREEBSD) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/freebsd + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/freebsd endif endif -ifeq ($(PLATFORM),PLATFORM_WEB) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/html5 -endif ifeq ($(PLATFORM),PLATFORM_RPI) - RAYLIB_RELEASE = $(RAYLIB_PATH)/release/libs/rpi + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/rpi +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + RAYLIB_RELEASE_PATH = $(RAYLIB_PATH)/release/libs/html5 endif # Define default C compiler: gcc +# NOTE: define g++ compiler if using C++ CC = gcc ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -129,9 +123,10 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif endif ifeq ($(PLATFORM),PLATFORM_RPI) - ifeq ($(RPI_CROSS_COMPILE),YES) - # RPI cross-compiler - CC = armv6j-hardfloat-linux-gnueabi-gcc + ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) + # Define RPI cross-compiler + #CC = armv6j-hardfloat-linux-gnueabi-gcc + CC = $(RPI_TOOLCHAIN)/bin/arm-linux-gnueabihf-gcc endif endif ifeq ($(PLATFORM),PLATFORM_WEB) @@ -181,8 +176,9 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing # -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) # -s USE_PTHREADS=1 # multithreading support + # -s WASM=1 # support Web Assembly (https://github.com/kripken/emscripten/wiki/WebAssembly) # --preload-file resources # specify a resources folder for data compilation - CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling --preload-file resources + CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 --profiling --preload-file resources # Define a custom shell .html and output extension CFLAGS += --shell-file $(RAYLIB_PATH)\templates\web_shell\shell.html @@ -202,7 +198,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif # Define library paths containing required libs -LDFLAGS = -L. -L$(RAYLIB_RELEASE) -L$(RAYLIB_PATH)/src +LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),FREEBSD) @@ -265,7 +261,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif ifeq ($(PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling - LDLIBS = $(RAYLIB_RELEASE)/libraylib.bc + LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.bc endif # Define all source files required From 230e78a23e3482aaa3e16f56ade3c940712d1272 Mon Sep 17 00:00:00 2001 From: - <-> Date: Mon, 15 Jan 2018 13:54:25 +0100 Subject: [PATCH 131/139] Code tweak while using OpenAL backend --- src/audio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/audio.c b/src/audio.c index 17b8ea22..052d4d3c 100644 --- a/src/audio.c +++ b/src/audio.c @@ -1114,6 +1114,7 @@ void SetSoundPitch(Sound sound, float pitch) // Convert wave data to desired format void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) { +#if USE_MINI_AL mal_format formatIn = ((wave->sampleSize == 8) ? mal_format_u8 : ((wave->sampleSize == 16) ? mal_format_s16 : mal_format_f32)); mal_format formatOut = (( sampleSize == 8) ? mal_format_u8 : (( sampleSize == 16) ? mal_format_s16 : mal_format_f32)); @@ -1142,7 +1143,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) free(wave->data); wave->data = data; -#if 0 +#else // Format sample rate // NOTE: Only supported 22050 <--> 44100 if (wave->sampleRate != sampleRate) From 61679a4bbc1c240a271d53cad54c635e83c466b0 Mon Sep 17 00:00:00 2001 From: - <-> Date: Mon, 15 Jan 2018 13:59:51 +0100 Subject: [PATCH 132/139] Review releases, removed external dependencies Not required any more! --- release/include/GLFW/glfw3.h | 4235 ----------------- release/include/GLFW/glfw3native.h | 456 -- release/include/raylib.h | 190 +- release/libs/android/armeabi-v7a/libopenal.a | Bin 1207292 -> 0 bytes release/libs/android/armeabi-v7a/libopenal.so | Bin 861680 -> 0 bytes release/libs/android/armeabi-v7a/libraylib.a | Bin 760182 -> 858612 bytes release/libs/html5/libraylib.bc | Bin 763552 -> 742584 bytes release/libs/linux/ADDLIBS | 0 release/libs/linux/libglfw3.a | Bin 176482 -> 0 bytes release/libs/linux/libraylib.a | Bin 0 -> 1413590 bytes release/libs/osx/ADDLIBS | 0 release/libs/osx/libglfw.3.0.dylib | Bin 127856 -> 0 bytes release/libs/osx/libglfw.3.dylib | 1 - release/libs/osx/libglfw.dylib | 1 - release/libs/osx/libraylib.a | Bin 0 -> 1088584 bytes release/libs/osx/libraylib.dylib | Bin 0 -> 874040 bytes release/libs/win32/mingw32/OpenAL32.dll | Bin 832000 -> 0 bytes release/libs/win32/mingw32/glfw3.dll | Bin 305452 -> 0 bytes release/libs/win32/mingw32/glfw3.lib | Bin 245676 -> 0 bytes release/libs/win32/mingw32/libOpenAL32.a | Bin 985812 -> 0 bytes release/libs/win32/mingw32/libOpenAL32dll.a | Bin 101606 -> 0 bytes release/libs/win32/mingw32/libglfw3.a | Bin 148800 -> 0 bytes release/libs/win32/mingw32/libglfw3dll.a | Bin 67426 -> 0 bytes release/libs/win32/mingw32/libraylib.a | Bin 958986 -> 973406 bytes release/libs/win32/msvc/OpenAL32.dll | Bin 731648 -> 0 bytes release/libs/win32/msvc/OpenAL32dll.lib | Bin 34440 -> 0 bytes release/libs/win32/msvc/glfw3.dll | Bin 71680 -> 0 bytes release/libs/win32/msvc/glfw3.lib | Bin 245676 -> 0 bytes release/libs/win32/msvc/glfw3dll.lib | Bin 24454 -> 0 bytes 29 files changed, 79 insertions(+), 4804 deletions(-) delete mode 100644 release/include/GLFW/glfw3.h delete mode 100644 release/include/GLFW/glfw3native.h delete mode 100644 release/libs/android/armeabi-v7a/libopenal.a delete mode 100644 release/libs/android/armeabi-v7a/libopenal.so delete mode 100644 release/libs/linux/ADDLIBS delete mode 100644 release/libs/linux/libglfw3.a create mode 100644 release/libs/linux/libraylib.a delete mode 100644 release/libs/osx/ADDLIBS delete mode 100644 release/libs/osx/libglfw.3.0.dylib delete mode 100644 release/libs/osx/libglfw.3.dylib delete mode 100644 release/libs/osx/libglfw.dylib create mode 100644 release/libs/osx/libraylib.a create mode 100644 release/libs/osx/libraylib.dylib delete mode 100644 release/libs/win32/mingw32/OpenAL32.dll delete mode 100644 release/libs/win32/mingw32/glfw3.dll delete mode 100644 release/libs/win32/mingw32/glfw3.lib delete mode 100644 release/libs/win32/mingw32/libOpenAL32.a delete mode 100644 release/libs/win32/mingw32/libOpenAL32dll.a delete mode 100644 release/libs/win32/mingw32/libglfw3.a delete mode 100644 release/libs/win32/mingw32/libglfw3dll.a delete mode 100644 release/libs/win32/msvc/OpenAL32.dll delete mode 100644 release/libs/win32/msvc/OpenAL32dll.lib delete mode 100644 release/libs/win32/msvc/glfw3.dll delete mode 100644 release/libs/win32/msvc/glfw3.lib delete mode 100644 release/libs/win32/msvc/glfw3dll.lib diff --git a/release/include/GLFW/glfw3.h b/release/include/GLFW/glfw3.h deleted file mode 100644 index 5a0c4508..00000000 --- a/release/include/GLFW/glfw3.h +++ /dev/null @@ -1,4235 +0,0 @@ -/************************************************************************* - * GLFW 3.2 - www.glfw.org - * A library for OpenGL, window and input - *------------------------------------------------------------------------ - * Copyright (c) 2002-2006 Marcus Geelnard - * Copyright (c) 2006-2016 Camilla Berglund - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would - * be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - * - *************************************************************************/ - -#ifndef _glfw3_h_ -#define _glfw3_h_ - -#ifdef __cplusplus -extern "C" { -#endif - - -/************************************************************************* - * Doxygen documentation - *************************************************************************/ - -/*! @file glfw3.h - * @brief The header of the GLFW 3 API. - * - * This is the header file of the GLFW 3 API. It defines all its types and - * declares all its functions. - * - * For more information about how to use this file, see @ref build_include. - */ -/*! @defgroup context Context reference - * - * This is the reference documentation for OpenGL and OpenGL ES context related - * functions. For more task-oriented information, see the @ref context_guide. - */ -/*! @defgroup vulkan Vulkan reference - * - * This is the reference documentation for Vulkan related functions and types. - * For more task-oriented information, see the @ref vulkan_guide. - */ -/*! @defgroup init Initialization, version and error reference - * - * This is the reference documentation for initialization and termination of - * the library, version management and error handling. For more task-oriented - * information, see the @ref intro_guide. - */ -/*! @defgroup input Input reference - * - * This is the reference documentation for input related functions and types. - * For more task-oriented information, see the @ref input_guide. - */ -/*! @defgroup monitor Monitor reference - * - * This is the reference documentation for monitor related functions and types. - * For more task-oriented information, see the @ref monitor_guide. - */ -/*! @defgroup window Window reference - * - * This is the reference documentation for window related functions and types, - * including creation, deletion and event polling. For more task-oriented - * information, see the @ref window_guide. - */ - - -/************************************************************************* - * Compiler- and platform-specific preprocessor work - *************************************************************************/ - -/* If we are we on Windows, we want a single define for it. - */ -#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)) - #define _WIN32 -#endif /* _WIN32 */ - -/* It is customary to use APIENTRY for OpenGL function pointer declarations on - * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. - */ -#ifndef APIENTRY - #ifdef _WIN32 - #define APIENTRY __stdcall - #else - #define APIENTRY - #endif -#endif /* APIENTRY */ - -/* Some Windows OpenGL headers need this. - */ -#if !defined(WINGDIAPI) && defined(_WIN32) - #define WINGDIAPI __declspec(dllimport) - #define GLFW_WINGDIAPI_DEFINED -#endif /* WINGDIAPI */ - -/* Some Windows GLU headers need this. - */ -#if !defined(CALLBACK) && defined(_WIN32) - #define CALLBACK __stdcall - #define GLFW_CALLBACK_DEFINED -#endif /* CALLBACK */ - -/* Most Windows GLU headers need wchar_t. - * The OS X OpenGL header blocks the definition of ptrdiff_t by glext.h. - * Include it unconditionally to avoid surprising side-effects. - */ -#include -#include - -/* Include the chosen client API headers. - */ -#if defined(__APPLE__) - #if defined(GLFW_INCLUDE_GLCOREARB) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif !defined(GLFW_INCLUDE_NONE) - #if !defined(GLFW_INCLUDE_GLEXT) - #define GL_GLEXT_LEGACY - #endif - #include - #endif - #if defined(GLFW_INCLUDE_GLU) - #include - #endif -#else - #if defined(GLFW_INCLUDE_GLCOREARB) - #include - #elif defined(GLFW_INCLUDE_ES1) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_ES2) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_ES3) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_ES31) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #elif defined(GLFW_INCLUDE_VULKAN) - #include - #elif !defined(GLFW_INCLUDE_NONE) - #include - #if defined(GLFW_INCLUDE_GLEXT) - #include - #endif - #endif - #if defined(GLFW_INCLUDE_GLU) - #include - #endif -#endif - -#if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) - /* GLFW_DLL must be defined by applications that are linking against the DLL - * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW - * configuration header when compiling the DLL version of the library. - */ - #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined" -#endif - -/* GLFWAPI is used to declare public API functions for export - * from the DLL / shared library / dynamic library. - */ -#if defined(_WIN32) && defined(_GLFW_BUILD_DLL) - /* We are building GLFW as a Win32 DLL */ - #define GLFWAPI __declspec(dllexport) -#elif defined(_WIN32) && defined(GLFW_DLL) - /* We are calling GLFW as a Win32 DLL */ - #define GLFWAPI __declspec(dllimport) -#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) - /* We are building GLFW as a shared / dynamic library */ - #define GLFWAPI __attribute__((visibility("default"))) -#else - /* We are building or calling GLFW as a static library */ - #define GLFWAPI -#endif - - -/************************************************************************* - * GLFW API tokens - *************************************************************************/ - -/*! @name GLFW version macros - * @{ */ -/*! @brief The major version number of the GLFW library. - * - * This is incremented when the API is changed in non-compatible ways. - * @ingroup init - */ -#define GLFW_VERSION_MAJOR 3 -/*! @brief The minor version number of the GLFW library. - * - * This is incremented when features are added to the API but it remains - * backward-compatible. - * @ingroup init - */ -#define GLFW_VERSION_MINOR 2 -/*! @brief The revision number of the GLFW library. - * - * This is incremented when a bug fix release is made that does not contain any - * API changes. - * @ingroup init - */ -#define GLFW_VERSION_REVISION 0 -/*! @} */ - -/*! @name Boolean values - * @{ */ -/*! @brief One. - * - * One. Seriously. You don't _need_ to use this symbol in your code. It's - * just semantic sugar for the number 1. You can use `1` or `true` or `_True` - * or `GL_TRUE` or whatever you want. - */ -#define GLFW_TRUE 1 -/*! @brief Zero. - * - * Zero. Seriously. You don't _need_ to use this symbol in your code. It's - * just just semantic sugar for the number 0. You can use `0` or `false` or - * `_False` or `GL_FALSE` or whatever you want. - */ -#define GLFW_FALSE 0 -/*! @} */ - -/*! @name Key and button actions - * @{ */ -/*! @brief The key or mouse button was released. - * - * The key or mouse button was released. - * - * @ingroup input - */ -#define GLFW_RELEASE 0 -/*! @brief The key or mouse button was pressed. - * - * The key or mouse button was pressed. - * - * @ingroup input - */ -#define GLFW_PRESS 1 -/*! @brief The key was held down until it repeated. - * - * The key was held down until it repeated. - * - * @ingroup input - */ -#define GLFW_REPEAT 2 -/*! @} */ - -/*! @defgroup keys Keyboard keys - * - * See [key input](@ref input_key) for how these are used. - * - * These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60), - * but re-arranged to map to 7-bit ASCII for printable keys (function keys are - * put in the 256+ range). - * - * The naming of the key codes follow these rules: - * - The US keyboard layout is used - * - Names of printable alpha-numeric characters are used (e.g. "A", "R", - * "3", etc.) - * - For non-alphanumeric characters, Unicode:ish names are used (e.g. - * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not - * correspond to the Unicode standard (usually for brevity) - * - Keys that lack a clear US mapping are named "WORLD_x" - * - For non-printable keys, custom names are used (e.g. "F4", - * "BACKSPACE", etc.) - * - * @ingroup input - * @{ - */ - -/* The unknown key */ -#define GLFW_KEY_UNKNOWN -1 - -/* Printable keys */ -#define GLFW_KEY_SPACE 32 -#define GLFW_KEY_APOSTROPHE 39 /* ' */ -#define GLFW_KEY_COMMA 44 /* , */ -#define GLFW_KEY_MINUS 45 /* - */ -#define GLFW_KEY_PERIOD 46 /* . */ -#define GLFW_KEY_SLASH 47 /* / */ -#define GLFW_KEY_0 48 -#define GLFW_KEY_1 49 -#define GLFW_KEY_2 50 -#define GLFW_KEY_3 51 -#define GLFW_KEY_4 52 -#define GLFW_KEY_5 53 -#define GLFW_KEY_6 54 -#define GLFW_KEY_7 55 -#define GLFW_KEY_8 56 -#define GLFW_KEY_9 57 -#define GLFW_KEY_SEMICOLON 59 /* ; */ -#define GLFW_KEY_EQUAL 61 /* = */ -#define GLFW_KEY_A 65 -#define GLFW_KEY_B 66 -#define GLFW_KEY_C 67 -#define GLFW_KEY_D 68 -#define GLFW_KEY_E 69 -#define GLFW_KEY_F 70 -#define GLFW_KEY_G 71 -#define GLFW_KEY_H 72 -#define GLFW_KEY_I 73 -#define GLFW_KEY_J 74 -#define GLFW_KEY_K 75 -#define GLFW_KEY_L 76 -#define GLFW_KEY_M 77 -#define GLFW_KEY_N 78 -#define GLFW_KEY_O 79 -#define GLFW_KEY_P 80 -#define GLFW_KEY_Q 81 -#define GLFW_KEY_R 82 -#define GLFW_KEY_S 83 -#define GLFW_KEY_T 84 -#define GLFW_KEY_U 85 -#define GLFW_KEY_V 86 -#define GLFW_KEY_W 87 -#define GLFW_KEY_X 88 -#define GLFW_KEY_Y 89 -#define GLFW_KEY_Z 90 -#define GLFW_KEY_LEFT_BRACKET 91 /* [ */ -#define GLFW_KEY_BACKSLASH 92 /* \ */ -#define GLFW_KEY_RIGHT_BRACKET 93 /* ] */ -#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */ -#define GLFW_KEY_WORLD_1 161 /* non-US #1 */ -#define GLFW_KEY_WORLD_2 162 /* non-US #2 */ - -/* Function keys */ -#define GLFW_KEY_ESCAPE 256 -#define GLFW_KEY_ENTER 257 -#define GLFW_KEY_TAB 258 -#define GLFW_KEY_BACKSPACE 259 -#define GLFW_KEY_INSERT 260 -#define GLFW_KEY_DELETE 261 -#define GLFW_KEY_RIGHT 262 -#define GLFW_KEY_LEFT 263 -#define GLFW_KEY_DOWN 264 -#define GLFW_KEY_UP 265 -#define GLFW_KEY_PAGE_UP 266 -#define GLFW_KEY_PAGE_DOWN 267 -#define GLFW_KEY_HOME 268 -#define GLFW_KEY_END 269 -#define GLFW_KEY_CAPS_LOCK 280 -#define GLFW_KEY_SCROLL_LOCK 281 -#define GLFW_KEY_NUM_LOCK 282 -#define GLFW_KEY_PRINT_SCREEN 283 -#define GLFW_KEY_PAUSE 284 -#define GLFW_KEY_F1 290 -#define GLFW_KEY_F2 291 -#define GLFW_KEY_F3 292 -#define GLFW_KEY_F4 293 -#define GLFW_KEY_F5 294 -#define GLFW_KEY_F6 295 -#define GLFW_KEY_F7 296 -#define GLFW_KEY_F8 297 -#define GLFW_KEY_F9 298 -#define GLFW_KEY_F10 299 -#define GLFW_KEY_F11 300 -#define GLFW_KEY_F12 301 -#define GLFW_KEY_F13 302 -#define GLFW_KEY_F14 303 -#define GLFW_KEY_F15 304 -#define GLFW_KEY_F16 305 -#define GLFW_KEY_F17 306 -#define GLFW_KEY_F18 307 -#define GLFW_KEY_F19 308 -#define GLFW_KEY_F20 309 -#define GLFW_KEY_F21 310 -#define GLFW_KEY_F22 311 -#define GLFW_KEY_F23 312 -#define GLFW_KEY_F24 313 -#define GLFW_KEY_F25 314 -#define GLFW_KEY_KP_0 320 -#define GLFW_KEY_KP_1 321 -#define GLFW_KEY_KP_2 322 -#define GLFW_KEY_KP_3 323 -#define GLFW_KEY_KP_4 324 -#define GLFW_KEY_KP_5 325 -#define GLFW_KEY_KP_6 326 -#define GLFW_KEY_KP_7 327 -#define GLFW_KEY_KP_8 328 -#define GLFW_KEY_KP_9 329 -#define GLFW_KEY_KP_DECIMAL 330 -#define GLFW_KEY_KP_DIVIDE 331 -#define GLFW_KEY_KP_MULTIPLY 332 -#define GLFW_KEY_KP_SUBTRACT 333 -#define GLFW_KEY_KP_ADD 334 -#define GLFW_KEY_KP_ENTER 335 -#define GLFW_KEY_KP_EQUAL 336 -#define GLFW_KEY_LEFT_SHIFT 340 -#define GLFW_KEY_LEFT_CONTROL 341 -#define GLFW_KEY_LEFT_ALT 342 -#define GLFW_KEY_LEFT_SUPER 343 -#define GLFW_KEY_RIGHT_SHIFT 344 -#define GLFW_KEY_RIGHT_CONTROL 345 -#define GLFW_KEY_RIGHT_ALT 346 -#define GLFW_KEY_RIGHT_SUPER 347 -#define GLFW_KEY_MENU 348 - -#define GLFW_KEY_LAST GLFW_KEY_MENU - -/*! @} */ - -/*! @defgroup mods Modifier key flags - * - * See [key input](@ref input_key) for how these are used. - * - * @ingroup input - * @{ */ - -/*! @brief If this bit is set one or more Shift keys were held down. - */ -#define GLFW_MOD_SHIFT 0x0001 -/*! @brief If this bit is set one or more Control keys were held down. - */ -#define GLFW_MOD_CONTROL 0x0002 -/*! @brief If this bit is set one or more Alt keys were held down. - */ -#define GLFW_MOD_ALT 0x0004 -/*! @brief If this bit is set one or more Super keys were held down. - */ -#define GLFW_MOD_SUPER 0x0008 - -/*! @} */ - -/*! @defgroup buttons Mouse buttons - * - * See [mouse button input](@ref input_mouse_button) for how these are used. - * - * @ingroup input - * @{ */ -#define GLFW_MOUSE_BUTTON_1 0 -#define GLFW_MOUSE_BUTTON_2 1 -#define GLFW_MOUSE_BUTTON_3 2 -#define GLFW_MOUSE_BUTTON_4 3 -#define GLFW_MOUSE_BUTTON_5 4 -#define GLFW_MOUSE_BUTTON_6 5 -#define GLFW_MOUSE_BUTTON_7 6 -#define GLFW_MOUSE_BUTTON_8 7 -#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8 -#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1 -#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2 -#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3 -/*! @} */ - -/*! @defgroup joysticks Joysticks - * - * See [joystick input](@ref joystick) for how these are used. - * - * @ingroup input - * @{ */ -#define GLFW_JOYSTICK_1 0 -#define GLFW_JOYSTICK_2 1 -#define GLFW_JOYSTICK_3 2 -#define GLFW_JOYSTICK_4 3 -#define GLFW_JOYSTICK_5 4 -#define GLFW_JOYSTICK_6 5 -#define GLFW_JOYSTICK_7 6 -#define GLFW_JOYSTICK_8 7 -#define GLFW_JOYSTICK_9 8 -#define GLFW_JOYSTICK_10 9 -#define GLFW_JOYSTICK_11 10 -#define GLFW_JOYSTICK_12 11 -#define GLFW_JOYSTICK_13 12 -#define GLFW_JOYSTICK_14 13 -#define GLFW_JOYSTICK_15 14 -#define GLFW_JOYSTICK_16 15 -#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16 -/*! @} */ - -/*! @defgroup errors Error codes - * - * See [error handling](@ref error_handling) for how these are used. - * - * @ingroup init - * @{ */ -/*! @brief GLFW has not been initialized. - * - * This occurs if a GLFW function was called that must not be called unless the - * library is [initialized](@ref intro_init). - * - * @analysis Application programmer error. Initialize GLFW before calling any - * function that requires initialization. - */ -#define GLFW_NOT_INITIALIZED 0x00010001 -/*! @brief No context is current for this thread. - * - * This occurs if a GLFW function was called that needs and operates on the - * current OpenGL or OpenGL ES context but no context is current on the calling - * thread. One such function is @ref glfwSwapInterval. - * - * @analysis Application programmer error. Ensure a context is current before - * calling functions that require a current context. - */ -#define GLFW_NO_CURRENT_CONTEXT 0x00010002 -/*! @brief One of the arguments to the function was an invalid enum value. - * - * One of the arguments to the function was an invalid enum value, for example - * requesting [GLFW_RED_BITS](@ref window_hints_fb) with @ref - * glfwGetWindowAttrib. - * - * @analysis Application programmer error. Fix the offending call. - */ -#define GLFW_INVALID_ENUM 0x00010003 -/*! @brief One of the arguments to the function was an invalid value. - * - * One of the arguments to the function was an invalid value, for example - * requesting a non-existent OpenGL or OpenGL ES version like 2.7. - * - * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead - * result in a @ref GLFW_VERSION_UNAVAILABLE error. - * - * @analysis Application programmer error. Fix the offending call. - */ -#define GLFW_INVALID_VALUE 0x00010004 -/*! @brief A memory allocation failed. - * - * A memory allocation failed. - * - * @analysis A bug in GLFW or the underlying operating system. Report the bug - * to our [issue tracker](https://github.com/glfw/glfw/issues). - */ -#define GLFW_OUT_OF_MEMORY 0x00010005 -/*! @brief GLFW could not find support for the requested API on the system. - * - * GLFW could not find support for the requested API on the system. - * - * @analysis The installed graphics driver does not support the requested - * API, or does not support it via the chosen context creation backend. - * Below are a few examples. - * - * @par - * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only - * supports OpenGL ES via EGL, while Nvidia and Intel only support it via - * a WGL or GLX extension. OS X does not provide OpenGL ES at all. The Mesa - * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary - * driver. Older graphics drivers do not support Vulkan. - */ -#define GLFW_API_UNAVAILABLE 0x00010006 -/*! @brief The requested OpenGL or OpenGL ES version is not available. - * - * The requested OpenGL or OpenGL ES version (including any requested context - * or framebuffer hints) is not available on this machine. - * - * @analysis The machine does not support your requirements. If your - * application is sufficiently flexible, downgrade your requirements and try - * again. Otherwise, inform the user that their machine does not match your - * requirements. - * - * @par - * Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 - * comes out before the 4.x series gets that far, also fail with this error and - * not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions - * will exist. - */ -#define GLFW_VERSION_UNAVAILABLE 0x00010007 -/*! @brief A platform-specific error occurred that does not match any of the - * more specific categories. - * - * A platform-specific error occurred that does not match any of the more - * specific categories. - * - * @analysis A bug or configuration error in GLFW, the underlying operating - * system or its drivers, or a lack of required resources. Report the issue to - * our [issue tracker](https://github.com/glfw/glfw/issues). - */ -#define GLFW_PLATFORM_ERROR 0x00010008 -/*! @brief The requested format is not supported or available. - * - * If emitted during window creation, the requested pixel format is not - * supported. - * - * If emitted when querying the clipboard, the contents of the clipboard could - * not be converted to the requested format. - * - * @analysis If emitted during window creation, one or more - * [hard constraints](@ref window_hints_hard) did not match any of the - * available pixel formats. If your application is sufficiently flexible, - * downgrade your requirements and try again. Otherwise, inform the user that - * their machine does not match your requirements. - * - * @par - * If emitted when querying the clipboard, ignore the error or report it to - * the user, as appropriate. - */ -#define GLFW_FORMAT_UNAVAILABLE 0x00010009 -/*! @brief The specified window does not have an OpenGL or OpenGL ES context. - * - * A window that does not have an OpenGL or OpenGL ES context was passed to - * a function that requires it to have one. - * - * @analysis Application programmer error. Fix the offending call. - */ -#define GLFW_NO_WINDOW_CONTEXT 0x0001000A -/*! @} */ - -#define GLFW_FOCUSED 0x00020001 -#define GLFW_ICONIFIED 0x00020002 -#define GLFW_RESIZABLE 0x00020003 -#define GLFW_VISIBLE 0x00020004 -#define GLFW_DECORATED 0x00020005 -#define GLFW_AUTO_ICONIFY 0x00020006 -#define GLFW_FLOATING 0x00020007 -#define GLFW_MAXIMIZED 0x00020008 - -#define GLFW_RED_BITS 0x00021001 -#define GLFW_GREEN_BITS 0x00021002 -#define GLFW_BLUE_BITS 0x00021003 -#define GLFW_ALPHA_BITS 0x00021004 -#define GLFW_DEPTH_BITS 0x00021005 -#define GLFW_STENCIL_BITS 0x00021006 -#define GLFW_ACCUM_RED_BITS 0x00021007 -#define GLFW_ACCUM_GREEN_BITS 0x00021008 -#define GLFW_ACCUM_BLUE_BITS 0x00021009 -#define GLFW_ACCUM_ALPHA_BITS 0x0002100A -#define GLFW_AUX_BUFFERS 0x0002100B -#define GLFW_STEREO 0x0002100C -#define GLFW_SAMPLES 0x0002100D -#define GLFW_SRGB_CAPABLE 0x0002100E -#define GLFW_REFRESH_RATE 0x0002100F -#define GLFW_DOUBLEBUFFER 0x00021010 - -#define GLFW_CLIENT_API 0x00022001 -#define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 -#define GLFW_CONTEXT_VERSION_MINOR 0x00022003 -#define GLFW_CONTEXT_REVISION 0x00022004 -#define GLFW_CONTEXT_ROBUSTNESS 0x00022005 -#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 -#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 -#define GLFW_OPENGL_PROFILE 0x00022008 -#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 -#define GLFW_CONTEXT_NO_ERROR 0x0002200A -#define GLFW_CONTEXT_CREATION_API 0x0002200B - -#define GLFW_NO_API 0 -#define GLFW_OPENGL_API 0x00030001 -#define GLFW_OPENGL_ES_API 0x00030002 - -#define GLFW_NO_ROBUSTNESS 0 -#define GLFW_NO_RESET_NOTIFICATION 0x00031001 -#define GLFW_LOSE_CONTEXT_ON_RESET 0x00031002 - -#define GLFW_OPENGL_ANY_PROFILE 0 -#define GLFW_OPENGL_CORE_PROFILE 0x00032001 -#define GLFW_OPENGL_COMPAT_PROFILE 0x00032002 - -#define GLFW_CURSOR 0x00033001 -#define GLFW_STICKY_KEYS 0x00033002 -#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 - -#define GLFW_CURSOR_NORMAL 0x00034001 -#define GLFW_CURSOR_HIDDEN 0x00034002 -#define GLFW_CURSOR_DISABLED 0x00034003 - -#define GLFW_ANY_RELEASE_BEHAVIOR 0 -#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 -#define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 - -#define GLFW_NATIVE_CONTEXT_API 0x00036001 -#define GLFW_EGL_CONTEXT_API 0x00036002 - -/*! @defgroup shapes Standard cursor shapes - * - * See [standard cursor creation](@ref cursor_standard) for how these are used. - * - * @ingroup input - * @{ */ - -/*! @brief The regular arrow cursor shape. - * - * The regular arrow cursor. - */ -#define GLFW_ARROW_CURSOR 0x00036001 -/*! @brief The text input I-beam cursor shape. - * - * The text input I-beam cursor shape. - */ -#define GLFW_IBEAM_CURSOR 0x00036002 -/*! @brief The crosshair shape. - * - * The crosshair shape. - */ -#define GLFW_CROSSHAIR_CURSOR 0x00036003 -/*! @brief The hand shape. - * - * The hand shape. - */ -#define GLFW_HAND_CURSOR 0x00036004 -/*! @brief The horizontal resize arrow shape. - * - * The horizontal resize arrow shape. - */ -#define GLFW_HRESIZE_CURSOR 0x00036005 -/*! @brief The vertical resize arrow shape. - * - * The vertical resize arrow shape. - */ -#define GLFW_VRESIZE_CURSOR 0x00036006 -/*! @} */ - -#define GLFW_CONNECTED 0x00040001 -#define GLFW_DISCONNECTED 0x00040002 - -#define GLFW_DONT_CARE -1 - - -/************************************************************************* - * GLFW API types - *************************************************************************/ - -/*! @brief Client API function pointer type. - * - * Generic function pointer used for returning client API function pointers - * without forcing a cast from a regular pointer. - * - * @sa @ref context_glext - * @sa glfwGetProcAddress - * - * @since Added in version 3.0. - - * @ingroup context - */ -typedef void (*GLFWglproc)(void); - -/*! @brief Vulkan API function pointer type. - * - * Generic function pointer used for returning Vulkan API function pointers - * without forcing a cast from a regular pointer. - * - * @sa @ref vulkan_proc - * @sa glfwGetInstanceProcAddress - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -typedef void (*GLFWvkproc)(void); - -/*! @brief Opaque monitor object. - * - * Opaque monitor object. - * - * @see @ref monitor_object - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -typedef struct GLFWmonitor GLFWmonitor; - -/*! @brief Opaque window object. - * - * Opaque window object. - * - * @see @ref window_object - * - * @since Added in version 3.0. - * - * @ingroup window - */ -typedef struct GLFWwindow GLFWwindow; - -/*! @brief Opaque cursor object. - * - * Opaque cursor object. - * - * @see @ref cursor_object - * - * @since Added in version 3.1. - * - * @ingroup cursor - */ -typedef struct GLFWcursor GLFWcursor; - -/*! @brief The function signature for error callbacks. - * - * This is the function signature for error callback functions. - * - * @param[in] error An [error code](@ref errors). - * @param[in] description A UTF-8 encoded string describing the error. - * - * @sa @ref error_handling - * @sa glfwSetErrorCallback - * - * @since Added in version 3.0. - * - * @ingroup init - */ -typedef void (* GLFWerrorfun)(int,const char*); - -/*! @brief The function signature for window position callbacks. - * - * This is the function signature for window position callback functions. - * - * @param[in] window The window that was moved. - * @param[in] xpos The new x-coordinate, in screen coordinates, of the - * upper-left corner of the client area of the window. - * @param[in] ypos The new y-coordinate, in screen coordinates, of the - * upper-left corner of the client area of the window. - * - * @sa @ref window_pos - * @sa glfwSetWindowPosCallback - * - * @since Added in version 3.0. - * - * @ingroup window - */ -typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); - -/*! @brief The function signature for window resize callbacks. - * - * This is the function signature for window size callback functions. - * - * @param[in] window The window that was resized. - * @param[in] width The new width, in screen coordinates, of the window. - * @param[in] height The new height, in screen coordinates, of the window. - * - * @sa @ref window_size - * @sa glfwSetWindowSizeCallback - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); - -/*! @brief The function signature for window close callbacks. - * - * This is the function signature for window close callback functions. - * - * @param[in] window The window that the user attempted to close. - * - * @sa @ref window_close - * @sa glfwSetWindowCloseCallback - * - * @since Added in version 2.5. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -typedef void (* GLFWwindowclosefun)(GLFWwindow*); - -/*! @brief The function signature for window content refresh callbacks. - * - * This is the function signature for window refresh callback functions. - * - * @param[in] window The window whose content needs to be refreshed. - * - * @sa @ref window_refresh - * @sa glfwSetWindowRefreshCallback - * - * @since Added in version 2.5. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); - -/*! @brief The function signature for window focus/defocus callbacks. - * - * This is the function signature for window focus callback functions. - * - * @param[in] window The window that gained or lost input focus. - * @param[in] focused `GLFW_TRUE` if the window was given input focus, or - * `GLFW_FALSE` if it lost it. - * - * @sa @ref window_focus - * @sa glfwSetWindowFocusCallback - * - * @since Added in version 3.0. - * - * @ingroup window - */ -typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); - -/*! @brief The function signature for window iconify/restore callbacks. - * - * This is the function signature for window iconify/restore callback - * functions. - * - * @param[in] window The window that was iconified or restored. - * @param[in] iconified `GLFW_TRUE` if the window was iconified, or - * `GLFW_FALSE` if it was restored. - * - * @sa @ref window_iconify - * @sa glfwSetWindowIconifyCallback - * - * @since Added in version 3.0. - * - * @ingroup window - */ -typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); - -/*! @brief The function signature for framebuffer resize callbacks. - * - * This is the function signature for framebuffer resize callback - * functions. - * - * @param[in] window The window whose framebuffer was resized. - * @param[in] width The new width, in pixels, of the framebuffer. - * @param[in] height The new height, in pixels, of the framebuffer. - * - * @sa @ref window_fbsize - * @sa glfwSetFramebufferSizeCallback - * - * @since Added in version 3.0. - * - * @ingroup window - */ -typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); - -/*! @brief The function signature for mouse button callbacks. - * - * This is the function signature for mouse button callback functions. - * - * @param[in] window The window that received the event. - * @param[in] button The [mouse button](@ref buttons) that was pressed or - * released. - * @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`. - * @param[in] mods Bit field describing which [modifier keys](@ref mods) were - * held down. - * - * @sa @ref input_mouse_button - * @sa glfwSetMouseButtonCallback - * - * @since Added in version 1.0. - * @glfw3 Added window handle and modifier mask parameters. - * - * @ingroup input - */ -typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); - -/*! @brief The function signature for cursor position callbacks. - * - * This is the function signature for cursor position callback functions. - * - * @param[in] window The window that received the event. - * @param[in] xpos The new cursor x-coordinate, relative to the left edge of - * the client area. - * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the - * client area. - * - * @sa @ref cursor_pos - * @sa glfwSetCursorPosCallback - * - * @since Added in version 3.0. Replaces `GLFWmouseposfun`. - * - * @ingroup input - */ -typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); - -/*! @brief The function signature for cursor enter/leave callbacks. - * - * This is the function signature for cursor enter/leave callback functions. - * - * @param[in] window The window that received the event. - * @param[in] entered `GLFW_TRUE` if the cursor entered the window's client - * area, or `GLFW_FALSE` if it left it. - * - * @sa @ref cursor_enter - * @sa glfwSetCursorEnterCallback - * - * @since Added in version 3.0. - * - * @ingroup input - */ -typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); - -/*! @brief The function signature for scroll callbacks. - * - * This is the function signature for scroll callback functions. - * - * @param[in] window The window that received the event. - * @param[in] xoffset The scroll offset along the x-axis. - * @param[in] yoffset The scroll offset along the y-axis. - * - * @sa @ref scrolling - * @sa glfwSetScrollCallback - * - * @since Added in version 3.0. Replaces `GLFWmousewheelfun`. - * - * @ingroup input - */ -typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); - -/*! @brief The function signature for keyboard key callbacks. - * - * This is the function signature for keyboard key callback functions. - * - * @param[in] window The window that received the event. - * @param[in] key The [keyboard key](@ref keys) that was pressed or released. - * @param[in] scancode The system-specific scancode of the key. - * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. - * @param[in] mods Bit field describing which [modifier keys](@ref mods) were - * held down. - * - * @sa @ref input_key - * @sa glfwSetKeyCallback - * - * @since Added in version 1.0. - * @glfw3 Added window handle, scancode and modifier mask parameters. - * - * @ingroup input - */ -typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); - -/*! @brief The function signature for Unicode character callbacks. - * - * This is the function signature for Unicode character callback functions. - * - * @param[in] window The window that received the event. - * @param[in] codepoint The Unicode code point of the character. - * - * @sa @ref input_char - * @sa glfwSetCharCallback - * - * @since Added in version 2.4. - * @glfw3 Added window handle parameter. - * - * @ingroup input - */ -typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); - -/*! @brief The function signature for Unicode character with modifiers - * callbacks. - * - * This is the function signature for Unicode character with modifiers callback - * functions. It is called for each input character, regardless of what - * modifier keys are held down. - * - * @param[in] window The window that received the event. - * @param[in] codepoint The Unicode code point of the character. - * @param[in] mods Bit field describing which [modifier keys](@ref mods) were - * held down. - * - * @sa @ref input_char - * @sa glfwSetCharModsCallback - * - * @since Added in version 3.1. - * - * @ingroup input - */ -typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); - -/*! @brief The function signature for file drop callbacks. - * - * This is the function signature for file drop callbacks. - * - * @param[in] window The window that received the event. - * @param[in] count The number of dropped files. - * @param[in] paths The UTF-8 encoded file and/or directory path names. - * - * @sa @ref path_drop - * @sa glfwSetDropCallback - * - * @since Added in version 3.1. - * - * @ingroup input - */ -typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); - -/*! @brief The function signature for monitor configuration callbacks. - * - * This is the function signature for monitor configuration callback functions. - * - * @param[in] monitor The monitor that was connected or disconnected. - * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. - * - * @sa @ref monitor_event - * @sa glfwSetMonitorCallback - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); - -/*! @brief The function signature for joystick configuration callbacks. - * - * This is the function signature for joystick configuration callback - * functions. - * - * @param[in] joy The joystick that was connected or disconnected. - * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. - * - * @sa @ref joystick_event - * @sa glfwSetJoystickCallback - * - * @since Added in version 3.2. - * - * @ingroup input - */ -typedef void (* GLFWjoystickfun)(int,int); - -/*! @brief Video mode type. - * - * This describes a single video mode. - * - * @sa @ref monitor_modes - * @sa glfwGetVideoMode glfwGetVideoModes - * - * @since Added in version 1.0. - * @glfw3 Added refresh rate member. - * - * @ingroup monitor - */ -typedef struct GLFWvidmode -{ - /*! The width, in screen coordinates, of the video mode. - */ - int width; - /*! The height, in screen coordinates, of the video mode. - */ - int height; - /*! The bit depth of the red channel of the video mode. - */ - int redBits; - /*! The bit depth of the green channel of the video mode. - */ - int greenBits; - /*! The bit depth of the blue channel of the video mode. - */ - int blueBits; - /*! The refresh rate, in Hz, of the video mode. - */ - int refreshRate; -} GLFWvidmode; - -/*! @brief Gamma ramp. - * - * This describes the gamma ramp for a monitor. - * - * @sa @ref monitor_gamma - * @sa glfwGetGammaRamp glfwSetGammaRamp - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -typedef struct GLFWgammaramp -{ - /*! An array of value describing the response of the red channel. - */ - unsigned short* red; - /*! An array of value describing the response of the green channel. - */ - unsigned short* green; - /*! An array of value describing the response of the blue channel. - */ - unsigned short* blue; - /*! The number of elements in each array. - */ - unsigned int size; -} GLFWgammaramp; - -/*! @brief Image data. - * - * @sa @ref cursor_custom - * - * @since Added in version 2.1. - * @glfw3 Removed format and bytes-per-pixel members. - */ -typedef struct GLFWimage -{ - /*! The width, in pixels, of this image. - */ - int width; - /*! The height, in pixels, of this image. - */ - int height; - /*! The pixel data of this image, arranged left-to-right, top-to-bottom. - */ - unsigned char* pixels; -} GLFWimage; - - -/************************************************************************* - * GLFW API functions - *************************************************************************/ - -/*! @brief Initializes the GLFW library. - * - * This function initializes the GLFW library. Before most GLFW functions can - * be used, GLFW must be initialized, and before an application terminates GLFW - * should be terminated in order to free any resources allocated during or - * after initialization. - * - * If this function fails, it calls @ref glfwTerminate before returning. If it - * succeeds, you should call @ref glfwTerminate before the application exits. - * - * Additional calls to this function after successful initialization but before - * termination will return `GLFW_TRUE` immediately. - * - * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. - * - * @remark @osx This function will change the current directory of the - * application to the `Contents/Resources` subdirectory of the application's - * bundle, if present. This can be disabled with a - * [compile-time option](@ref compile_options_osx). - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref intro_init - * @sa glfwTerminate - * - * @since Added in version 1.0. - * - * @ingroup init - */ -GLFWAPI int glfwInit(void); - -/*! @brief Terminates the GLFW library. - * - * This function destroys all remaining windows and cursors, restores any - * modified gamma ramps and frees any other allocated resources. Once this - * function is called, you must again call @ref glfwInit successfully before - * you will be able to use most GLFW functions. - * - * If GLFW has been successfully initialized, this function should be called - * before the application exits. If initialization fails, there is no need to - * call this function, as it is called by @ref glfwInit before it returns - * failure. - * - * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. - * - * @remark This function may be called before @ref glfwInit. - * - * @warning The contexts of any remaining windows must not be current on any - * other thread when this function is called. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref intro_init - * @sa glfwInit - * - * @since Added in version 1.0. - * - * @ingroup init - */ -GLFWAPI void glfwTerminate(void); - -/*! @brief Retrieves the version of the GLFW library. - * - * This function retrieves the major, minor and revision numbers of the GLFW - * library. It is intended for when you are using GLFW as a shared library and - * want to ensure that you are using the minimum required version. - * - * Any or all of the version arguments may be `NULL`. - * - * @param[out] major Where to store the major version number, or `NULL`. - * @param[out] minor Where to store the minor version number, or `NULL`. - * @param[out] rev Where to store the revision number, or `NULL`. - * - * @errors None. - * - * @remark This function may be called before @ref glfwInit. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref intro_version - * @sa glfwGetVersionString - * - * @since Added in version 1.0. - * - * @ingroup init - */ -GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); - -/*! @brief Returns a string describing the compile-time configuration. - * - * This function returns the compile-time generated - * [version string](@ref intro_version_string) of the GLFW library binary. It - * describes the version, platform, compiler and any platform-specific - * compile-time options. It should not be confused with the OpenGL or OpenGL - * ES version string, queried with `glGetString`. - * - * __Do not use the version string__ to parse the GLFW library version. The - * @ref glfwGetVersion function provides the version of the running library - * binary in numerical format. - * - * @return The ASCII encoded GLFW version string. - * - * @errors None. - * - * @remark This function may be called before @ref glfwInit. - * - * @pointer_lifetime The returned string is static and compile-time generated. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref intro_version - * @sa glfwGetVersion - * - * @since Added in version 3.0. - * - * @ingroup init - */ -GLFWAPI const char* glfwGetVersionString(void); - -/*! @brief Sets the error callback. - * - * This function sets the error callback, which is called with an error code - * and a human-readable description each time a GLFW error occurs. - * - * The error callback is called on the thread where the error occurred. If you - * are using GLFW from multiple threads, your error callback needs to be - * written accordingly. - * - * Because the description string may have been generated specifically for that - * error, it is not guaranteed to be valid after the callback has returned. If - * you wish to use it after the callback returns, you need to make a copy. - * - * Once set, the error callback remains set even after the library has been - * terminated. - * - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set. - * - * @errors None. - * - * @remark This function may be called before @ref glfwInit. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref error_handling - * - * @since Added in version 3.0. - * - * @ingroup init - */ -GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); - -/*! @brief Returns the currently connected monitors. - * - * This function returns an array of handles for all currently connected - * monitors. The primary monitor is always first in the returned array. If no - * monitors were found, this function returns `NULL`. - * - * @param[out] count Where to store the number of monitors in the returned - * array. This is set to zero if an error occurred. - * @return An array of monitor handles, or `NULL` if no monitors were found or - * if an [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is guaranteed to be valid only until the - * monitor configuration changes or the library is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_monitors - * @sa @ref monitor_event - * @sa glfwGetPrimaryMonitor - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); - -/*! @brief Returns the primary monitor. - * - * This function returns the primary monitor. This is usually the monitor - * where elements like the task bar or global menu bar are located. - * - * @return The primary monitor, or `NULL` if no monitors were found or if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @remark The primary monitor is always first in the array returned by @ref - * glfwGetMonitors. - * - * @sa @ref monitor_monitors - * @sa glfwGetMonitors - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); - -/*! @brief Returns the position of the monitor's viewport on the virtual screen. - * - * This function returns the position, in screen coordinates, of the upper-left - * corner of the specified monitor. - * - * Any or all of the position arguments may be `NULL`. If an error occurs, all - * non-`NULL` position arguments will be set to zero. - * - * @param[in] monitor The monitor to query. - * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. - * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_properties - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); - -/*! @brief Returns the physical size of the monitor. - * - * This function returns the size, in millimetres, of the display area of the - * specified monitor. - * - * Some systems do not provide accurate monitor size information, either - * because the monitor - * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data) - * data is incorrect or because the driver does not report it accurately. - * - * Any or all of the size arguments may be `NULL`. If an error occurs, all - * non-`NULL` size arguments will be set to zero. - * - * @param[in] monitor The monitor to query. - * @param[out] widthMM Where to store the width, in millimetres, of the - * monitor's display area, or `NULL`. - * @param[out] heightMM Where to store the height, in millimetres, of the - * monitor's display area, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @remark @win32 calculates the returned physical size from the - * current resolution and system DPI instead of querying the monitor EDID data. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_properties - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM); - -/*! @brief Returns the name of the specified monitor. - * - * This function returns a human-readable name, encoded as UTF-8, of the - * specified monitor. The name typically reflects the make and model of the - * monitor and is not guaranteed to be unique among the connected monitors. - * - * @param[in] monitor The monitor to query. - * @return The UTF-8 encoded name of the monitor, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @pointer_lifetime The returned string is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified monitor is - * disconnected or the library is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_properties - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); - -/*! @brief Sets the monitor configuration callback. - * - * This function sets the monitor configuration callback, or removes the - * currently set callback. This is called when a monitor is connected to or - * disconnected from the system. - * - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_event - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); - -/*! @brief Returns the available video modes for the specified monitor. - * - * This function returns an array of all video modes supported by the specified - * monitor. The returned array is sorted in ascending order, first by color - * bit depth (the sum of all channel depths) and then by resolution area (the - * product of width and height). - * - * @param[in] monitor The monitor to query. - * @param[out] count Where to store the number of video modes in the returned - * array. This is set to zero if an error occurred. - * @return An array of video modes, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified monitor is - * disconnected, this function is called again for that monitor or the library - * is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_modes - * @sa glfwGetVideoMode - * - * @since Added in version 1.0. - * @glfw3 Changed to return an array of modes for a specific monitor. - * - * @ingroup monitor - */ -GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); - -/*! @brief Returns the current mode of the specified monitor. - * - * This function returns the current video mode of the specified monitor. If - * you have created a full screen window for that monitor, the return value - * will depend on whether that window is iconified. - * - * @param[in] monitor The monitor to query. - * @return The current mode of the monitor, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified monitor is - * disconnected or the library is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_modes - * @sa glfwGetVideoModes - * - * @since Added in version 3.0. Replaces `glfwGetDesktopMode`. - * - * @ingroup monitor - */ -GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); - -/*! @brief Generates a gamma ramp and sets it for the specified monitor. - * - * This function generates a 256-element gamma ramp from the specified exponent - * and then calls @ref glfwSetGammaRamp with it. The value must be a finite - * number greater than zero. - * - * @param[in] monitor The monitor whose gamma ramp to set. - * @param[in] gamma The desired exponent. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_gamma - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); - -/*! @brief Returns the current gamma ramp for the specified monitor. - * - * This function returns the current gamma ramp of the specified monitor. - * - * @param[in] monitor The monitor to query. - * @return The current gamma ramp, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned structure and its arrays are allocated and - * freed by GLFW. You should not free them yourself. They are valid until the - * specified monitor is disconnected, this function is called again for that - * monitor or the library is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_gamma - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); - -/*! @brief Sets the current gamma ramp for the specified monitor. - * - * This function sets the current gamma ramp for the specified monitor. The - * original gamma ramp for that monitor is saved by GLFW the first time this - * function is called and is restored by @ref glfwTerminate. - * - * @param[in] monitor The monitor whose gamma ramp to set. - * @param[in] ramp The gamma ramp to use. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @remark Gamma ramp sizes other than 256 are not supported by all platforms - * or graphics hardware. - * - * @remark @win32 The gamma ramp size must be 256. - * - * @pointer_lifetime The specified gamma ramp is copied before this function - * returns. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref monitor_gamma - * - * @since Added in version 3.0. - * - * @ingroup monitor - */ -GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); - -/*! @brief Resets all window hints to their default values. - * - * This function resets all window hints to their - * [default values](@ref window_hints_values). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_hints - * @sa glfwWindowHint - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwDefaultWindowHints(void); - -/*! @brief Sets the specified window hint to the desired value. - * - * This function sets hints for the next call to @ref glfwCreateWindow. The - * hints, once set, retain their values until changed by a call to @ref - * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is - * terminated. - * - * This function does not check whether the specified hint values are valid. - * If you set hints to invalid values this will instead be reported by the next - * call to @ref glfwCreateWindow. - * - * @param[in] hint The [window hint](@ref window_hints) to set. - * @param[in] value The new value of the window hint. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_ENUM. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_hints - * @sa glfwDefaultWindowHints - * - * @since Added in version 3.0. Replaces `glfwOpenWindowHint`. - * - * @ingroup window - */ -GLFWAPI void glfwWindowHint(int hint, int value); - -/*! @brief Creates a window and its associated context. - * - * This function creates a window and its associated OpenGL or OpenGL ES - * context. Most of the options controlling how the window and its context - * should be created are specified with [window hints](@ref window_hints). - * - * Successful creation does not change which context is current. Before you - * can use the newly created context, you need to - * [make it current](@ref context_current). For information about the `share` - * parameter, see @ref context_sharing. - * - * The created window, framebuffer and context may differ from what you - * requested, as not all parameters and hints are - * [hard constraints](@ref window_hints_hard). This includes the size of the - * window, especially for full screen windows. To query the actual attributes - * of the created window, framebuffer and context, see @ref - * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. - * - * To create a full screen window, you need to specify the monitor the window - * will cover. If no monitor is specified, the window will be windowed mode. - * Unless you have a way for the user to choose a specific monitor, it is - * recommended that you pick the primary monitor. For more information on how - * to query connected monitors, see @ref monitor_monitors. - * - * For full screen windows, the specified size becomes the resolution of the - * window's _desired video mode_. As long as a full screen window is not - * iconified, the supported video mode most closely matching the desired video - * mode is set for the specified monitor. For more information about full - * screen windows, including the creation of so called _windowed full screen_ - * or _borderless full screen_ windows, see @ref window_windowed_full_screen. - * - * By default, newly created windows use the placement recommended by the - * window system. To create the window at a specific position, make it - * initially invisible using the [GLFW_VISIBLE](@ref window_hints_wnd) window - * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) - * it. - * - * As long as at least one full screen window is not iconified, the screensaver - * is prohibited from starting. - * - * Window systems put limits on window sizes. Very large or very small window - * dimensions may be overridden by the window system on creation. Check the - * actual [size](@ref window_size) after creation. - * - * The [swap interval](@ref buffer_swap) is not set during window creation and - * the initial value may vary depending on driver settings and defaults. - * - * @param[in] width The desired width, in screen coordinates, of the window. - * This must be greater than zero. - * @param[in] height The desired height, in screen coordinates, of the window. - * This must be greater than zero. - * @param[in] title The initial, UTF-8 encoded window title. - * @param[in] monitor The monitor to use for full screen mode, or `NULL` for - * windowed mode. - * @param[in] share The window whose context to share resources with, or `NULL` - * to not share resources. - * @return The handle of the created window, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref - * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref - * GLFW_PLATFORM_ERROR. - * - * @remark @win32 Window creation will fail if the Microsoft GDI software - * OpenGL implementation is the only one available. - * - * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it - * will be set as the initial icon for the window. If no such icon is present, - * the `IDI_WINLOGO` icon will be used instead. To set a different icon, see - * @ref glfwSetWindowIcon. - * - * @remark @win32 The context to share resources with must not be current on - * any other thread. - * - * @remark @osx The GLFW window has no icon, as it is not a document - * window, but the dock icon will be the same as the application bundle's icon. - * For more information on bundles, see the - * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) - * in the Mac Developer Library. - * - * @remark @osx The first time a window is created the menu bar is populated - * with common commands like Hide, Quit and About. The About entry opens - * a minimal about dialog with information from the application's bundle. The - * menu bar can be disabled with a - * [compile-time option](@ref compile_options_osx). - * - * @remark @osx On OS X 10.10 and later the window frame will not be rendered - * at full resolution on Retina displays unless the `NSHighResolutionCapable` - * key is enabled in the application bundle's `Info.plist`. For more - * information, see - * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) - * in the Mac Developer Library. The GLFW test and example programs use - * a custom `Info.plist` template for this, which can be found as - * `CMake/MacOSXBundleInfo.plist.in` in the source tree. - * - * @remark @x11 Some window managers will not respect the placement of - * initially hidden windows. - * - * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for - * a window to reach its requested state. This means you may not be able to - * query the final size, position or other attributes directly after window - * creation. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_creation - * @sa glfwDestroyWindow - * - * @since Added in version 3.0. Replaces `glfwOpenWindow`. - * - * @ingroup window - */ -GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); - -/*! @brief Destroys the specified window and its context. - * - * This function destroys the specified window and its context. On calling - * this function, no further callbacks will be called for that window. - * - * If the context of the specified window is current on the main thread, it is - * detached before being destroyed. - * - * @param[in] window The window to destroy. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @note The context of the specified window must not be current on any other - * thread when this function is called. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_creation - * @sa glfwCreateWindow - * - * @since Added in version 3.0. Replaces `glfwCloseWindow`. - * - * @ingroup window - */ -GLFWAPI void glfwDestroyWindow(GLFWwindow* window); - -/*! @brief Checks the close flag of the specified window. - * - * This function returns the value of the close flag of the specified window. - * - * @param[in] window The window to query. - * @return The value of the close flag. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @sa @ref window_close - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); - -/*! @brief Sets the close flag of the specified window. - * - * This function sets the value of the close flag of the specified window. - * This can be used to override the user's attempt to close the window, or - * to signal that it should be closed. - * - * @param[in] window The window whose flag to change. - * @param[in] value The new value. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @sa @ref window_close - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); - -/*! @brief Sets the title of the specified window. - * - * This function sets the window title, encoded as UTF-8, of the specified - * window. - * - * @param[in] window The window whose title to change. - * @param[in] title The UTF-8 encoded window title. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @remark @osx The window title will not be updated until the next time you - * process events. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_title - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); - -/*! @brief Sets the icon for the specified window. - * - * This function sets the icon of the specified window. If passed an array of - * candidate images, those of or closest to the sizes desired by the system are - * selected. If no images are specified, the window reverts to its default - * icon. - * - * The desired image sizes varies depending on platform and system settings. - * The selected images will be rescaled as needed. Good sizes include 16x16, - * 32x32 and 48x48. - * - * @param[in] window The window whose icon to set. - * @param[in] count The number of images in the specified array, or zero to - * revert to the default window icon. - * @param[in] images The images to create the icon from. This is ignored if - * count is zero. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The specified image data is copied before this function - * returns. - * - * @remark @osx The GLFW window has no icon, as it is not a document - * window, so this function does nothing. The dock icon will be the same as - * the application bundle's icon. For more information on bundles, see the - * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) - * in the Mac Developer Library. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_icon - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images); - -/*! @brief Retrieves the position of the client area of the specified window. - * - * This function retrieves the position, in screen coordinates, of the - * upper-left corner of the client area of the specified window. - * - * Any or all of the position arguments may be `NULL`. If an error occurs, all - * non-`NULL` position arguments will be set to zero. - * - * @param[in] window The window to query. - * @param[out] xpos Where to store the x-coordinate of the upper-left corner of - * the client area, or `NULL`. - * @param[out] ypos Where to store the y-coordinate of the upper-left corner of - * the client area, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_pos - * @sa glfwSetWindowPos - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); - -/*! @brief Sets the position of the client area of the specified window. - * - * This function sets the position, in screen coordinates, of the upper-left - * corner of the client area of the specified windowed mode window. If the - * window is a full screen window, this function does nothing. - * - * __Do not use this function__ to move an already visible window unless you - * have very good reasons for doing so, as it will confuse and annoy the user. - * - * The window manager may put limits on what positions are allowed. GLFW - * cannot and should not override these limits. - * - * @param[in] window The window to query. - * @param[in] xpos The x-coordinate of the upper-left corner of the client area. - * @param[in] ypos The y-coordinate of the upper-left corner of the client area. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_pos - * @sa glfwGetWindowPos - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); - -/*! @brief Retrieves the size of the client area of the specified window. - * - * This function retrieves the size, in screen coordinates, of the client area - * of the specified window. If you wish to retrieve the size of the - * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize. - * - * Any or all of the size arguments may be `NULL`. If an error occurs, all - * non-`NULL` size arguments will be set to zero. - * - * @param[in] window The window whose size to retrieve. - * @param[out] width Where to store the width, in screen coordinates, of the - * client area, or `NULL`. - * @param[out] height Where to store the height, in screen coordinates, of the - * client area, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_size - * @sa glfwSetWindowSize - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); - -/*! @brief Sets the size limits of the specified window. - * - * This function sets the size limits of the client area of the specified - * window. If the window is full screen, the size limits only take effect - * once it is made windowed. If the window is not resizable, this function - * does nothing. - * - * The size limits are applied immediately to a windowed mode window and may - * cause it to be resized. - * - * The maximum dimensions must be greater than or equal to the minimum - * dimensions and all must be greater than or equal to zero. - * - * @param[in] window The window to set limits for. - * @param[in] minwidth The minimum width, in screen coordinates, of the client - * area, or `GLFW_DONT_CARE`. - * @param[in] minheight The minimum height, in screen coordinates, of the - * client area, or `GLFW_DONT_CARE`. - * @param[in] maxwidth The maximum width, in screen coordinates, of the client - * area, or `GLFW_DONT_CARE`. - * @param[in] maxheight The maximum height, in screen coordinates, of the - * client area, or `GLFW_DONT_CARE`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. - * - * @remark If you set size limits and an aspect ratio that conflict, the - * results are undefined. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_sizelimits - * @sa glfwSetWindowAspectRatio - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); - -/*! @brief Sets the aspect ratio of the specified window. - * - * This function sets the required aspect ratio of the client area of the - * specified window. If the window is full screen, the aspect ratio only takes - * effect once it is made windowed. If the window is not resizable, this - * function does nothing. - * - * The aspect ratio is specified as a numerator and a denominator and both - * values must be greater than zero. For example, the common 16:9 aspect ratio - * is specified as 16 and 9, respectively. - * - * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect - * ratio limit is disabled. - * - * The aspect ratio is applied immediately to a windowed mode window and may - * cause it to be resized. - * - * @param[in] window The window to set limits for. - * @param[in] numer The numerator of the desired aspect ratio, or - * `GLFW_DONT_CARE`. - * @param[in] denom The denominator of the desired aspect ratio, or - * `GLFW_DONT_CARE`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. - * - * @remark If you set size limits and an aspect ratio that conflict, the - * results are undefined. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_sizelimits - * @sa glfwSetWindowSizeLimits - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); - -/*! @brief Sets the size of the client area of the specified window. - * - * This function sets the size, in screen coordinates, of the client area of - * the specified window. - * - * For full screen windows, this function updates the resolution of its desired - * video mode and switches to the video mode closest to it, without affecting - * the window's context. As the context is unaffected, the bit depths of the - * framebuffer remain unchanged. - * - * If you wish to update the refresh rate of the desired video mode in addition - * to its resolution, see @ref glfwSetWindowMonitor. - * - * The window manager may put limits on what sizes are allowed. GLFW cannot - * and should not override these limits. - * - * @param[in] window The window to resize. - * @param[in] width The desired width, in screen coordinates, of the window - * client area. - * @param[in] height The desired height, in screen coordinates, of the window - * client area. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_size - * @sa glfwGetWindowSize - * @sa glfwSetWindowMonitor - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); - -/*! @brief Retrieves the size of the framebuffer of the specified window. - * - * This function retrieves the size, in pixels, of the framebuffer of the - * specified window. If you wish to retrieve the size of the window in screen - * coordinates, see @ref glfwGetWindowSize. - * - * Any or all of the size arguments may be `NULL`. If an error occurs, all - * non-`NULL` size arguments will be set to zero. - * - * @param[in] window The window whose framebuffer to query. - * @param[out] width Where to store the width, in pixels, of the framebuffer, - * or `NULL`. - * @param[out] height Where to store the height, in pixels, of the framebuffer, - * or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_fbsize - * @sa glfwSetFramebufferSizeCallback - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); - -/*! @brief Retrieves the size of the frame of the window. - * - * This function retrieves the size, in screen coordinates, of each edge of the - * frame of the specified window. This size includes the title bar, if the - * window has one. The size of the frame may vary depending on the - * [window-related hints](@ref window_hints_wnd) used to create it. - * - * Because this function retrieves the size of each window frame edge and not - * the offset along a particular coordinate axis, the retrieved values will - * always be zero or positive. - * - * Any or all of the size arguments may be `NULL`. If an error occurs, all - * non-`NULL` size arguments will be set to zero. - * - * @param[in] window The window whose frame size to query. - * @param[out] left Where to store the size, in screen coordinates, of the left - * edge of the window frame, or `NULL`. - * @param[out] top Where to store the size, in screen coordinates, of the top - * edge of the window frame, or `NULL`. - * @param[out] right Where to store the size, in screen coordinates, of the - * right edge of the window frame, or `NULL`. - * @param[out] bottom Where to store the size, in screen coordinates, of the - * bottom edge of the window frame, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_size - * - * @since Added in version 3.1. - * - * @ingroup window - */ -GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); - -/*! @brief Iconifies the specified window. - * - * This function iconifies (minimizes) the specified window if it was - * previously restored. If the window is already iconified, this function does - * nothing. - * - * If the specified window is a full screen window, the original monitor - * resolution is restored until the window is restored. - * - * @param[in] window The window to iconify. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_iconify - * @sa glfwRestoreWindow - * @sa glfwMaximizeWindow - * - * @since Added in version 2.1. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwIconifyWindow(GLFWwindow* window); - -/*! @brief Restores the specified window. - * - * This function restores the specified window if it was previously iconified - * (minimized) or maximized. If the window is already restored, this function - * does nothing. - * - * If the specified window is a full screen window, the resolution chosen for - * the window is restored on the selected monitor. - * - * @param[in] window The window to restore. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_iconify - * @sa glfwIconifyWindow - * @sa glfwMaximizeWindow - * - * @since Added in version 2.1. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwRestoreWindow(GLFWwindow* window); - -/*! @brief Maximizes the specified window. - * - * This function maximizes the specified window if it was previously not - * maximized. If the window is already maximized, this function does nothing. - * - * If the specified window is a full screen window, this function does nothing. - * - * @param[in] window The window to maximize. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @par Thread Safety - * This function may only be called from the main thread. - * - * @sa @ref window_iconify - * @sa glfwIconifyWindow - * @sa glfwRestoreWindow - * - * @since Added in GLFW 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); - -/*! @brief Makes the specified window visible. - * - * This function makes the specified window visible if it was previously - * hidden. If the window is already visible or is in full screen mode, this - * function does nothing. - * - * @param[in] window The window to make visible. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_hide - * @sa glfwHideWindow - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwShowWindow(GLFWwindow* window); - -/*! @brief Hides the specified window. - * - * This function hides the specified window if it was previously visible. If - * the window is already hidden or is in full screen mode, this function does - * nothing. - * - * @param[in] window The window to hide. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_hide - * @sa glfwShowWindow - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwHideWindow(GLFWwindow* window); - -/*! @brief Brings the specified window to front and sets input focus. - * - * This function brings the specified window to front and sets input focus. - * The window should already be visible and not iconified. - * - * By default, both windowed and full screen mode windows are focused when - * initially created. Set the [GLFW_FOCUSED](@ref window_hints_wnd) to disable - * this behavior. - * - * __Do not use this function__ to steal focus from other applications unless - * you are certain that is what the user wants. Focus stealing can be - * extremely disruptive. - * - * @param[in] window The window to give input focus. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_focus - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwFocusWindow(GLFWwindow* window); - -/*! @brief Returns the monitor that the window uses for full screen mode. - * - * This function returns the handle of the monitor that the specified window is - * in full screen on. - * - * @param[in] window The window to query. - * @return The monitor, or `NULL` if the window is in windowed mode or an error - * occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_monitor - * @sa glfwSetWindowMonitor - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); - -/*! @brief Sets the mode, monitor, video mode and placement of a window. - * - * This function sets the monitor that the window uses for full screen mode or, - * if the monitor is `NULL`, makes it windowed mode. - * - * When setting a monitor, this function updates the width, height and refresh - * rate of the desired video mode and switches to the video mode closest to it. - * The window position is ignored when setting a monitor. - * - * When the monitor is `NULL`, the position, width and height are used to - * place the window client area. The refresh rate is ignored when no monitor - * is specified. - * - * If you only wish to update the resolution of a full screen window or the - * size of a windowed mode window, see @ref glfwSetWindowSize. - * - * When a window transitions from full screen to windowed mode, this function - * restores any previous window settings such as whether it is decorated, - * floating, resizable, has size or aspect ratio limits, etc.. - * - * @param[in] window The window whose monitor, size or video mode to set. - * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. - * @param[in] xpos The desired x-coordinate of the upper-left corner of the - * client area. - * @param[in] ypos The desired y-coordinate of the upper-left corner of the - * client area. - * @param[in] width The desired with, in screen coordinates, of the client area - * or video mode. - * @param[in] height The desired height, in screen coordinates, of the client - * area or video mode. - * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode, - * or `GLFW_DONT_CARE`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_monitor - * @sa @ref window_full_screen - * @sa glfwGetWindowMonitor - * @sa glfwSetWindowSize - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); - -/*! @brief Returns an attribute of the specified window. - * - * This function returns the value of an attribute of the specified window or - * its OpenGL or OpenGL ES context. - * - * @param[in] window The window to query. - * @param[in] attrib The [window attribute](@ref window_attribs) whose value to - * return. - * @return The value of the attribute, or zero if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @remark Framebuffer related hints are not window attributes. See @ref - * window_attribs_fb for more information. - * - * @remark Zero is a valid value for many window and context related - * attributes so you cannot use a return value of zero as an indication of - * errors. However, this function should not fail as long as it is passed - * valid arguments and the library has been [initialized](@ref intro_init). - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_attribs - * - * @since Added in version 3.0. Replaces `glfwGetWindowParam` and - * `glfwGetGLVersion`. - * - * @ingroup window - */ -GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); - -/*! @brief Sets the user pointer of the specified window. - * - * This function sets the user-defined pointer of the specified window. The - * current value is retained until the window is destroyed. The initial value - * is `NULL`. - * - * @param[in] window The window whose pointer to set. - * @param[in] pointer The new value. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @sa @ref window_userptr - * @sa glfwGetWindowUserPointer - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); - -/*! @brief Returns the user pointer of the specified window. - * - * This function returns the current value of the user-defined pointer of the - * specified window. The initial value is `NULL`. - * - * @param[in] window The window whose pointer to return. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @sa @ref window_userptr - * @sa glfwSetWindowUserPointer - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); - -/*! @brief Sets the position callback for the specified window. - * - * This function sets the position callback of the specified window, which is - * called when the window is moved. The callback is provided with the screen - * position of the upper-left corner of the client area of the window. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_pos - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun cbfun); - -/*! @brief Sets the size callback for the specified window. - * - * This function sets the size callback of the specified window, which is - * called when the window is resized. The callback is provided with the size, - * in screen coordinates, of the client area of the window. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_size - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup window - */ -GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun cbfun); - -/*! @brief Sets the close callback for the specified window. - * - * This function sets the close callback of the specified window, which is - * called when the user attempts to close the window, for example by clicking - * the close widget in the title bar. - * - * The close flag is set before this callback is called, but you can modify it - * at any time with @ref glfwSetWindowShouldClose. - * - * The close callback is not triggered by @ref glfwDestroyWindow. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @remark @osx Selecting Quit from the application menu will trigger the close - * callback for all windows. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_close - * - * @since Added in version 2.5. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup window - */ -GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun cbfun); - -/*! @brief Sets the refresh callback for the specified window. - * - * This function sets the refresh callback of the specified window, which is - * called when the client area of the window needs to be redrawn, for example - * if the window has been exposed after having been covered by another window. - * - * On compositing window systems such as Aero, Compiz or Aqua, where the window - * contents are saved off-screen, this callback may be called only very - * infrequently or never at all. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_refresh - * - * @since Added in version 2.5. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup window - */ -GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun cbfun); - -/*! @brief Sets the focus callback for the specified window. - * - * This function sets the focus callback of the specified window, which is - * called when the window gains or loses input focus. - * - * After the focus callback is called for a window that lost input focus, - * synthetic key and mouse button release events will be generated for all such - * that had been pressed. For more information, see @ref glfwSetKeyCallback - * and @ref glfwSetMouseButtonCallback. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_focus - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun cbfun); - -/*! @brief Sets the iconify callback for the specified window. - * - * This function sets the iconification callback of the specified window, which - * is called when the window is iconified or restored. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_iconify - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun cbfun); - -/*! @brief Sets the framebuffer resize callback for the specified window. - * - * This function sets the framebuffer resize callback of the specified window, - * which is called when the framebuffer of the specified window is resized. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref window_fbsize - * - * @since Added in version 3.0. - * - * @ingroup window - */ -GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun); - -/*! @brief Processes all pending events. - * - * This function processes only those events that are already in the event - * queue and then returns immediately. Processing events will cause the window - * and input callbacks associated with those events to be called. - * - * On some platforms, a window move, resize or menu operation will cause event - * processing to block. This is due to how event processing is designed on - * those platforms. You can use the - * [window refresh callback](@ref window_refresh) to redraw the contents of - * your window when necessary during such operations. - * - * On some platforms, certain events are sent directly to the application - * without going through the event queue, causing callbacks to be called - * outside of a call to one of the event processing functions. - * - * Event processing is not required for joystick input to work. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref events - * @sa glfwWaitEvents - * @sa glfwWaitEventsTimeout - * - * @since Added in version 1.0. - * - * @ingroup window - */ -GLFWAPI void glfwPollEvents(void); - -/*! @brief Waits until events are queued and processes them. - * - * This function puts the calling thread to sleep until at least one event is - * available in the event queue. Once one or more events are available, - * it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue - * are processed and the function then returns immediately. Processing events - * will cause the window and input callbacks associated with those events to be - * called. - * - * Since not all events are associated with callbacks, this function may return - * without a callback having been called even if you are monitoring all - * callbacks. - * - * On some platforms, a window move, resize or menu operation will cause event - * processing to block. This is due to how event processing is designed on - * those platforms. You can use the - * [window refresh callback](@ref window_refresh) to redraw the contents of - * your window when necessary during such operations. - * - * On some platforms, certain callbacks may be called outside of a call to one - * of the event processing functions. - * - * If no windows exist, this function returns immediately. For synchronization - * of threads in applications that do not create windows, use your threading - * library of choice. - * - * Event processing is not required for joystick input to work. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref events - * @sa glfwPollEvents - * @sa glfwWaitEventsTimeout - * - * @since Added in version 2.5. - * - * @ingroup window - */ -GLFWAPI void glfwWaitEvents(void); - -/*! @brief Waits with timeout until events are queued and processes them. - * - * This function puts the calling thread to sleep until at least one event is - * available in the event queue, or until the specified timeout is reached. If - * one or more events are available, it behaves exactly like @ref - * glfwPollEvents, i.e. the events in the queue are processed and the function - * then returns immediately. Processing events will cause the window and input - * callbacks associated with those events to be called. - * - * The timeout value must be a positive finite number. - * - * Since not all events are associated with callbacks, this function may return - * without a callback having been called even if you are monitoring all - * callbacks. - * - * On some platforms, a window move, resize or menu operation will cause event - * processing to block. This is due to how event processing is designed on - * those platforms. You can use the - * [window refresh callback](@ref window_refresh) to redraw the contents of - * your window when necessary during such operations. - * - * On some platforms, certain callbacks may be called outside of a call to one - * of the event processing functions. - * - * If no windows exist, this function returns immediately. For synchronization - * of threads in applications that do not create windows, use your threading - * library of choice. - * - * Event processing is not required for joystick input to work. - * - * @param[in] timeout The maximum amount of time, in seconds, to wait. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref events - * @sa glfwPollEvents - * @sa glfwWaitEvents - * - * @since Added in version 3.2. - * - * @ingroup window - */ -GLFWAPI void glfwWaitEventsTimeout(double timeout); - -/*! @brief Posts an empty event to the event queue. - * - * This function posts an empty event from the current thread to the event - * queue, causing @ref glfwWaitEvents to return. - * - * If no windows exist, this function returns immediately. For synchronization - * of threads in applications that do not create windows, use your threading - * library of choice. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref events - * @sa glfwWaitEvents - * - * @since Added in version 3.1. - * - * @ingroup window - */ -GLFWAPI void glfwPostEmptyEvent(void); - -/*! @brief Returns the value of an input option for the specified window. - * - * This function returns the value of an input option for the specified window. - * The mode must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. - * - * @param[in] window The window to query. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_ENUM. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa glfwSetInputMode - * - * @since Added in version 3.0. - * - * @ingroup input - */ -GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); - -/*! @brief Sets an input option for the specified window. - * - * This function sets an input mode option for the specified window. The mode - * must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. - * - * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor - * modes: - * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. - * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client - * area of the window but does not restrict the cursor from leaving. - * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual - * and unlimited cursor movement. This is useful for implementing for - * example 3D camera controls. - * - * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to - * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are - * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` - * the next time it is called even if the key had been released before the - * call. This is useful when you are only interested in whether keys have been - * pressed but not when or in which order. - * - * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either - * `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it. - * If sticky mouse buttons are enabled, a mouse button press will ensure that - * @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even - * if the mouse button had been released before the call. This is useful when - * you are only interested in whether mouse buttons have been pressed but not - * when or in which order. - * - * @param[in] window The window whose input mode to set. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. - * @param[in] value The new value of the specified input mode. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa glfwGetInputMode - * - * @since Added in version 3.0. Replaces `glfwEnable` and `glfwDisable`. - * - * @ingroup input - */ -GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); - -/*! @brief Returns the localized name of the specified printable key. - * - * This function returns the localized name of the specified printable key. - * This is intended for displaying key bindings to the user. - * - * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used instead, otherwise - * the scancode is ignored. If a non-printable key or (if the key is - * `GLFW_KEY_UNKNOWN`) a scancode that maps to a non-printable key is - * specified, this function returns `NULL`. - * - * This behavior allows you to pass in the arguments passed to the - * [key callback](@ref input_key) without modification. - * - * The printable keys are: - * - `GLFW_KEY_APOSTROPHE` - * - `GLFW_KEY_COMMA` - * - `GLFW_KEY_MINUS` - * - `GLFW_KEY_PERIOD` - * - `GLFW_KEY_SLASH` - * - `GLFW_KEY_SEMICOLON` - * - `GLFW_KEY_EQUAL` - * - `GLFW_KEY_LEFT_BRACKET` - * - `GLFW_KEY_RIGHT_BRACKET` - * - `GLFW_KEY_BACKSLASH` - * - `GLFW_KEY_WORLD_1` - * - `GLFW_KEY_WORLD_2` - * - `GLFW_KEY_0` to `GLFW_KEY_9` - * - `GLFW_KEY_A` to `GLFW_KEY_Z` - * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9` - * - `GLFW_KEY_KP_DECIMAL` - * - `GLFW_KEY_KP_DIVIDE` - * - `GLFW_KEY_KP_MULTIPLY` - * - `GLFW_KEY_KP_SUBTRACT` - * - `GLFW_KEY_KP_ADD` - * - `GLFW_KEY_KP_EQUAL` - * - * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`. - * @param[in] scancode The scancode of the key to query. - * @return The localized name of the key, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned string is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the next call to @ref - * glfwGetKeyName, or until the library is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_key_name - * - * @since Added in version 3.2. - * - * @ingroup input - */ -GLFWAPI const char* glfwGetKeyName(int key, int scancode); - -/*! @brief Returns the last reported state of a keyboard key for the specified - * window. - * - * This function returns the last state reported for the specified key to the - * specified window. The returned state is one of `GLFW_PRESS` or - * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to - * the key callback. - * - * If the `GLFW_STICKY_KEYS` input mode is enabled, this function returns - * `GLFW_PRESS` the first time you call it for a key that was pressed, even if - * that key has already been released. - * - * The key functions deal with physical keys, with [key tokens](@ref keys) - * named after their use on the standard US keyboard layout. If you want to - * input text, use the Unicode character callback instead. - * - * The [modifier key bit masks](@ref mods) are not key tokens and cannot be - * used with this function. - * - * __Do not use this function__ to implement [text input](@ref input_char). - * - * @param[in] window The desired window. - * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is - * not a valid key for this function. - * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_ENUM. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_key - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup input - */ -GLFWAPI int glfwGetKey(GLFWwindow* window, int key); - -/*! @brief Returns the last reported state of a mouse button for the specified - * window. - * - * This function returns the last state reported for the specified mouse button - * to the specified window. The returned state is one of `GLFW_PRESS` or - * `GLFW_RELEASE`. - * - * If the `GLFW_STICKY_MOUSE_BUTTONS` input mode is enabled, this function - * `GLFW_PRESS` the first time you call it for a mouse button that was pressed, - * even if that mouse button has already been released. - * - * @param[in] window The desired window. - * @param[in] button The desired [mouse button](@ref buttons). - * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_ENUM. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_mouse_button - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup input - */ -GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); - -/*! @brief Retrieves the position of the cursor relative to the client area of - * the window. - * - * This function returns the position of the cursor, in screen coordinates, - * relative to the upper-left corner of the client area of the specified - * window. - * - * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor - * position is unbounded and limited only by the minimum and maximum values of - * a `double`. - * - * The coordinate can be converted to their integer equivalents with the - * `floor` function. Casting directly to an integer type works for positive - * coordinates, but fails for negative ones. - * - * Any or all of the position arguments may be `NULL`. If an error occurs, all - * non-`NULL` position arguments will be set to zero. - * - * @param[in] window The desired window. - * @param[out] xpos Where to store the cursor x-coordinate, relative to the - * left edge of the client area, or `NULL`. - * @param[out] ypos Where to store the cursor y-coordinate, relative to the to - * top edge of the client area, or `NULL`. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_pos - * @sa glfwSetCursorPos - * - * @since Added in version 3.0. Replaces `glfwGetMousePos`. - * - * @ingroup input - */ -GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); - -/*! @brief Sets the position of the cursor, relative to the client area of the - * window. - * - * This function sets the position, in screen coordinates, of the cursor - * relative to the upper-left corner of the client area of the specified - * window. The window must have input focus. If the window does not have - * input focus when this function is called, it fails silently. - * - * __Do not use this function__ to implement things like camera controls. GLFW - * already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the - * cursor, transparently re-centers it and provides unconstrained cursor - * motion. See @ref glfwSetInputMode for more information. - * - * If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is - * unconstrained and limited only by the minimum and maximum values of - * a `double`. - * - * @param[in] window The desired window. - * @param[in] xpos The desired x-coordinate, relative to the left edge of the - * client area. - * @param[in] ypos The desired y-coordinate, relative to the top edge of the - * client area. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_pos - * @sa glfwGetCursorPos - * - * @since Added in version 3.0. Replaces `glfwSetMousePos`. - * - * @ingroup input - */ -GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); - -/*! @brief Creates a custom cursor. - * - * Creates a new custom cursor image that can be set for a window with @ref - * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. - * Any remaining cursors are destroyed by @ref glfwTerminate. - * - * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight - * bits per channel. They are arranged canonically as packed sequential rows, - * starting from the top-left corner. - * - * The cursor hotspot is specified in pixels, relative to the upper-left corner - * of the cursor image. Like all other coordinate systems in GLFW, the X-axis - * points to the right and the Y-axis points down. - * - * @param[in] image The desired cursor image. - * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot. - * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. - * @return The handle of the created cursor, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The specified image data is copied before this function - * returns. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_object - * @sa glfwDestroyCursor - * @sa glfwCreateStandardCursor - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); - -/*! @brief Creates a cursor with a standard shape. - * - * Returns a cursor with a [standard shape](@ref shapes), that can be set for - * a window with @ref glfwSetCursor. - * - * @param[in] shape One of the [standard shapes](@ref shapes). - * @return A new cursor ready to use or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_object - * @sa glfwCreateCursor - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); - -/*! @brief Destroys a cursor. - * - * This function destroys a cursor previously created with @ref - * glfwCreateCursor. Any remaining cursors will be destroyed by @ref - * glfwTerminate. - * - * @param[in] cursor The cursor object to destroy. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @reentrancy This function must not be called from a callback. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_object - * @sa glfwCreateCursor - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); - -/*! @brief Sets the cursor for the window. - * - * This function sets the cursor image to be used when the cursor is over the - * client area of the specified window. The set cursor will only be visible - * when the [cursor mode](@ref cursor_mode) of the window is - * `GLFW_CURSOR_NORMAL`. - * - * On some platforms, the set cursor may not be visible unless the window also - * has input focus. - * - * @param[in] window The window to set the cursor for. - * @param[in] cursor The cursor to set, or `NULL` to switch back to the default - * arrow cursor. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_object - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); - -/*! @brief Sets the key callback. - * - * This function sets the key callback of the specified window, which is called - * when a key is pressed, repeated or released. - * - * The key functions deal with physical keys, with layout independent - * [key tokens](@ref keys) named after their values in the standard US keyboard - * layout. If you want to input text, use the - * [character callback](@ref glfwSetCharCallback) instead. - * - * When a window loses input focus, it will generate synthetic key release - * events for all pressed keys. You can tell these events from user-generated - * events by the fact that the synthetic ones are generated after the focus - * loss event has been processed, i.e. after the - * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. - * - * The scancode of a key is specific to that platform or sometimes even to that - * machine. Scancodes are intended to allow users to bind keys that don't have - * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their - * state is not saved and so it cannot be queried with @ref glfwGetKey. - * - * Sometimes GLFW needs to generate synthetic key events, in which case the - * scancode may be zero. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new key callback, or `NULL` to remove the currently - * set callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_key - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup input - */ -GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); - -/*! @brief Sets the Unicode character callback. - * - * This function sets the character callback of the specified window, which is - * called when a Unicode character is input. - * - * The character callback is intended for Unicode text input. As it deals with - * characters, it is keyboard layout dependent, whereas the - * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1 - * to physical keys, as a key may produce zero, one or more characters. If you - * want to know whether a specific physical key was pressed or released, see - * the key callback instead. - * - * The character callback behaves as system text input normally does and will - * not be called if modifier keys are held down that would prevent normal text - * input on that platform, for example a Super (Command) key on OS X or Alt key - * on Windows. There is a - * [character with modifiers callback](@ref glfwSetCharModsCallback) that - * receives these events. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_char - * - * @since Added in version 2.4. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup input - */ -GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); - -/*! @brief Sets the Unicode character with modifiers callback. - * - * This function sets the character with modifiers callback of the specified - * window, which is called when a Unicode character is input regardless of what - * modifier keys are used. - * - * The character with modifiers callback is intended for implementing custom - * Unicode character input. For regular Unicode text input, see the - * [character callback](@ref glfwSetCharCallback). Like the character - * callback, the character with modifiers callback deals with characters and is - * keyboard layout dependent. Characters do not map 1:1 to physical keys, as - * a key may produce zero, one or more characters. If you want to know whether - * a specific physical key was pressed or released, see the - * [key callback](@ref glfwSetKeyCallback) instead. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_char - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun); - -/*! @brief Sets the mouse button callback. - * - * This function sets the mouse button callback of the specified window, which - * is called when a mouse button is pressed or released. - * - * When a window loses input focus, it will generate synthetic mouse button - * release events for all pressed mouse buttons. You can tell these events - * from user-generated events by the fact that the synthetic ones are generated - * after the focus loss event has been processed, i.e. after the - * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_mouse_button - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup input - */ -GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun cbfun); - -/*! @brief Sets the cursor position callback. - * - * This function sets the cursor position callback of the specified window, - * which is called when the cursor is moved. The callback is provided with the - * position, in screen coordinates, relative to the upper-left corner of the - * client area of the window. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_pos - * - * @since Added in version 3.0. Replaces `glfwSetMousePosCallback`. - * - * @ingroup input - */ -GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun cbfun); - -/*! @brief Sets the cursor enter/exit callback. - * - * This function sets the cursor boundary crossing callback of the specified - * window, which is called when the cursor enters or leaves the client area of - * the window. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref cursor_enter - * - * @since Added in version 3.0. - * - * @ingroup input - */ -GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun cbfun); - -/*! @brief Sets the scroll callback. - * - * This function sets the scroll callback of the specified window, which is - * called when a scrolling device is used, such as a mouse wheel or scrolling - * area of a touchpad. - * - * The scroll callback receives all scrolling input, like that from a mouse - * wheel or a touchpad scrolling area. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new scroll callback, or `NULL` to remove the currently - * set callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref scrolling - * - * @since Added in version 3.0. Replaces `glfwSetMouseWheelCallback`. - * - * @ingroup input - */ -GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun); - -/*! @brief Sets the file drop callback. - * - * This function sets the file drop callback of the specified window, which is - * called when one or more dragged files are dropped on the window. - * - * Because the path array and its strings may have been generated specifically - * for that event, they are not guaranteed to be valid after the callback has - * returned. If you wish to use them after the callback returns, you need to - * make a deep copy. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new file drop callback, or `NULL` to remove the - * currently set callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref path_drop - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); - -/*! @brief Returns whether the specified joystick is present. - * - * This function returns whether the specified joystick is present. - * - * @param[in] joy The [joystick](@ref joysticks) to query. - * @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref joystick - * - * @since Added in version 3.0. Replaces `glfwGetJoystickParam`. - * - * @ingroup input - */ -GLFWAPI int glfwJoystickPresent(int joy); - -/*! @brief Returns the values of all axes of the specified joystick. - * - * This function returns the values of all axes of the specified joystick. - * Each element in the array is a value between -1.0 and 1.0. - * - * Querying a joystick slot with no device present is not an error, but will - * cause this function to return `NULL`. Call @ref glfwJoystickPresent to - * check device presence. - * - * @param[in] joy The [joystick](@ref joysticks) to query. - * @param[out] count Where to store the number of axis values in the returned - * array. This is set to zero if an error occurred. - * @return An array of axis values, or `NULL` if the joystick is not present. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified joystick is - * disconnected, this function is called again for that joystick or the library - * is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref joystick_axis - * - * @since Added in version 3.0. Replaces `glfwGetJoystickPos`. - * - * @ingroup input - */ -GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count); - -/*! @brief Returns the state of all buttons of the specified joystick. - * - * This function returns the state of all buttons of the specified joystick. - * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. - * - * Querying a joystick slot with no device present is not an error, but will - * cause this function to return `NULL`. Call @ref glfwJoystickPresent to - * check device presence. - * - * @param[in] joy The [joystick](@ref joysticks) to query. - * @param[out] count Where to store the number of button states in the returned - * array. This is set to zero if an error occurred. - * @return An array of button states, or `NULL` if the joystick is not present. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified joystick is - * disconnected, this function is called again for that joystick or the library - * is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref joystick_button - * - * @since Added in version 2.2. - * @glfw3 Changed to return a dynamic array. - * - * @ingroup input - */ -GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count); - -/*! @brief Returns the name of the specified joystick. - * - * This function returns the name, encoded as UTF-8, of the specified joystick. - * The returned string is allocated and freed by GLFW. You should not free it - * yourself. - * - * Querying a joystick slot with no device present is not an error, but will - * cause this function to return `NULL`. Call @ref glfwJoystickPresent to - * check device presence. - * - * @param[in] joy The [joystick](@ref joysticks) to query. - * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick - * is not present. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned string is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the specified joystick is - * disconnected, this function is called again for that joystick or the library - * is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref joystick_name - * - * @since Added in version 3.0. - * - * @ingroup input - */ -GLFWAPI const char* glfwGetJoystickName(int joy); - -/*! @brief Sets the joystick configuration callback. - * - * This function sets the joystick configuration callback, or removes the - * currently set callback. This is called when a joystick is connected to or - * disconnected from the system. - * - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref joystick_event - * - * @since Added in version 3.2. - * - * @ingroup input - */ -GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun); - -/*! @brief Sets the clipboard to the specified string. - * - * This function sets the system clipboard to the specified, UTF-8 encoded - * string. - * - * @param[in] window The window that will own the clipboard contents. - * @param[in] string A UTF-8 encoded string. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The specified string is copied before this function - * returns. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref clipboard - * @sa glfwGetClipboardString - * - * @since Added in version 3.0. - * - * @ingroup input - */ -GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); - -/*! @brief Returns the contents of the clipboard as a string. - * - * This function returns the contents of the system clipboard, if it contains - * or is convertible to a UTF-8 encoded string. If the clipboard is empty or - * if its contents cannot be converted, `NULL` is returned and a @ref - * GLFW_FORMAT_UNAVAILABLE error is generated. - * - * @param[in] window The window that will request the clipboard contents. - * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` - * if an [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. - * - * @pointer_lifetime The returned string is allocated and freed by GLFW. You - * should not free it yourself. It is valid until the next call to @ref - * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library - * is terminated. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref clipboard - * @sa glfwSetClipboardString - * - * @since Added in version 3.0. - * - * @ingroup input - */ -GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); - -/*! @brief Returns the value of the GLFW timer. - * - * This function returns the value of the GLFW timer. Unless the timer has - * been set using @ref glfwSetTime, the timer measures time elapsed since GLFW - * was initialized. - * - * The resolution of the timer is system dependent, but is usually on the order - * of a few micro- or nanoseconds. It uses the highest-resolution monotonic - * time source on each supported platform. - * - * @return The current value, in seconds, or zero if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. Reading and - * writing of the internal timer offset is not atomic, so it needs to be - * externally synchronized with calls to @ref glfwSetTime. - * - * @sa @ref time - * - * @since Added in version 1.0. - * - * @ingroup input - */ -GLFWAPI double glfwGetTime(void); - -/*! @brief Sets the GLFW timer. - * - * This function sets the value of the GLFW timer. It then continues to count - * up from that value. The value must be a positive finite number less than - * or equal to 18446744073.0, which is approximately 584.5 years. - * - * @param[in] time The new value, in seconds. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_INVALID_VALUE. - * - * @remark The upper limit of the timer is calculated as - * floor((264 - 1) / 109) and is due to implementations - * storing nanoseconds in 64 bits. The limit may be increased in the future. - * - * @thread_safety This function may be called from any thread. Reading and - * writing of the internal timer offset is not atomic, so it needs to be - * externally synchronized with calls to @ref glfwGetTime. - * - * @sa @ref time - * - * @since Added in version 2.2. - * - * @ingroup input - */ -GLFWAPI void glfwSetTime(double time); - -/*! @brief Returns the current value of the raw timer. - * - * This function returns the current value of the raw timer, measured in - * 1 / frequency seconds. To get the frequency, call @ref - * glfwGetTimerFrequency. - * - * @return The value of the timer, or zero if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref time - * @sa glfwGetTimerFrequency - * - * @since Added in version 3.2. - * - * @ingroup input - */ -GLFWAPI uint64_t glfwGetTimerValue(void); - -/*! @brief Returns the frequency, in Hz, of the raw timer. - * - * This function returns the frequency, in Hz, of the raw timer. - * - * @return The frequency of the timer, in Hz, or zero if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref time - * @sa glfwGetTimerValue - * - * @since Added in version 3.2. - * - * @ingroup input - */ -GLFWAPI uint64_t glfwGetTimerFrequency(void); - -/*! @brief Makes the context of the specified window current for the calling - * thread. - * - * This function makes the OpenGL or OpenGL ES context of the specified window - * current on the calling thread. A context can only be made current on - * a single thread at a time and each thread can have only a single current - * context at a time. - * - * By default, making a context non-current implicitly forces a pipeline flush. - * On machines that support `GL_KHR_context_flush_control`, you can control - * whether a context performs this flush by setting the - * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint. - * - * The specified window must have an OpenGL or OpenGL ES context. Specifying - * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT - * error. - * - * @param[in] window The window whose context to make current, or `NULL` to - * detach the current context. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref context_current - * @sa glfwGetCurrentContext - * - * @since Added in version 3.0. - * - * @ingroup context - */ -GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); - -/*! @brief Returns the window whose context is current on the calling thread. - * - * This function returns the window whose OpenGL or OpenGL ES context is - * current on the calling thread. - * - * @return The window whose context is current, or `NULL` if no window's - * context is current. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref context_current - * @sa glfwMakeContextCurrent - * - * @since Added in version 3.0. - * - * @ingroup context - */ -GLFWAPI GLFWwindow* glfwGetCurrentContext(void); - -/*! @brief Swaps the front and back buffers of the specified window. - * - * This function swaps the front and back buffers of the specified window when - * rendering with OpenGL or OpenGL ES. If the swap interval is greater than - * zero, the GPU driver waits the specified number of screen updates before - * swapping the buffers. - * - * The specified window must have an OpenGL or OpenGL ES context. Specifying - * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT - * error. - * - * This function does not apply to Vulkan. If you are rendering with Vulkan, - * see `vkQueuePresentKHR` instead. - * - * @param[in] window The window whose buffers to swap. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. - * - * @remark __EGL:__ The context of the specified window must be current on the - * calling thread. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref buffer_swap - * @sa glfwSwapInterval - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter. - * - * @ingroup window - */ -GLFWAPI void glfwSwapBuffers(GLFWwindow* window); - -/*! @brief Sets the swap interval for the current context. - * - * This function sets the swap interval for the current OpenGL or OpenGL ES - * context, i.e. the number of screen updates to wait from the time @ref - * glfwSwapBuffers was called before swapping the buffers and returning. This - * is sometimes called _vertical synchronization_, _vertical retrace - * synchronization_ or just _vsync_. - * - * Contexts that support either of the `WGL_EXT_swap_control_tear` and - * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, - * which allow the driver to swap even if a frame arrives a little bit late. - * You can check for the presence of these extensions using @ref - * glfwExtensionSupported. For more information about swap tearing, see the - * extension specifications. - * - * A context must be current on the calling thread. Calling this function - * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. - * - * This function does not apply to Vulkan. If you are rendering with Vulkan, - * see the present mode of your swapchain instead. - * - * @param[in] interval The minimum number of screen updates to wait for - * until the buffers are swapped by @ref glfwSwapBuffers. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. - * - * @remark This function is not called during context creation, leaving the - * swap interval set to whatever is the default on that platform. This is done - * because some swap interval extensions used by GLFW do not allow the swap - * interval to be reset to zero once it has been set to a non-zero value. - * - * @remark Some GPU drivers do not honor the requested swap interval, either - * because of a user setting that overrides the application's request or due to - * bugs in the driver. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref buffer_swap - * @sa glfwSwapBuffers - * - * @since Added in version 1.0. - * - * @ingroup context - */ -GLFWAPI void glfwSwapInterval(int interval); - -/*! @brief Returns whether the specified extension is available. - * - * This function returns whether the specified - * [API extension](@ref context_glext) is supported by the current OpenGL or - * OpenGL ES context. It searches both for client API extension and context - * creation API extensions. - * - * A context must be current on the calling thread. Calling this function - * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. - * - * As this functions retrieves and searches one or more extension strings each - * call, it is recommended that you cache its results if it is going to be used - * frequently. The extension strings will not change during the lifetime of - * a context, so there is no danger in doing this. - * - * This function does not apply to Vulkan. If you are using Vulkan, see @ref - * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties` - * and `vkEnumerateDeviceExtensionProperties` instead. - * - * @param[in] extension The ASCII encoded name of the extension. - * @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE` - * otherwise. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref - * GLFW_PLATFORM_ERROR. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref context_glext - * @sa glfwGetProcAddress - * - * @since Added in version 1.0. - * - * @ingroup context - */ -GLFWAPI int glfwExtensionSupported(const char* extension); - -/*! @brief Returns the address of the specified function for the current - * context. - * - * This function returns the address of the specified OpenGL or OpenGL ES - * [core or extension function](@ref context_glext), if it is supported - * by the current context. - * - * A context must be current on the calling thread. Calling this function - * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. - * - * This function does not apply to Vulkan. If you are rendering with Vulkan, - * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and - * `vkGetDeviceProcAddr` instead. - * - * @param[in] procname The ASCII encoded name of the function. - * @return The address of the function, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. - * - * @remark The address of a given function is not guaranteed to be the same - * between contexts. - * - * @remark This function may return a non-`NULL` address despite the - * associated version or extension not being available. Always check the - * context version or extension string first. - * - * @pointer_lifetime The returned function pointer is valid until the context - * is destroyed or the library is terminated. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref context_glext - * @sa glfwExtensionSupported - * - * @since Added in version 1.0. - * - * @ingroup context - */ -GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); - -/*! @brief Returns whether the Vulkan loader has been found. - * - * This function returns whether the Vulkan loader has been found. This check - * is performed by @ref glfwInit. - * - * The availability of a Vulkan loader does not by itself guarantee that window - * surface creation or even device creation is possible. Call @ref - * glfwGetRequiredInstanceExtensions to check whether the extensions necessary - * for Vulkan surface creation are available and @ref - * glfwGetPhysicalDevicePresentationSupport to check whether a queue family of - * a physical device supports image presentation. - * - * @return `GLFW_TRUE` if Vulkan is available, or `GLFW_FALSE` otherwise. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref vulkan_support - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -GLFWAPI int glfwVulkanSupported(void); - -/*! @brief Returns the Vulkan instance extensions required by GLFW. - * - * This function returns an array of names of Vulkan instance extensions required - * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the - * list will always contains `VK_KHR_surface`, so if you don't require any - * additional extensions you can pass this list directly to the - * `VkInstanceCreateInfo` struct. - * - * If Vulkan is not available on the machine, this function returns `NULL` and - * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported - * to check whether Vulkan is available. - * - * If Vulkan is available but no set of extensions allowing window surface - * creation was found, this function returns `NULL`. You may still use Vulkan - * for off-screen rendering and compute work. - * - * @param[out] count Where to store the number of extensions in the returned - * array. This is set to zero if an error occurred. - * @return An array of ASCII encoded extension names, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_API_UNAVAILABLE. - * - * @remarks Additional extensions may be required by future versions of GLFW. - * You should check if any extensions you wish to enable are already in the - * returned array, as it is an error to specify an extension more than once in - * the `VkInstanceCreateInfo` struct. - * - * @pointer_lifetime The returned array is allocated and freed by GLFW. You - * should not free it yourself. It is guaranteed to be valid only until the - * library is terminated. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref vulkan_ext - * @sa glfwCreateWindowSurface - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count); - -#if defined(VK_VERSION_1_0) - -/*! @brief Returns the address of the specified Vulkan instance function. - * - * This function returns the address of the specified Vulkan core or extension - * function for the specified instance. If instance is set to `NULL` it can - * return any function exported from the Vulkan loader, including at least the - * following functions: - * - * - `vkEnumerateInstanceExtensionProperties` - * - `vkEnumerateInstanceLayerProperties` - * - `vkCreateInstance` - * - `vkGetInstanceProcAddr` - * - * If Vulkan is not available on the machine, this function returns `NULL` and - * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported - * to check whether Vulkan is available. - * - * This function is equivalent to calling `vkGetInstanceProcAddr` with - * a platform-specific query of the Vulkan loader as a fallback. - * - * @param[in] instance The Vulkan instance to query, or `NULL` to retrieve - * functions related to instance creation. - * @param[in] procname The ASCII encoded name of the function. - * @return The address of the function, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_API_UNAVAILABLE. - * - * @pointer_lifetime The returned function pointer is valid until the library - * is terminated. - * - * @thread_safety This function may be called from any thread. - * - * @sa @ref vulkan_proc - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname); - -/*! @brief Returns whether the specified queue family can present images. - * - * This function returns whether the specified queue family of the specified - * physical device supports presentation to the platform GLFW was built for. - * - * If Vulkan or the required window surface creation instance extensions are - * not available on the machine, or if the specified instance was not created - * with the required extensions, this function returns `GLFW_FALSE` and - * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported - * to check whether Vulkan is available and @ref - * glfwGetRequiredInstanceExtensions to check what instance extensions are - * required. - * - * @param[in] instance The instance that the physical device belongs to. - * @param[in] device The physical device that the queue family belongs to. - * @param[in] queuefamily The index of the queue family to query. - * @return `GLFW_TRUE` if the queue family supports presentation, or - * `GLFW_FALSE` otherwise. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. - * - * @thread_safety This function may be called from any thread. For - * synchronization details of Vulkan objects, see the Vulkan specification. - * - * @sa @ref vulkan_present - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); - -/*! @brief Creates a Vulkan surface for the specified window. - * - * This function creates a Vulkan surface for the specified window. - * - * If the Vulkan loader was not found at initialization, this function returns - * `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref GLFW_API_UNAVAILABLE - * error. Call @ref glfwVulkanSupported to check whether the Vulkan loader was - * found. - * - * If the required window surface creation instance extensions are not - * available or if the specified instance was not created with these extensions - * enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and - * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref - * glfwGetRequiredInstanceExtensions to check what instance extensions are - * required. - * - * The window surface must be destroyed before the specified Vulkan instance. - * It is the responsibility of the caller to destroy the window surface. GLFW - * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the - * surface. - * - * @param[in] instance The Vulkan instance to create the surface in. - * @param[in] window The window to create the surface for. - * @param[in] allocator The allocator to use, or `NULL` to use the default - * allocator. - * @param[out] surface Where to store the handle of the surface. This is set - * to `VK_NULL_HANDLE` if an error occurred. - * @return `VK_SUCCESS` if successful, or a Vulkan error code if an - * [error](@ref error_handling) occurred. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. - * - * @remarks If an error occurs before the creation call is made, GLFW returns - * the Vulkan error code most appropriate for the error. Appropriate use of - * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should - * eliminate almost all occurrences of these errors. - * - * @thread_safety This function may be called from any thread. For - * synchronization details of Vulkan objects, see the Vulkan specification. - * - * @sa @ref vulkan_surface - * @sa glfwGetRequiredInstanceExtensions - * - * @since Added in version 3.2. - * - * @ingroup vulkan - */ -GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); - -#endif /*VK_VERSION_1_0*/ - - -/************************************************************************* - * Global definition cleanup - *************************************************************************/ - -/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ - -#ifdef GLFW_WINGDIAPI_DEFINED - #undef WINGDIAPI - #undef GLFW_WINGDIAPI_DEFINED -#endif - -#ifdef GLFW_CALLBACK_DEFINED - #undef CALLBACK - #undef GLFW_CALLBACK_DEFINED -#endif - -/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ - - -#ifdef __cplusplus -} -#endif - -#endif /* _glfw3_h_ */ - diff --git a/release/include/GLFW/glfw3native.h b/release/include/GLFW/glfw3native.h deleted file mode 100644 index 30e1a570..00000000 --- a/release/include/GLFW/glfw3native.h +++ /dev/null @@ -1,456 +0,0 @@ -/************************************************************************* - * GLFW 3.2 - www.glfw.org - * A library for OpenGL, window and input - *------------------------------------------------------------------------ - * Copyright (c) 2002-2006 Marcus Geelnard - * Copyright (c) 2006-2016 Camilla Berglund - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would - * be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - * - *************************************************************************/ - -#ifndef _glfw3_native_h_ -#define _glfw3_native_h_ - -#ifdef __cplusplus -extern "C" { -#endif - - -/************************************************************************* - * Doxygen documentation - *************************************************************************/ - -/*! @file glfw3native.h - * @brief The header of the native access functions. - * - * This is the header file of the native access functions. See @ref native for - * more information. - */ -/*! @defgroup native Native access - * - * **By using the native access functions you assert that you know what you're - * doing and how to fix problems caused by using them. If you don't, you - * shouldn't be using them.** - * - * Before the inclusion of @ref glfw3native.h, you may define exactly one - * window system API macro and zero or more context creation API macros. - * - * The chosen backends must match those the library was compiled for. Failure - * to do this will cause a link-time error. - * - * The available window API macros are: - * * `GLFW_EXPOSE_NATIVE_WIN32` - * * `GLFW_EXPOSE_NATIVE_COCOA` - * * `GLFW_EXPOSE_NATIVE_X11` - * * `GLFW_EXPOSE_NATIVE_WAYLAND` - * * `GLFW_EXPOSE_NATIVE_MIR` - * - * The available context API macros are: - * * `GLFW_EXPOSE_NATIVE_WGL` - * * `GLFW_EXPOSE_NATIVE_NSGL` - * * `GLFW_EXPOSE_NATIVE_GLX` - * * `GLFW_EXPOSE_NATIVE_EGL` - * - * These macros select which of the native access functions that are declared - * and which platform-specific headers to include. It is then up your (by - * definition platform-specific) code to handle which of these should be - * defined. - */ - - -/************************************************************************* - * System headers and types - *************************************************************************/ - -#if defined(GLFW_EXPOSE_NATIVE_WIN32) - // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for - // example to allow applications to correctly declare a GL_ARB_debug_output - // callback) but windows.h assumes no one will define APIENTRY before it does - #undef APIENTRY - #include -#elif defined(GLFW_EXPOSE_NATIVE_COCOA) - #include - #if defined(__OBJC__) - #import - #else - typedef void* id; - #endif -#elif defined(GLFW_EXPOSE_NATIVE_X11) - #include - #include -#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) - #include -#elif defined(GLFW_EXPOSE_NATIVE_MIR) - #include -#endif - -#if defined(GLFW_EXPOSE_NATIVE_WGL) - /* WGL is declared by windows.h */ -#endif -#if defined(GLFW_EXPOSE_NATIVE_NSGL) - /* NSGL is declared by Cocoa.h */ -#endif -#if defined(GLFW_EXPOSE_NATIVE_GLX) - #include -#endif -#if defined(GLFW_EXPOSE_NATIVE_EGL) - #include -#endif - - -/************************************************************************* - * Functions - *************************************************************************/ - -#if defined(GLFW_EXPOSE_NATIVE_WIN32) -/*! @brief Returns the adapter device name of the specified monitor. - * - * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) - * of the specified monitor, or `NULL` if an [error](@ref error_handling) - * occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.1. - * - * @ingroup native - */ -GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); - -/*! @brief Returns the display device name of the specified monitor. - * - * @return The UTF-8 encoded display device name (for example - * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.1. - * - * @ingroup native - */ -GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); - -/*! @brief Returns the `HWND` of the specified window. - * - * @return The `HWND` of the specified window, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_WGL) -/*! @brief Returns the `HGLRC` of the specified window. - * - * @return The `HGLRC` of the specified window, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_COCOA) -/*! @brief Returns the `CGDirectDisplayID` of the specified monitor. - * - * @return The `CGDirectDisplayID` of the specified monitor, or - * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.1. - * - * @ingroup native - */ -GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); - -/*! @brief Returns the `NSWindow` of the specified window. - * - * @return The `NSWindow` of the specified window, or `nil` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_NSGL) -/*! @brief Returns the `NSOpenGLContext` of the specified window. - * - * @return The `NSOpenGLContext` of the specified window, or `nil` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_X11) -/*! @brief Returns the `Display` used by GLFW. - * - * @return The `Display` used by GLFW, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI Display* glfwGetX11Display(void); - -/*! @brief Returns the `RRCrtc` of the specified monitor. - * - * @return The `RRCrtc` of the specified monitor, or `None` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.1. - * - * @ingroup native - */ -GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); - -/*! @brief Returns the `RROutput` of the specified monitor. - * - * @return The `RROutput` of the specified monitor, or `None` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.1. - * - * @ingroup native - */ -GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); - -/*! @brief Returns the `Window` of the specified window. - * - * @return The `Window` of the specified window, or `None` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI Window glfwGetX11Window(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_GLX) -/*! @brief Returns the `GLXContext` of the specified window. - * - * @return The `GLXContext` of the specified window, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); - -/*! @brief Returns the `GLXWindow` of the specified window. - * - * @return The `GLXWindow` of the specified window, or `None` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_WAYLAND) -/*! @brief Returns the `struct wl_display*` used by GLFW. - * - * @return The `struct wl_display*` used by GLFW, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI struct wl_display* glfwGetWaylandDisplay(void); - -/*! @brief Returns the `struct wl_output*` of the specified monitor. - * - * @return The `struct wl_output*` of the specified monitor, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); - -/*! @brief Returns the main `struct wl_surface*` of the specified window. - * - * @return The main `struct wl_surface*` of the specified window, or `NULL` if - * an [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_MIR) -/*! @brief Returns the `MirConnection*` used by GLFW. - * - * @return The `MirConnection*` used by GLFW, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI MirConnection* glfwGetMirDisplay(void); - -/*! @brief Returns the Mir output ID of the specified monitor. - * - * @return The Mir output ID of the specified monitor, or zero if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); - -/*! @brief Returns the `MirSurface*` of the specified window. - * - * @return The `MirSurface*` of the specified window, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_EGL) -/*! @brief Returns the `EGLDisplay` used by GLFW. - * - * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI EGLDisplay glfwGetEGLDisplay(void); - -/*! @brief Returns the `EGLContext` of the specified window. - * - * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); - -/*! @brief Returns the `EGLSurface` of the specified window. - * - * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.0. - * - * @ingroup native - */ -GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* _glfw3_native_h_ */ - diff --git a/release/include/raylib.h b/release/include/raylib.h index 392e0a24..dc02370d 100644 --- a/release/include/raylib.h +++ b/release/include/raylib.h @@ -1,23 +1,23 @@ /********************************************************************************************** * -* raylib v1.8.0 +* raylib v1.9-dev * * A simple and easy-to-use library to learn videogames programming (www.raylib.com) * * FEATURES: * - Written in plain C code (C99) in PascalCase/camelCase notation -* - Multiple platforms support: Windows, Linux, Mac, Android, Raspberry Pi and HTML5 -* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES 2.0) +* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES2 - choose at compile) * - Unique OpenGL abstraction layer (usable as standalone module): [rlgl] -* - Powerful fonts module with SpriteFonts support (XNA bitmap fonts, AngelCode fonts, TTF) -* - Outstanding texture formats support, including compressed formats (DXT, ETC, PVRT, ASTC) -* - Basic 3d support for Geometrics, Models, Billboards, Heightmaps and Cubicmaps +* - Powerful fonts module with SpriteFonts support (XNA fonts, AngelCode fonts, TTF) +* - Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC) +* - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more! * - Flexible Materials system, supporting classic maps and PBR maps * - Shaders support, including Model shaders and Postprocessing shaders -* - Powerful math module for Vector2, Vector3, Matrix and Quaternion operations: [raymath] -* - Audio loading and playing with streaming support and mixing channels: [audio] -* - VR stereo rendering support with configurable HMD device parameters -* - Minimal external dependencies (GLFW3, OpenGL, OpenAL) +* - Powerful math module for Vector, Matrix and Quaternion operations: [raymath] +* - Audio loading and playing with streaming support (WAV, OGG, FLAC, XM, MOD) +* - Multiple platforms support: Windows, Linux, FreeBSD, MacOS, UWP, Android, Raspberry Pi, HTML5. +* - VR stereo rendering with configurable HMD device parameters +* - NO external dependencies, all required libraries included with raylib * - Complete bindings to LUA (raylib-lua) and Go (raylib-go) * * NOTES: @@ -25,17 +25,17 @@ * If using OpenGL 3.3 or ES2, one default shader is loaded automatically (internally defined) [rlgl] * If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads * -* DEPENDENCIES: -* GLFW3 (www.glfw.org) for window/context management and input [core] -* GLAD for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) [rlgl] -* OpenAL Soft for audio device/context management [audio] +* DEPENDENCIES (included): +* rglfw (github.com/glfw/glfw) for window/context management and input (only PLATFORM_DESKTOP) [core] +* glad (github.com/Dav1dde/glad) for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) [rlgl] +* mini_al (github.com/dr-soft/mini_al) for audio device/context management [audio] * -* OPTIONAL DEPENDENCIES: -* stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA) [textures] +* OPTIONAL DEPENDENCIES (included): +* stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...) [textures] * stb_image_resize (Sean Barret) for image resizing algorythms [textures] * stb_image_write (Sean Barret) for image writting (PNG) [utils] * stb_truetype (Sean Barret) for ttf fonts loading [text] -* stb_vorbis (Sean Barret) for ogg audio loading [audio] +* stb_vorbis (Sean Barret) for OGG audio loading [audio] * stb_perlin (Sean Barret) for Perlin noise image generation [textures] * par_shapes (Philip Rideout) for parametric 3d shapes generation [models] * jar_xm (Joshua Reisenauer) for XM audio module loading [audio] @@ -50,7 +50,7 @@ * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: * -* Copyright (c) 2013-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -72,20 +72,6 @@ #ifndef RAYLIB_H #define RAYLIB_H -// Choose your platform here or just define it at compile time: -DPLATFORM_DESKTOP -//#define PLATFORM_DESKTOP // Windows, Linux or OSX -//#define PLATFORM_ANDROID // Android device -//#define PLATFORM_RPI // Raspberry Pi -//#define PLATFORM_WEB // HTML5 (emscripten, asm.js) - -// Security check in case no PLATFORM_* defined -#if !defined(PLATFORM_DESKTOP) && \ - !defined(PLATFORM_ANDROID) && \ - !defined(PLATFORM_RPI) && \ - !defined(PLATFORM_WEB) - #define PLATFORM_DESKTOP -#endif - #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) #define RLAPI __declspec(dllexport) // We are building raylib as a Win32 shared library (.dll) #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) @@ -179,13 +165,11 @@ #define KEY_Y 89 #define KEY_Z 90 -#if defined(PLATFORM_ANDROID) - // Android Physical Buttons - #define KEY_BACK 4 - #define KEY_MENU 82 - #define KEY_VOLUME_UP 24 - #define KEY_VOLUME_DOWN 25 -#endif +// Android Physical Buttons +#define KEY_BACK 4 +#define KEY_MENU 82 +#define KEY_VOLUME_UP 24 +#define KEY_VOLUME_DOWN 25 // Mouse Buttons #define MOUSE_LEFT_BUTTON 0 @@ -357,7 +341,7 @@ typedef struct Image { int width; // Image base width int height; // Image base height int mipmaps; // Mipmap levels, 1 by default - int format; // Data format (TextureFormat type) + int format; // Data format (PixelFormat type) } Image; // Texture2D type @@ -367,7 +351,7 @@ typedef struct Texture2D { int width; // Texture base width int height; // Texture base height int mipmaps; // Mipmap levels, 1 by default - int format; // Data format (TextureFormat type) + int format; // Data format (PixelFormat type) } Texture2D; // RenderTexture2D type, for texture rendering @@ -486,9 +470,11 @@ typedef struct Wave { // Sound source type typedef struct Sound { - unsigned int source; // OpenAL audio source id - unsigned int buffer; // OpenAL audio buffer id - int format; // OpenAL audio format specifier + void *audioBuffer; // Pointer to internal data used by the audio system + + unsigned int source; // Audio source id + unsigned int buffer; // Audio buffer id + int format; // Audio format specifier } Sound; // Music type (file streaming from memory) @@ -502,27 +488,13 @@ typedef struct AudioStream { 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) + void *audioBuffer; // Pointer to internal data used by the audio system. + + int format; // Audio format specifier + unsigned int source; // Audio source id + unsigned int buffers[2]; // Audio buffers (double buffering) } AudioStream; -// rRES data returned when reading a resource, -// it contains all required data for user (24 byte) -typedef struct RRESData { - unsigned int type; // Resource type (4 byte) - - unsigned int param1; // Resouce parameter 1 (4 byte) - unsigned int param2; // Resouce parameter 2 (4 byte) - unsigned int param3; // Resouce parameter 3 (4 byte) - unsigned int param4; // Resouce parameter 4 (4 byte) - - void *data; // Resource data pointer (4 byte) -} RRESData; - -// RRES type (pointer to RRESData array) -typedef struct RRESData *RRES; - // Head-Mounted-Display device parameters typedef struct VrDeviceInfo { int hResolution; // HMD horizontal resolution in pixels @@ -542,11 +514,11 @@ typedef struct VrDeviceInfo { //---------------------------------------------------------------------------------- // Trace log type typedef enum { - LOG_INFO = 0, - LOG_WARNING, - LOG_ERROR, - LOG_DEBUG, - LOG_OTHER + LOG_INFO = 1, + LOG_WARNING = 2, + LOG_ERROR = 4, + LOG_DEBUG = 8, + LOG_OTHER = 16 } LogType; // Shader location point type @@ -599,17 +571,19 @@ typedef enum { #define MAP_DIFFUSE MAP_ALBEDO #define MAP_SPECULAR MAP_METALNESS -// Texture formats +// Pixel formats // NOTE: Support depends on OpenGL version and platform typedef enum { UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) - UNCOMPRESSED_GRAY_ALPHA, // 16 bpp (2 channels) + UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) UNCOMPRESSED_R5G6B5, // 16 bpp UNCOMPRESSED_R8G8B8, // 24 bpp UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) UNCOMPRESSED_R8G8B8A8, // 32 bpp - UNCOMPRESSED_R32G32B32, // 32 bit per channel (float) - HDR + UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) COMPRESSED_DXT3_RGBA, // 8 bpp @@ -621,7 +595,7 @@ typedef enum { COMPRESSED_PVRT_RGBA, // 4 bpp COMPRESSED_ASTC_4x4_RGBA, // 8 bpp COMPRESSED_ASTC_8x8_RGBA // 2 bpp -} TextureFormat; +} PixelFormat; // Texture parameters: filter mode // NOTE 1: Filtering considers mipmaps if available in the texture @@ -684,18 +658,6 @@ typedef enum { HMD_SONY_PSVR } VrDeviceType; -// RRESData type -typedef enum { - RRES_TYPE_RAW = 0, - RRES_TYPE_IMAGE, - RRES_TYPE_WAVE, - RRES_TYPE_VERTEX, - RRES_TYPE_TEXT, - RRES_TYPE_FONT_IMAGE, - RRES_TYPE_FONT_CHARDATA, // CharInfo data array - RRES_TYPE_DIRECTORY -} RRESDataType; - #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -710,11 +672,7 @@ extern "C" { // Prevents name mangling of functions //------------------------------------------------------------------------------------ // Window-related functions -#if defined(PLATFORM_ANDROID) -RLAPI void InitWindow(int width, int height, void *state); // Initialize Android activity -#elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) -RLAPI void InitWindow(int width, int height, const char *title); // Initialize window and OpenGL context -#endif +RLAPI void InitWindow(int width, int height, void *data); // Initialize window and OpenGL context RLAPI void CloseWindow(void); // Close window and unload OpenGL context RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed RLAPI bool IsWindowMinimized(void); // Check if window has been minimized (or lost focus) @@ -727,14 +685,12 @@ RLAPI void SetWindowMinSize(int width, int height); // Set window RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height -#if !defined(PLATFORM_ANDROID) // Cursor-related functions RLAPI void ShowCursor(void); // Shows cursor RLAPI void HideCursor(void); // Hides cursor RLAPI bool IsCursorHidden(void); // Check if cursor is not visible RLAPI void EnableCursor(void); // Enables cursor (unlock cursor) RLAPI void DisableCursor(void); // Disables cursor (lock cursor) -#endif // Drawing-related functions RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color) @@ -756,6 +712,7 @@ RLAPI Matrix GetCameraMatrix(Camera camera); // Returns cam RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) RLAPI int GetFPS(void); // Returns current FPS RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn +RLAPI double GetTime(void); // Returns elapsed time in seconds since InitWindow() // Color-related functions RLAPI int GetHexValue(Color color); // Returns hexadecimal value for a Color @@ -764,7 +721,7 @@ RLAPI Color Fade(Color color, float alpha); // Color fade- RLAPI float *ColorToFloat(Color color); // Converts Color to float array and normalizes // Math useful functions (available from raymath.h) -RLAPI float *VectorToFloat(Vector3 vec); // Returns Vector3 as float array +RLAPI float *Vector3ToFloat(Vector3 vec); // Returns Vector3 as float array RLAPI float *MatrixToFloat(Matrix mat); // Returns Matrix as float array RLAPI Vector3 Vector3Zero(void); // Vector with components value 0.0f RLAPI Vector3 Vector3One(void); // Vector with components value 1.0f @@ -772,16 +729,18 @@ RLAPI Matrix MatrixIdentity(void); // Returns ide // Misc. functions RLAPI void ShowLogo(void); // Activate raylib logo at startup (can be done with flags) -RLAPI void SetConfigFlags(char flags); // Setup window configuration flags (view FLAGS) +RLAPI void SetConfigFlags(unsigned char flags); // Setup window configuration flags (view FLAGS) +RLAPI void SetTraceLog(unsigned char types); // Enable trace log message types (bit flags based) RLAPI void TraceLog(int logType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (saved a .png) RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) // Files management functions RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension -RLAPI const char *GetExtension(const char *fileName); // Get file extension -RLAPI const char *GetDirectoryPath(const char *fileName); // Get directory for a given fileName (with path) -RLAPI const char *GetWorkingDirectory(void); // Get current working directory +RLAPI const char *GetExtension(const char *fileName); // Get pointer to extension for a filename string +RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string +RLAPI const char *GetDirectoryPath(const char *fileName); // Get full path for a given fileName (uses static string) +RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) RLAPI bool ChangeDirectory(const char *dir); // Change working directory, returns true if success RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window RLAPI char **GetDroppedFiles(int *count); // Get dropped files names @@ -873,14 +832,13 @@ RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color colo RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version) RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle +RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version) RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a vertical-gradient-filled rectangle RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a horizontal-gradient-filled rectangle RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw a gradient-filled rectangle with custom vertex colors -RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version) RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline -RLAPI void DrawRectangleT(int posX, int posY, int width, int height, Color color); // Draw rectangle using text character RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version) @@ -912,19 +870,23 @@ RLAPI void UnloadImage(Image image); RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array +RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data RLAPI void SaveImageAs(const char *fileName, Image image); // Save image to a PNG file // Image manipulation functions +RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image -RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) -RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) +RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color +RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value +RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) RLAPI void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm) +RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) RLAPI Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image @@ -940,6 +902,7 @@ RLAPI void ImageColorContrast(Image *image, float contrast); RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) // Image generation functions +RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color RLAPI Image GenImageGradientV(int width, int height, Color top, Color bottom); // Generate image: vertical gradient RLAPI Image GenImageGradientH(int width, int height, Color left, Color right); // Generate image: horizontal gradient RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial gradient @@ -1074,11 +1037,12 @@ RLAPI Texture2D GetTextureDefault(void); // Get // Shader configuration functions RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location -RLAPI void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) -RLAPI void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) +RLAPI void SetShaderValue(Shader shader, int uniformLoc, const float *value, int size); // Set shader uniform value (float) +RLAPI void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int size); // Set shader uniform value (int) RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) +RLAPI Matrix GetMatrixModelview(); // Get internal modelview matrix // Texture maps generation (PBR) // NOTE: Required shaders should be provided @@ -1094,14 +1058,15 @@ RLAPI void BeginBlendMode(int mode); // Beg RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) // VR control functions -VrDeviceInfo GetVrDeviceInfo(int vrDeviceType); // Get VR device information for some standard devices -void InitVrSimulator(VrDeviceInfo info); // Init VR simulator for selected device parameters -RLAPI void CloseVrSimulator(void); // Close VR simulator for current device -RLAPI bool IsVrSimulatorReady(void); // Detect if VR simulator is ready -RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera -RLAPI void ToggleVrMode(void); // Enable/Disable VR experience -RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering -RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering +RLAPI VrDeviceInfo GetVrDeviceInfo(int vrDeviceType); // Get VR device information for some standard devices +RLAPI void InitVrSimulator(VrDeviceInfo info); // Init VR simulator for selected device parameters +RLAPI void CloseVrSimulator(void); // Close VR simulator for current device +RLAPI bool IsVrSimulatorReady(void); // Detect if VR simulator is ready +RLAPI void SetVrDistortionShader(Shader shader); // Set VR distortion shader for stereoscopic rendering +RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera +RLAPI void ToggleVrMode(void); // Enable/Disable VR experience +RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering +RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) @@ -1146,7 +1111,7 @@ RLAPI void ResumeMusicStream(Music music); // Resume RLAPI bool IsMusicPlaying(Music music); // Check if music is playing RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) -RLAPI void SetMusicLoopCount(Music music, float count); // Set music loop count (loop repeats) +RLAPI void SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats) RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) @@ -1159,7 +1124,10 @@ RLAPI bool IsAudioBufferProcessed(AudioStream stream); // Check i RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream RLAPI void PauseAudioStream(AudioStream stream); // Pause audio stream RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream +RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream +RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) +RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) #ifdef __cplusplus } diff --git a/release/libs/android/armeabi-v7a/libopenal.a b/release/libs/android/armeabi-v7a/libopenal.a deleted file mode 100644 index ffc90321adfa1e1488cacf200165f3ce2e3650f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1207292 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 QuAjgI5!I)=`p?n}5D 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 NX}`!dC6=h~e*=(a3U>ei diff --git a/release/libs/android/armeabi-v7a/libopenal.so b/release/libs/android/armeabi-v7a/libopenal.so deleted file mode 100644 index d0f913a64bcc9a4c19f08feaedeaa13f5b8d2634..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 861680 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�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

{Ege)up>@I6e+UZ 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

=)fjn2wXL{M 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 z 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≪$-3<)j(o)(lFoYhp*M9uG?oyL&$muM)#0_O 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 z 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 T+?*(z+BA$KCPmgtu$lXR0@Fk- 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

3*Et~TPT~Bidj?8 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

>P?w`G<+gyl7%zFT*U%K*8%KoADBM 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ྦr0TJ3Me@oN}8FQ4x21YgKz9W1i|qGJ)W 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 z

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�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

&qnvmff&Abn!4j$p^&t2qrA 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 O4-`ItVxrUVzyAQJx;>8o literal 763552 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%0AOM6hZPZ5$1 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

  • @zl^8^y0e(%EZxeznqziHlq@VS=Ahr`QBiF~X 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 z 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


    +Z#YbGcEadm;}#qCP)AcX+>%BTvuoKWb>7 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

    %7OVoFb9xMX0QX&v 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

    L>hhE*v>(#iR58< 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

    S~7hruyyOUCEyMretSVM?2W{TU)nW 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

    g@)VR) zs|)H#;+*QGWTt2LwM>l|+C_X%?4=Z(S-;K|Jbtl9whym7GWFTSS0bH`<1U4*XpVXl z!R&lVAs06FkTE5=FynA_!Byb6cFhY+wia`tgCYGn;FcL1Mh_-r8i8e)6QS9N#4HhW zZSw4aep~W7TwQ5RcCo|}80#q6OvE08Ffj_~%t{N!nP~a?I2XTewbVlU@=A&6w|A

    WrV54Ww$9moN~NdmrIiY%oSA!R#W^k|xTfl_l8U*t z3h@^$KOB3d(^JYOH48?aM3vHZZahh)(aizxvS0g3X$@M#9ojwjEihf%s;G9HE@0J- zTIcJ@s|>TL)yyKbB5JPVx=eR#lNqM{J(gQiy z+!3O=ty4PL#XKdg11|eM<+-+`)^xX-`%k^yQYm8bTGUn zJ&v$vDe#;zWK&C5D-z_f;upH-i;(Hu)E;MRFI`bjs-BI{bV+G5$-jm@m0N)ne_CZ@Z^B@bk4b?4glcBpx}dgR%A*$k46?I!S`l{QoZp8+5C32TJKgV4_tkxR0 zVd3Y}EL&tot#jY8l)^Q#(sh>SotSyNhCbYMHm&831#*w? z3A7|TOU0mriaRq)s!0W-J)GSoJ4%_l7QJ7m-m{ofr=hVCM|7QQT5!6K2?B2VHI+8j z(z!m>fUB6LBI?9C3~w4VnNhTqg5>$Dh?}%o+aa|E*sFr@wdRf`a#1EQTiY-YUi4a; zPIYrM-F2V^$B(ivvKD=y#^tE_qJ9-kw?Vwpp|4t0%Z-0j3Nz(!jJoS5PJ)`ue!3%d z8*1ukz!mhyE=TAJ>f}d5;X;^GwRGbk4mY-AMcmQp81PufdmwlprLAezb@ujHNxf~! z>*`V^CEMj}Zw^_9TvIgrwsR=7cQq%m>pZsw#9P&VZQI;2&nYd$J*P?`_BmB>mLa!T zP<~Y%4O?-jgV7B~8zudLa0^~sd2PkU_O`~>?xy5xYj&DLnai7#$yO&ySNVsV+HvY7 zml8`!=cpZPP=h<0YZ|a%@`Uu&b59eyKIud-ms(X4QxP1zc6VUM?KQP){}Ns7X*&j8 zsV|j2T|+ygpA*bo=XHqFPS8;(nJm|e+);E}YH5>GaTz%-LOp54jBq;!P1EI-)W?*h zFg9G|=_3C;16#CDZtOyZbYAAt`0!p=cSGykaW|NYaAt?O`)bTwP-&!B!buDEWVM^V zsFaP@$Z&Kw@?uNL8nK|LTY z#Nxf$61EEh!-$!4n?;TuZu&#IOW(vTZFuV(&bhjvSJ86yLXK8Frd4g7(wltPo=M|y zmWx^3?sLr(u^YQ8k7+v(f69z|`GYM>$N4s&aDd5$GfY*K}kjM7B~y8?BgE z)i+h!PHn{9k>qNt|=F|R@t233m7n@jSBscW$(RU`SJ_i8xAk8SO&p+Dnz=hqT;<5UKkFqSn=Kp0Dg&MJ6gB4 zp5J(WJ6{US>-v2kh z1782!c`5Sx`X=;Xs;actzs(aWvwhn9q_;c@A@vFV$<~s?_WPHhy@?Z4B>{W3Z6}cH zLG0oBbYoY2cbiPa>g#K&T;f2*&q*DxSn&%j-|_d(3nY}~NpgLCvblbXtOQi(_pjpD z%3p%->&UO-ci#Gf&sa38ME@=Ygyiu!Z7~uVJ{=So$9LPMiA`0{3oL~K!r7nt3gFWN z=AV3H<`(?B2LJxjUtP@lcWcLyojZ=q!n({vBu@Xj2-yp;@G@D#4<`*j~i9D(xWZ1FZgYhdL48AQ5sY#E7*E9u!w@RH? z-w(tF>T*b#sL{Krd9lXX*nwXm5wFCor(#wetUeO6YDd&^MiZM6_Tw?@C$UVOO6=4f z)zsN8L^S@Lhf+uxk}&dI@TBMw{HdMApSr`(1w%rHgbdXk)<_2SrjQj#)kth$paPHg zMc^Uxw8qYZz2%}LUhE0usm6LJX7w$>6Fu!~Hu7g;R%K5t)0Z$*WeSg*^|2X`aeYkS zF{Y23@fgv^I36YXSZ4PM!}(AQ#v-vybPBivmCxPX_31ApF4qO7v0YktM>VpC(mBS$fiyGm_QF zj`3HR9g@$Iuneq&QA^=V&1CT=2sOGPT3jfXS~+Gz){0 zU(W?^7*GuDHll&OlDV+dcM$Of%MS$0AAynGLa{{qLXs?TYGC&S*jjTRs~KRq>=^|U zMOc&Rlc$)qd&DpvK%B#PVwq|)&)^dsQXlq+PRx42)Wh8xt}k2A?kh8S`HPsfN@_sB zP^(gSoHYSgNe!6MN2vi*`Y1IZua9v&io1ww(r`LZ16HvHtYQsVRe=&l4Oqn*u!=Qc z6>Gq%kk){1)PN4ufcdBak{u>ZP7~G~%Ip#UO`4qYm!d8z|NqyX{%hM)Lfcc1sip&_ zxewHh?vswE(wd1`J7&?tN+)%Uw3ty6YePcaZ&P8RayC^V)IpnCDAc%3oh;O&Hnmi! z37fi5s3&czOsGklS|ZfbHdQWE-lkRv^{h=DFVvJxy+x=)HuWx{W^C$Wp$^9~mq@Fs zVGnQZtuW2y@fzzfv_|P`YcSYZebPU%HNu3&?$z{&Db#c65z(wnkC*^TkGL5qJz^Y) zoWq!7**&TDdZsgFe=Yr~-C3hS*_}1ol-*e`!6Q5C5FSlgWp+o5yLJyNmgTOGt*We(=@kCUYqwg>1!#WEd4srfS6i>z+!DdsNuUyqGNk4S%l zdG<;(Y6k~C4Kg+m9kqwN#_l7rZO&Ye2fE z;I8*0(rM#}VfRigwEDV?WG!;lBRR%0-DhxD9hNB53m4k6_?3&wU?8|l{*QSY&$)(U zMMuV>cN*K#J6A?Wf&;SV%NW^#{Cq?eYs3h3N*LV8%@-c)NL=iG7rS?AflJ~JfF!#l z-Z1lB5^or{#2dzK%^Sw;ffL3ovLp{O(K}7<-#L9Ove0DS^fSmT&6T_|KE^LUpM*mbyq&!>(rjP^C>$Py+iZqj+N2u{|)(chsmcq3i)JLCA2;?x$C9U zn4aR?MZ&S7Lu1j~G>dLq8664^Y!toAa~UH(kY~+a0xqUu3vYJ#h({ZWPbBf1u$ky> z#+Tcszv9$wiP_Y0^izwrd|Pa8X1{fk!Pw4&(o>ts&MrJS`vYdOilv{uFn9X$teVxK#g0`yfuD%rZ)e=i zTZAk-%DzMPbWGlhXqF-;`#sXbj+A|sBh^ATg#&YeY1x*tcaGXo5ZpAHZiAzvvJY$f z__XoyY4H)p{>OZL_FDxXAAx(LQhRM5CykGjPCm-s-G5I$GFxR^YCP8R@E{_NEig4E zGfy&mo+qO(b|u1T3Z|-HKdM3|G~AEE{6`i&c71p4L7A-uGjbyc=0JmHJ>bljo(rBM zq0TY;ReoJ(zErTS&FGk5UyYq*P6PL~Zd3Ujp;P_lYWn zmAY)I!1NoUF)d#Fk2-K8y!an=z^Uk-`W^Pw36NLLm^O<)C#?UvG~f>(crN&^TtEJr z%|Vh62#Fm+B_sV0;qjlL_+X@eEO_^UNdJ!CTX=XN(%=0%>!F)#e;2&_M^!gRe_t8A zd)#g~Ve!Q?zJ%^Qii|39irbA3e$C~NaR6H_ZU=q@2N0viyW=@)EE2r?`J3yW3*P;N z9j95a6xz3}SOK_w z)L+3IoBzzBSDu1wYQ7A`pE}JYI4@8k^BoMv4Z?j6e|GLTyy_<8Qr|m3*fR<}R6*v+ zp~}}#@b=Ic0?T-!YfnNF;R6PY@6>mMcSQhaQ?u?cC`%2KiO%-+EQCF225JwiSZ{8j zYmE<;B_&jr*ec7gkGA~zub}E6Y$n8-V>g&IEZgT@j{m#Lz{Ku_%k!f1K0CeU*blS# za}mTOephkgjSF|e1=N^7EB*^$%$t8sOOV=R?A_wAXU|wr8@AZzzW=yTHb{w|4XZ8p1|Fcj_1Ir)HO8O)H zFIsz>%(2G<{p0-ujrOkR{&_Cl??N|YtKHmJP@3;j`tn>#w`2;j-ZF>MSoBZ;zd}b| z>S_P!pOTKNTXQ3`#W=Qi zHzRqO=+i4PhZ;Bsto;j+fK2z(nkkL7*xlbPIx%bEBhZssZuIHtM_|)bmHd~b>K$U$ z8;eegS?sqPdr!4GRPLC#QKa*zM`vkCorm2zeaAwl zkVC~5A9QQ)Ds9oD^O_d#c3XT+?XUbr+PD2h+BbW&Wfa_h6k`tZ8jr4AVVU|1WVYJ%Ng?2-}ERDu``um%(hKm2OKZLcQW`D((?mJrJ7#5nW~2z}#c zv11PuER3R}2JV$>QaBWTGIPp0tT3#)C#{F92P&ANHc|Z}tmp|ab3m7X zVi5WNP$7<(p1f!o44AoKOfQPui?TBJCia+P3TtoNv^N~S?2ehIz6d}AW>lEjBP=vc zQ7{to=iWdLmh_fKOg$d!t3g{u1c9A<%@ay3IB*^4SfdfebaogUSQx>-oj6llVcSIC zYt9~nZ{WoP9?6*V8oh-87hxV}G3E#-GazAcs{oFHjT;6T6Nl6u^Duoa*rS0#c*$9Y z?d7{1FU=G3FF5c)^->t#3G-N_Oj3jtl#q!ekTDVyuc%Ca1AhwLgU)$hby}>-3t?)^ zoIZ)sUUSJK6dd>n2$ZKeq330v#sPC?a^M-hABl-Ywx1b4&Q_Dq<%QCToKcWPMo+p z=8p4>qTn}|2p)2RpX3c5EDHX?62V{Z1b>4!_{)FePx0{xZcjzF9;b|=sgIkGs!ZLT_88Ct2W@B06=%-EpAyatiZi#koe{;?aApF| zbg47)NM|OEGt<9EYqVp&8tb-ukCAL>?Dc0uzr?)D9kVD(%%WS!hUqW441OqW8!XP( zGz<>N(P1f@-mIOz)MfK>u~{ZgUWg}8S?!TCNHHrXj&8G}F0M)lm#fdsFQol4$Ls|~ zW>YlVI)_;a;WB%N%j{;yY*7yEX{OnxIn4SpAqum0L*FHLQ0-znrQgow#s1p6M-GW4 zN3QV2VHci+aJl{r#!)8@nI7FcgVK#EvRf}qPTy0c`G+|)2Z}WRIEQ9q zk>+!AXyTTx&(9{*-BNza|J>G_qOQ-B*8F!Q*Q?nxhvxT-H03^Usn}(Q&TDi29GY@a z<<%VdY-yV^74&M}Gl!-u(CvZal+QcesPqZ^UGy692a0-){WdkAFq`lejM| z1CBMj?0L@BF_W4^47{FJn|WOg&MPn<8y6<-i&%X*JWatxOdp@bqdfKQm8WoU09h$> zSE0ss^*s%cU&b)ZR8S<-{{-H?Wf`dAvKHLJ)$Vl|dhh!dS^%bnlCqkCMIXdcrSjf? z121YlQf)m5Cq@yv#`;%l&t2vL7m;@lo2MsY)<70daBm1;+`}|a^vxxgJw})@+7#{; z#f-6JIQuG$Lnd~ex*N7W>JGPFHdnUErQW@hFoH_)cSyIX6z~2bD#dQ$vf!~)dUyyt zqp4A2@dS=#vd7DR#PIXtm`DG0uxj(8%NL0OwQMa4i?Ojq=FdB%=hljdOf(G^( zkRbCLGwoL%jk8>p{ssOYmay2amxZF+f6V3G{vS5(9G+JHXEe}^CYt`wc>JF+0cPlb zVDX>pKVFUT=0A!AiI*Z-Qb?tgn6Sb&3(w_v=1$(u9ftyG$=X7B;0mleJ%@~YhnOCd zcRP0gyn%3w_5_KQg*asbO)=235FqCO^9zNDTez-5eAWbb)?~t1G%o?T9k_GH)0%mA zfrtBSxP=unJAkK1GAvvNF+7CF24U|*I8J&D_p^Mm`9_9-MKUA6`Du}$H>ZJc;j4sf zfeE+BFEgpgn=Q%3vL*Qe)JfC1wB9at5slb%x`nz}sGsa~oI&?Yq>kgNskt}?sBjkO zmsCJ%%7PatY?TXbmHnUTM|Lg0(9simpETfmr|^W~Oxj$`dcau8Tq4cHJnmb7r~72e zw(Q|$M=PxtRc6&rVyx8pyf4lbzBpIdri>5TQ9Q<2PYK(?%q31O-6xUXCo@sGP=)1g zjuAT=POh8=xyjI`Atdh<$p(A)ev2)-*@z_NnG;qN6dW6WZqAA?SkU1w&Kq;Dm9yx0 z{_v&6vh`u@M#OMO9{zB&{lQLImLN z* zROWwF|D61AdCxdZmYYzfW7H?DThHUET#aM={on(?Bv{fJ@_`U z>o^b@*I-*}P+j)CbANNO6eMuIF>6i83aRitG4g>KXn_uzkW0PbqMVBIK-_7kQJ`(H8!B{r18b@0n@SLR-`nPYAauDrI5VkGP}bg zQn*B#%flO{b7-+b&XW+ePASyGXxn z7g=E2MK0KO%kZdnE3o6S!sG>CksX+lEfH(Cyc(-@MAMnMRUA^ZthVTHJw9FMu1g_=A(PcTDedzsOYwx3yps~z=U{$71zyxqD zRs6kciFJgrSXgPe79D12Lh?-2GnQ??`;NE$w1;X*puLlL39=pgM*l5&FwQ&>L>>tI z*XDsNy#7Dr!AkUGV|^D&hTu15PU7`R&bQ^s&eNj0@M8%7?7ARt$xB@jL_P?-W0f0+5p>XC0^T{xN7V|4pXxt~jdrOlXIsWBeSd++O? zge_W0>cs7tJ@W9vE0)RKZRYP{9N;5c)n%!YrHy=C->Ta$WjiWcahW|549ezS0&bvl z(f{g>+;2M~4==p3Ew^}qxxQeTzy2!%GC100-6!3$$y2-ixTn1(+LC*;w&(3;P?YTy z^DzC?EK=aRZ{QibrEk0Q8hevPdOy8M!QJpmtGdj7922Q$H%78be(oKbQasfXJzI)S zR5u7L^Q8szPV(+yi+(9?Zib|N6ze0OOjU%Io#e zaptR-&r~27W(V=uKy4`ahUf%*shz~&jWb}p)QPdXJ3kg37oTHe(VW4|$FV;6Rm{4! zCzknm1uz9H2Q~x4zyxp!a5FFjjK?y|Vwq|TGV5a?Be6^j7S?0*iXr%V3|%ntR4=1Z12FJa#7-E3EClwmY4!;%b>LOd&k zoU;lsC4|g@bZ!+0q(2ZdFL=v4-*58JSgQUC2sELZp4OrZ1hhUiYm>f7|LHRnxky3+Gla)Bk#WQ@w5~!?>S8av7ot9*o*z&;O-pgo1>5QM<2gA`uOlXy~;BEFx1W2A1@ zMSLV+UT{EDdq_F}B*I}#31iy08GX|1;XXP2Cuyp^2V);~)(<04a9#<(E8#UT>wPnz zcIGICn(^N0#gOH#+NXmzt;aZojw>mE_w4+)Ld=B_v-OFz&f-D{P7}JP&~ztopkDW= z^?+47UVI-!vc$O)GJO=@^O)XT=_q9`C+6-KbEC$b=SGK2@C)WfT;}8i|32Q+aCP5U|r%e*WfqDI|^=dSuuBqm>cq#GnW&vtZ|upy~~{3xVZ1aw7H<+ zHYXQY>TVHp{l=W+T1-)TLDDqdwh4AwAi zW!W`J3MYokJ|RgGe9ac3u;)CIB#d|CI6A56G+V8B4_r^ zM~W)V?9ZJf6ifFVlB6L?k`=uzYGH@Gb_gkx0CIatCXDWs^%s2grmTBhCGs9l#!c+Y z--3LXlEOg_?n@NZ_649@kT4s>fYHHNuye=3A0u>d*Y8d4Ex)W=$0M^?>(>}FI}Tbe z?fmsmpl9vaW!0sFyVgUS-S@8Zo)UrXrtDhh7W~WzWV{ac)!G8?P%eKXVzN(?mP2Us z-|XVc@vY5Y>f*}`&_qw6DRk$Z9XGR36SR6T-^}%Fv(5cNm$adAdg6Y`Y2UjLi}goS zrEqW1{lyrW`s_TIg1bkBCz@piO>OFjC0)HZBoFqTAWvK^@463! zsr{y;O;RIBs|L(X=c zOg{rkTKiB~=!f8t_CqFndLkxM+zM5;f?2&8tyGn2$<@}U~* z5!I3kx393+e;A!k)H-0*V&WK`DyWzzjkhO^4(5}-yb)ipAYeaT@TI2MmqPNxuH>7u zA6E`IjywxTo>eR2rg@q^SE3gZONT{Awwj9*vi1qp%AdNtPoIugz;W!~c?wk=KfZ+H z@nXl#emSm$Wj<7)nW!oYV6k}11LH$LqAS&uTCISJoDPperrtT^0PawAWGIugzeqCUq4~=lW)q4or z>rsA#i_v1Hg)c1}uTjrr*n{EDm~}ut!P@)lMKLsde33ODyy?4WU08TMDv$xwxsK0z zHIrf2hSzW5@yyDK;4MpG*>rt+-#~7fX=9&>VXSkNgxFYyH5G0mLFGs24zV1}RF>6n zr+xbUh}P~z5tH_4u9)6k9FwUpIFiY9piy*BN^QYrjz;P@=0tkn8I(;OBE?s{tVf)9 z<($P8ul8Q9cpXEfQW$>i6o#FcF89Wy-Hj`zvr459gSMn_LxtUhrX7b|DZ`X zDf^XePYNrO(oVt^pJS+0%F16mW#vxFc6ejbrtOO9Rm%>IOj|nE=&xON&@QA<+Oe5N zI*sfYa5!$FWmI7QZ?F<;yT8M~GqJ84z`vLAZ!4y>CGH20psS7z^us7>LGkx=IS z*n7((IF9co4eXu(7)N87K4JCtgz<^B5yVVJrYDT=Dw@wa<739wz_Fy}Cu{FP zL*omx4?P$A29BqUdD&>h-BTmFCufYwe&ao(`dE%fjY4)E?-^Dua^s$?KB7|JGh`l@ zX}h{VPP`5AIJtQt z?A@jI%zNnbA*2&~lx;h4x01FK_bBOe;{JjY^5}J9DV(?;!O)ZDVtUwmUqonptQX3e z8#Y8q30^ycM=eb0aQn3|vA<>Y539l? z9<%y5fk!RO+8mnpc+48q((Lay3Z^PnWp<`PRat3)jB(4GnDRnm(j^m9ZtcD6&ri%K zyviXe^xY$PWMYQ#$i!sv$ixicF{`?Rcw}PINKF5ql^AhL6Ek2=cwz$s=J-|*zV}67 z+Ij)^_vK{0hKJ(TUfIjRI!`_?n;B4Ich>Omx$(XsJk{W0w__R?yNwWEhTLP+aLV8k z%EH(AK&t&w*%Yd!*_pQFGpY7RWfOSZY}DmrsrE-@<9IY)>x;CmucqcD-b{Q2SZMa~ z3Sb4W9EgqhIGXr}!oVfKCBP6cBp1*#sWRP%KM5!4a^Pk1Xsl0;oRB5B2q90$2M2x! z0xu^Bg{+VY8QXbamoT^G-V&R4Kt4lrqZC`l=q!?RHZFJ7Mw#x1D}k3G&EnKp$A_oR zL%{uS=zH}jGRur})8(S9r*CunLuK`*H+Q1>kkxMSJM)Q~7iRWILew0r(P?woC4y=B z@|rUSoD2nIymZs{glGEU!t6o?oXWW7!bi=aCjy#CV+*alx4?q+cxFHlho}O^1zV?Q zp&>bYpk1A~xTmS+YOWKe%o^xddjej2I$@$}Z%+u#ce7-kPQVy}&QRudJY?0D>-JUZFh`w0Y>JQ74633y{W*-iHL z9A7dbo$9zs+gFQ@xAyihB0)qX;I^FUIo>9v#>RSkWHlmn*xY?YLQO^Hy2H$N#?0sJ zF`F!GTo!8an|08@z+G|T+R}XeK`x>PY9_k=1dfs*{ry40U8h1Mh7sci+tNP3m0g8KE+nS zg-A9l?Fe-z+%y$4rbs29K7e;m#`+Gy0)nC0$P)(Eb`TlE_Kuk%cE(I0oH0`fjF~4% z>@sF@_j6iS4YcezJ43BlFPw6mtNH&Z>iVQhc4zYv+&wiia)=uIWJ zUW^UsSMIgub4G>#SA<^7sDKZ$QDF6zo2P*=KATTAu7rEuOpWK&_tA27{Lhkv=eThp^ zkL13@rKm(P%!)2W4Jy-Fk-67r?KouY*%fBTA*Z(V9!z-rsl05XbH!D!ge-ghKIuIx zMQ7F?%_NI1E zzC`=h6g&;-V>2Gh^buW>>08;8&%z3Oa)})^Va9N7h=Ch{u1R?2dX(r5D9-CqoHw92 zuSap-fa1I!#d!mY^LiBL4Jgj*QJgoRI4`QnT#9X>b?AWp7bdyoh+BQt($GXc6dTwv z%Cb?aV2@gxFO#~8OBqM{11gpSA~>IAEnkB>kh>Z{9>`p{6&49DA@ts zmyOIFVRmtKLr58tV6F)x39^pAK0!ATg&h6}WqxkuRFa zr6OdD>|0$6o3aOTEo^p=1CcHAjrnU~vwIYXZ0R1xc0R5NtcR)h;l}KclM=lS_0h_! zq`yVOw? z_f)WQA*S9Q*~oSUE%ybLJ!6*`mBC|KCPOaq3b#1Zqem?gYogsbu_4z+5@Z@KO`N9;=O3eS}0K2Hc??h+K>y@);-6q_!Cn`tf%o}%* zFbqlmhU+*-a1aCIGuBhqPvrj^Vl7;1lyPbv{0>Bo2e5mrFE`k!mzy#;Zp4TDYoG1K zi=e?<{t@|WUkQlj5ft|l-#;E4xDkAFZzxmyEUXE8fn1xx_iejpA~#=rs@gfXSUMHy z7inHTd>eH>8QuF5jw0nlGqP7bHSb(}eDgceBS_@}{I3z@Q~q^R4=p@azk822NoA;t z=BHcG^mG`F;?2~f_+;mFR9a(Zhj#Et{*>;>xz78{el@Pz%_6oyra~8qux2ucr>;1n z6Dh*yGpU96#%l08FW_2NCKbZxWd6|myT#bRp0v834Bk|R-VPI5>GZHeG3o4IqoXb4 zDsEpKHeZT~&PV}G|59R(9>V6mmGf$u3qRD#sg_s4T;Yk%$PJ$9FGFEl^w0vo5$c$z zTzX&bVjEg3FIrGr} zKL_4cn00f_vor@SvcbLRY<`Y^3sI!+z`ttz`xyRZ@Xskvi{lgy6nH@eWhbi?WVynu zY|lysidk<2%*3qA%TPOU>k%8ZMfWCo z{dpF#;YC!u3m@F|kUS17KOXrZN6MN&v`&a;AkIK6`{`x^;HtE^LdfcfD@S#B1Dn;^ zG|5}55DG_?XadqO4m^YQu3v4tPtq%Uzo_(?9XLvnp#0yU;5s!fl01vI@`Z=CG*3Lz zRw8dezY#(8AZlQFqR!;ktbGCm5tQwgV7eeqn0WO27?v(ZGJ7L7U)7=Ma9}hKsn2MQ z%czLesQJc)eg_XGR@i)e!VZsaj(&|Vvq$(QC~n*0QI|}-jjk`Yna}na6?_p7Dqf)z zzIU&Lhm#dZs9l!-hrM@!v$87tzc&g*Ce2XdLngUBkOKk&g5m+4kr^FwMn+)}5u6!^ z4NT6dIVh;;5R9?eZl#jK(i%&XN{#Xm9*7Y!&`3u!L(>|Q5|k2^3=ir1{jGJ~`!st{ zpa1iJKhOJl+aH+keXZ+S*IMgZ>t6S|5BuJ~oR-)X8HgxC8`Md>>ND=&t7&5=$b7ZC zYZrH}e1ooLlorQVjmJ0NA>gkIebRuh6R21|tj*av*%{@;byfU+rBl*K(plu^ImC|w z#c}stoXzc0>BIB*i7gp8hprT!i&uu=@KqeYXSZbD-v@rZte+&7scO8dvAd~FWB+un zD_d%Q>x;ksWuz>5CD`Ehb#`M&rR;0lzWFtrCtEj>O^ZtRT#tIdAX=Tt6$jdg(Fa#k*pydz|Dp{rty?d3^BIs!)0#3|^9&rjs=6u1HPe zY*T5iscC(ET3u?I&bP3epOTg+>#IKQbhIA;?y2qepSc|6-5k2<$WzIf){%d39l1pv z`3KjW#PHY^bfkZlh2>e$k=ypwk;H`qL-`i&uF{d6&Zq0hf^%F)b_V;4)zacizivzG z*NvDb-|3s^S6)_P{rX_guMZ~sHT`@&mj>@GqtxJuxYJy1NPS(YI&>HG6=Ej_ich;r zN--c^@pvMK?)|6aNGdqXNmcwfk>j9r#mm!!!Z|-m&2g|hT&i%cPNgaaBouk+ijIV< zqtX@MNGQgnD>fz+r=%->kx=BPDyT=afJct>yB~ZRMN@ua{vp08?>9eO15Kwg6O(=Z zY^kLMkNkN@Hh;PN{^G#NoEGwu^ks+P#QMTt+I7d6$2b>Ydb2YtUzZ;H?~+})Oe-7? z+*z#M`&4!^2B$Y^_d4V5&3=(k7r$haylHh-m}qZU?bTpnMW`c9Y@)B1 zJ$4o?+QWm8JZpLcg$9SsK0X3Fbn~k;u@KVviQ6d-PE%8hJ;Cn5uLQZbj#1 zNh}cDnN;$RZ%EJi_J4PKowS&v74EDe?k_}^ z=N7EfD{Xmrui*ZJD7Gm2yW;pw#jG4k{5Nz3?%zS`-gCrTj`qf!$&$^3@loi@FZ7j(-m{$M^IeVjG8c_Ux#_-;EuNkC zuWAjx{32h8N9SFQVy*^m5vU66)R)NCsg~}s|NHcPh3Mw!WBhudN{Bb|*X46xXNav= zDt8nTsZDLPuSaU1Jg%7NYYtw;nO%ErB8$Ev5M)WD7RT4?c8gwRJm^$C4xKyDIM_H; zbXD2hz5`PQF?si3v%6{I)3!Nn+i9EIpHJ9zC$_dEwzhh^4V&Fv4(0W?e)z^K8WzDS zhVi%#@ax&_p1E;pxt7e|X!}~3@LD{vpxdk7t}U^(AhA`Ouxqq5|71qAy%L$5 zLn?+rG!v+)p1E;pW9|mB-HP+KSFtSimhR@8np);8<(;!k{^C=`V>uD1sh+uaNbCBM zHg>x<=8@v-J~FX2Cb2anv3021Qpbi9X#)~l2PU?1&CcIIiMEH3sgH`GK6|e0?b+M2}H?TM|mX2Cdl#MbP@ zR;Algj}|A=N_-j-D6_O!ySy;2_)C3M4E31^)JD(TxU}4wZt<3@Jb70JGIJS! z{R>v{sp7F*=Phsb%)O%%**B1Hg0mev%}E(=(jfmzlm)RdPRr$uy&Cs1_mm=aylNocrNrz;;w>%0{9(poR+q64}$UedJ%qz*6X z>I0HnQ^evbo*PRcm-vg7n4nt@3j8B`1<|jzA;qjR?Ug|@`TAGN;hZC#eY+xKHNf*7 zRX>Dbqt$6D!Ltetq+Or$X@H?Q9Ojr4sXj6|5_gj&H?pR z_Nx^F5`73(wjo8orN1#(j~#4<+&8z}H{tXpI9Kr{8@0CJO)kXI+a!KHz==HELZ#he zK^r??!!Gp;V8MGj{25ZzzxFIR5q1lvXk6Fq{Ng1VFJqg4s5l1C8eEn}`;egYQch_7 z@89rZ1WrYC4!t9%UF&x)KCQ-9?}F_Y3c34mu6mj4)g`;u_D!7E+@rMxcPrHN``Sq7 zUNTQukZ3Pmu(uI!c1sgkZEn}l)fPW&Bs-mz-7`~eY?$y%Mv`JK(Fe>{e9Gw)^e9>E zo^;ulZ!fj;l?cAQ5L=&E1KHC9sb5+uSQn-`?(r|Xc%W#9VWkpZtFki5{kut z&Luc1Z}H2})j-Qo&;OiD{O4R^2lMZL>s&(DnHX3)wtlp839Z}z*PKiE%Cu`i=#Cx# z@109%RhD)xQS9Q9axS3+*8iQ%O3oz; zDuN%E$h=?USD!0;tUgQP{jM4RaV}`Plb7Ivww96pg7$LPXKtm*-lWx+8&=!_`jtD0 zd|kJN{JPVhNxKzlEZRmh3Zu(~;`pRKRK?{B*4|o{M%#N_`PS85Z|7I5$}qIaNGs(b5CN@B`p%6he&oVxaH z9BdpaI$!@;ul{Gfnux%Eu6=j8i=iD_sQzcY`k!mxx)If-dHQ2t`_`eg=e6&Bu2+>M z^V+vA`u?w3ulmZgmr*Bo>~L3Z{VyWhvE*)4{*bJ#emP4kxJXD4`+YJjj&PT7{YBvD zLvI%6jNps@xkGm!Cgq^^67uBaJxV{cinDg={+an7Z^gbI#vF-jR<+w{X7{ zEsouDt*MUn+JRNdD#!WGoBtUgd6Asv<#rNc_h|94PKy;TLF1o~4{i}? ze7IW#(q_FyFcF1c*2|V_&0|2?EdnL{-(S|N9aynk>#hpzv*`v+Q9f7JU2Zmqp!lNR&6-aqi`{Wj|Dt~QtEx`)h5 z;ziq1pIzbk)siSbAGmmne?}!*zR4};i`MZy3BEp5w8js^#hZBa%5S@G0`NT~A3OiH z>HCl6$)^JMa?}EMRlaEKTZPfx{tdIcqOG?S#`qsC?I?=A&bttUm!qaV&{4=6N_i-4 zWzz4*dw1i$UqtCw^sP^O?drEZj03N?Bh@Qo5Cc16OCiS@+7U|CqF4-l8omaKq7~D)MBT+Y#iaIjx zBo*C=hA(62)*LT_yx!eFYF(bVd$jm^hJ>$P;B>XG?BW|8-FpaPtv=BS_qoD?J4Zzw z!EK|g_lk5AWMB7+l6Qc(S0v-~dquIJ7VIS4`njK5GXA6^{pL2;6incbIECt(yidGUKW%dTf*>EieH&xx;K%ZH}uz4lJ`;N>Wi{H)@>HpR1yIm^=1 z_H*yza%rbvobj{kJEibxs=D*;U!~ZeXPc8h&%RU5w}RgDKiFvxmuB2=w6LUpKcb?3C-nA4u%b0gAarKwYMxPFne(+rs1d{K6@izZCcata zp1>T=T{icQwcLS=xMjytXmG3N(64w7tMeRH<2fPXImy`cRqh&9y2&-|zt<}5LT;dB z{IRbI7sq*vPpp-0=1o-gCZiZVzjRZh8#8)emhPyFkMID^WBh-D|B2^mm+W%4_1$Bb zi@W?Z=chbo{Z2Q4xd22ZLiYQ&8o8nSNAicVyBJ~|lQu_N`C36x{Ni=7*1OYk>PtNQ zn6OLZUFfmJTZ32UM*GRr(n-h2YtGf~PQ1UL&ifrl;@SJr8|D8`zg6x$`JXy)(+Wpw z%FKA4Ti+&MFi>qP$_>8wvM$dJqJDRCZI8h;u)}lk^`1jb9(E&gv42dVIQB_)yxpuq z^H@~A0vr3X*82wow(h~4yj>(N7?6|q25jX0DYH>rxL|;^>)y^xkIh)-i zG3@dGdlkdiCE0w+Z?c!1Uy9M}hjQ`;{+hI$>Fy2wcT?LU{+zErgNoK7=7;%He3UXE z&crOYSXGpik~A_kDUm*?==L{rW)%~cb9~Y;%5g2C=+*471@3u@l#&bXU*45L<( z)50Qmghk~A71WcSgk{mN-ow&`dDgJFyu4{pUR_wUiSNd39mYmaBknAW#9xiLiW%B7(5Yq||+erIWB!I=>3bOt+=5Xe-)2oxg;o z4D<|(d=r*pmq%gImaEk^X?PA0IV~)5M_5!|P{FRZNs3RHb42f9$;UivSX|y{e4@O% zuxQIwpv+f5aw0769G(nIF{SP^ES!z6ALINgEO~BAVbNB!{V4ttmN4iU7WpPDLtGw( zMO&^`Tcn9OOzP4T5>VZ8WxwAIbU8~ShVFTknbxXIT4mu z!^yBrq|}1@ShA-c1CvK0zLc$l!_v)Rq7!oN6`j3rsvt#2ThaDC{3SZOLC@%@2%@vY zB4_ZFRQa%GK<%gfZCsDQRy1;+Ra zNKQoOIWA5HrRGuUM~TiDqSNKvD>_@;mZGCA-V(%LqSFa_Mn^>uopmmcqN6QWxi!+n zoF*+gaz}Jjo^z*V+244(9JcB#7E}cXveeO9Xv#s>lJ(thx$njdF6WC>+#eh&Y904; zGQweZz&Bi`^SfDy-Fg&-Yq_S?X*}$NS?xY?R_TL**ABe;6HBuh)P6VB;%&0{jB69F z5-mr(k{m2jR2}YGDnIvKwt*?pmrA3P7b0~bvDwJx7QeZG%}&2r$>uu0Ig`z`ezS~C z`6`axv<6IxUQmpOd{T!{bv7rmnd>*lusOhQ=CK*_n_)KhdS^q}-0e4W*>qKn-L%8| z9Z(wGpQnH;k?8X^w9H+jiFdF?*RM`Cb$u8cf>Ug-KJ~9aN}So zPFmQ=X0hK~z-GSRtYmYd-<-+j7{6J@rhJveZps6t(V4|K%O_QVWs}Fy*DJ7Wj$u=Q zWs|S)u2*2$46~`gvN?oJ1(wZRHdR&pDzNw+FeN&X5#gG_QQ1Xh)k24R8bM;nxgnlA zaMvf?z#Y89v)^`@47I-4nhdpfx_*K4=0ZJ}O^xhI&sDP%B?LQBZo#2x;aA*!uJd_q zo%5w6?;tnD0pG#0Do(K~7FiVw(yCaNR>cl=Uvzz0vWg{E#bT>sVNgYiZI?1-f9Jc@ zE~{$f?YS2c*mEk$7z()`6$?%`mTX)}@dfU!lKPsYuQU~yD96!1Fn9T_d&al~O=f;8 zo<{=5!@xUVvZ3lKU~~I)+p?O)`tZuMxGW3!xw7_|Xk!I^qwTZRR=&L;L?^5zE0VNG z>yXIjGUSuAxxJ9Tav!7?BRe-G%E8?zAv&QG6C`Pows=W(EsmX9eDdPm{#V|(RI3XB z{Qj96PZ`(axIBbCD((tVE8uYs57gC^Ng=?yBxvSxVL0{ zja!wrFW{#AUc7(RgDw^2`}b+M3qfu)6jQ7_-^}<9Z(4rh(Lo4;c&zFi|G`mxa_-#{ zbuNPB_9w6z+nM~GNxP`-j1srVisOqrnGHGijCzryJilM#^w6Dp^Yb$ss0*C>-#7Tp+^DnC|qH-ysMSfGP9_c2cFw4VcA5a^WO zD|Y2?U}p0*S*Lwfoz7Qw{cjQZ^}*mu+NOhC3vt#oCAz#`KQJGCQcnC_ru%j2)O7u} zobrpw^brFO3~GR~-<$MY&UyZ~UbsBhZvaY|ZuB@ts*#3*Jc{O#o5?D+ccnNEA?u_dQ9d}iqbe|-DO)2`dtdg`5LR`HeWHlYC~ zY5d1VS(ck1xj*G>Af2Q`J%QTptH|z z(%mPYzvsMr_}eD$KJD^@?mY9w%a(aL|GNKUeHMQd8I&)oeyY3b8ajT8(t?@cVKw2>s+Ojjg~LOL6(v*7 zE}B+xdcpL`#o-1sbc*TcPANG1%#!TNbIJ<}d*qs2TUFN>uB&NkYG?{y+Em4M!`w)? zzM&=D+}haK(9{x{8@gb6(ai9aLaH%`dMvD|Ypn}c)z>sPv@|s|)>Mb*)zr37=i106 zk=kUoa7{BgW`+uSSk~0f&n)4L)29X{l-JibRLzad4L3#V=i;^{vaqGKDH5Jr)lwCn z*VIrKo^ftLX*lo9vhv}f3uYAb%%~>R_GX`@Aa73~DJpw5$~q}LgZeZyofHm-hc$;> z%DJwF5z>N`8Ih*unudCef|N5$rj;m?joAhFfS!cG%r%GOwG8d37uI|Q8aUU zg|)h(x}mPIDbg%`Me}hj)zY6=bUJ?nO=NDuIK|+sDbqjPZYm=s#ZA%l$zvGNcARrm)lzd&O>IrfA}OYno*6hwl%i%dUee^-aaQrUSq-Y1 zTdFG-%x#jB)L8g&R*^FFGA;Z-uBg_i4qZUrqO+$>nR@n|aN*49;bcpLG1Z*xhBRvh z;^Uc*JGQ7`^2f+hHsjonQ=x)s(?5>))LqU7QnT%)+V>KBb~vxDY9XU;^q6@w*_Tq{ z)pK45c0)HmBs`?e4X0N%N5YpbsA-7=0S?=)+}v7S%^;rFT3fp)l*O#Np|y6dn-eaI zSf0?-#z_5{CE>Y|c~z~oOh+wMEs^GMO?^#EO;v5pWlRuhUQ;Kj#1s-#+RYt#7xk#$ z@Z^LN%05KG^BS7!s#-GUt6m03ug2rD42|r@y$p=(#=Q)S?8d19Ig& zV8qqXJ?t#0y%yM3SJemmN+Mg@k+3wr6TEl+Q2-(aGTuPOkBdv3s@U8 zrCa!RhAx;^TzGDLAVGHZ4{n;Pab z;@p}b-Ex|*MwTHD$jKDTCGOL+2( zvBN*AZQ)ttIDVwY|BNa+a;}D(_Ahm+kEwP|mPTo|)(A69pFKi;SytB2%)H-FZz4lw zazjJYTocdM99?U|tZIs-@YCGn=60*=)v}jf+5<0S*sn zXl+qp<2dA1&Clv4VKd&@WOWlhAQV_xv2t&fgRX1UfR(WSLzqTR>FjiE21ko6ummd0&;jyE~3_m%1z~byR zN=?;eq?AvV{!a8=Y8x`*Wj6Z?d1}AZ)K}G}wJoSoqF`_@L9#uWyOurY}e6E-1!N+?-uD5!b*w2&EbEyR*4{Ii&09rQZ_$sD@Q~_Y zd^mNc@f8`LH&%@w=VCYxk6JyZe$pMJ%}#-bF{4jB@%WM9QDa7r8G{E_pkw98EkrXG zWUQLC3#s}HiIj;xb>AGlFno%}MEJDKVRKSAV;K0o*12m=nR2PwJ{+d?p}9;=OL5w= zAi`DqN#VRyci~Yfbss*$rg5LkpYJwJ`wE#{=FtmB7{kX{$|6fylv&W&Ak&Dv)Se<9 z$E0=L=tUz`LPp|cO3bFXG*F0iZ=wfW#ZK30x>a`Uh`h8O9(@^wq^CG%X-=xmLrQ-h z6LvxI?UdRVS~D-4S5?0#?;9(|E-Ct3Xv zZ>c_0ts=a=1!rtBhaWogEkn-}4Rbbp^!#KVH}YLKp3BvW-g;5vC%qTl0J2_8sjYX? zTV2s6OSXaTOU)7xjE9eIO0iEpA#%OY6q!3R?3z0=tjH$LT~#4^f`2Ker)&oIZG+U{ z-l|_81*zESUZ(D0@(H#B+aS%6b(Qn!)>lgLvfoO{o1xG2nOc5o9TRrF<^Qnqr9UmB zPUb5}Pc6^YAN$~wu*pm_IZ?kX`c$2^gHKxehGdLV_1boJ(wj}D-r1z&PmAGc-a5$Z zh;8sm)Is@E{s($7t$efTRezfIld5+k} zzaJ(4hn1h9Pt+ms4fRo3!6#7%vr&4WPv}ldZ(FL~*?*YcdmMcSv*Bt5dj zr-y#GPY<2w*+W0ZQm*Jlzt;4{o;~u1cuY&5y}jw(x2|~ptQUP*f1m#Vo}1#+!++%f zubX-W=`mpJHi+}!y z=qpV>yqEf~G<~!eefUtXIIBr|sy|ur{>us9p;lIoDw#e7Aly_Da1ruVPs_!T#O^7}dT$lp1`rH2mb&HpT~Ki@ru-E)4a zobUC$?LWIszm4`E9@?)*`CVW3`FlHlg>7Oi>7{**bw2;kdeP@Mc>QFL9_6nzz3m1) z^qr=EtC#$pjb1Ulm-y{&_WFX}>euS^kM^R^z0~W^>qXzV(ChO(dencd>3eH`Xpzr& zK`;3$O@Bo%`fk%d(u;oWWnR&nzU^|aKfJg6AENIzeJeX~w((VYwRilRUg9^#4$RHu zuj;dZ&-i`A=l?4cNH+f+-}CxU^fJEJc6j}{y_BE(1Fyf^qeuB&ruVyF&;764^kXTX zPmla#ZuO2o(M$RHKl1v)x!LEh%6q+jqeoBwzx0X&d(r2cepoO1M$-@KrG6{d`Ha2I z&mE@kZU5~ueP=K6vE^T=&t>O^`Yg=tlY8JN252rniehzWUOSkluld;d0bhptbneyr zO&(~=YG=pSIzl_l&dw9E+G#2)JJ|cP!(LXq>#oL`i=DEhWAnK zNbK6oZeQbSI(7@qZeQ)V0=vqOV0R04#b&p!{@sdQ{ztIegWW{4vvp_IxE$Iq>Ce`8 zS?vn3TVwu?+(-Osv0H0)Q}$tZJ$Bp7&d!^%mir)fp;5lyR_(*zcI+0K-M;$cKqmD{ zv$ON5tmTf!Zsr7EuANt9wVRDy*(7gg=T}+nmSMO0G;bGNkI8nNxgEQ%Gripz`)Kde z*zGmDvVGXShh11-yS6z7iHrg*z<=1lj=vR{^9xAH7+XXj&C{k32>WV*Mr z^RldVH)0nuJ3IbowcCWhBut^5=Mec0QNY?r!W>U+C@Zye_NV^QvF9x3lxR ztag1r$?<5Ox3lxStac-@3+W4)e4;LR{K+y7ren9j>~!AeK7rkrmiE1tNFPPw71)I@ z_5Sv?-na$3Vtvb(kDUi*Eq5z+jf=dUoeyTU+k@SZ%e~!Xt6sKt9Lk`}H#=KjX7yKy zU9s8Od16+(TI|AC_;T%hF{|D6*yUa2?d-fUtKEaxm9=?0JAce-w;j8^OT3+(M`pD< zkezYNQg4^PkGPD-uGsAM6~EcoHJY8BUuG?L8Fp*TZeQ!&+p!BR^YwdVAN6}${yu`; zd)Sq=dw+-T!{1Sy+|2w4b|u(Vnw`!^-6zYqZ^3Teb-r9XFU=a48|Clo-cIMIY5q!< z_Pe(4b^B{S+9ZG9^>#W>O|whc-*#cwcAK};`D$-=2XV5w;K$z1&RetA?-cAhe&X%y z{57lHTHOAxg8nE@ z&i8#k&HnZ)Z@1CRvdsr0vFkEBLg_z&KNHoC>Da9^yJ41|&EFN+b()=>|7LCPE%LX) z*Dn|b+5BzAuEXp`?W5d1*sU?U&dhOO`IbJw^$=E9SHge85{T*0A{a+L(b5lve1;B! zUnhOf{X8RyybB%yw?n4;!M}&g(Qh*SuS~xV%6|t8V}AoY46cOS`WY32bls?{VKrO= zxg<8~3ixGsDQt&LkaMn~^WkFTb0PH|{3X*DnSPRS0+ih-D7#@$e!`|7Z2EuS=hOcR zW#0{D|9jYq+-dSX@B-u?LN2L}x&d%Kmdu_Bl}T?GI%ig0kPs^^cjPzX>mbuRz8|`~`SoC{*{b z$?M@vRO{e;co$TCe*|UM2$e4aRsZ84aTq!hYCME3eSfI&u$SvP8V`Sjs?YDB>hl|@ z`acL&-@8nIhv|O^RnGNL;qR~_qn@#z8$~t`5uJI_fsf+=g+Cdx^GBUIkTNGnC){ zurKl(Kl0=7W#iZ2P3%W)P<|E~8;uK$mByK{KXzY)?7#6aoQVHtZsk}HAA^ePgT{M} zYvBm=KY&NWRqzDtt~L3qP;r?LmHz^GJe&@{Li$-y^H>o)0`3oG-*t;`Un5lg=Nm6H zmK#fqlZ_`Ek24-)Jkt1i<7bTnpxXV;4}E#xg(~kG#;CE)c&V|$INw-dJkL1Qc&70b zsB-@BgHY%s+IK&kKznb4KSTbe@ham4xPtVdPhN}N#Q1$%*EQ62ZY$v<{%FkD!+A$BR9TVUO@U`!HZiV|X4t{1_2~|!T zl)p#5r0I!4VZt#4XonP|qZ+jkS%;O-a^uksCcy$`wpYl#H9&0?> zI0Qb4{XnR=?!DggCF5_6zcgM272kh<)7SIwQ1N{pJ_$4j94 zu>zg}XTko|?`Zfw@=gx2gm%&sQ0d=?gmBbJmVO+32YDn^e|-_EzrFxf&ih~Y{q;7y z3;8vu{`w76eE+r5+r13srwb~5Fw}VI0~Pmw5yXGOolx-{U_9ztFXzWSXJ6yFFy?vv z3Lp3DpyK{D<5k8>jSHaSeXenW@i5~jjZa2>yr)9d?=<)X91S0Z2SLUA?d3k+JE7w6 zEL6O=K*jrBsQ7*bD!xZU#q~gw`@v4+Jzw+l$xHA~8jO&f!0nfXLc8FjQ1QD4DqlNPz83ff@^ttb z91s5v4}!12w-@<*PeA3nA1dGNCV$uDufiA5pAAoj!{EQ+U>K&pI~RKS8F(1-6OdhO z)UQnb5nPRY1C;-j@IvGnP<{(7eUiz?n0%DUpE3DUCck~D_wxo+{%(_>HF>kiohILD z@@?>U*sn7AT9dCZxz*%qlV_X!C6gzcJl5n9CV$@Ke(*;8|Me2z&wqlek)MWY_d2*9 zd99`2YUww^XGpJve}KhM`9?tH`;4Xcfqx?X?bcA}$MAJ1{a;Of!Q>}Re$?dkCf{T7 zk4?VW_ZEO-;+cNA1R2b$a;s=n{F`1-sIB|mTS@8CA%Z^LKd zRi>{p{S-@|2=7Hd9KHkx!TaF5&A!~fLY4a<{5SlrrME$qR{<4|X;9;09DE9HZ1Qov z8ID0-4wb(NYW!Xdm7n)+x%_9rUm>3ahoc{D@=%zE{3$pB{X1U?g>Hd6;L)%PmcaX< z>~1yvH%))J>F1jMvrzNGOO3vLKZL5sYN&QBgB{2V;16L5d=HL-p+2Eehru5qe-_>f z-)IPhegJnu<^LH}JHH3j&M9yx{{}(LZ~fr&@U{9-=+Cels{Ci6^4|+p-by1cA#w8A z#u3I(8egh2dno@GLd7Ru>(iUzi^yld@54{SO1K}K4d1%h^A+Qtj87SVZM@%jCzSu| zjE%-~j1!Cp8~^oXZ@&(nO}=@s6dnu}r+?IV-Up8*P91P1>3bIV^e(9MyWw)uZ-z%A zUk8tXmm3?P{7p6fd44Fg2l=;f6585&jza=TP;y5vm@CLA9@HuCGU-@eruv(x;&6^ICN% zG#a}>Q1yNHBCo$6j-vcqq3U-P+yWcn+wf#dKiJYgVd+m*dHXeR6LvSiz3|I$KgQi0 zC_iUI`N@Ow|3;-xe+er6PN?*#rC(<0rIvo8rH`=me^z+==b_^FYpD3$246*Phl=A& z<0qlw_y7kh#VH4>{cp_idDe$sBzJCzHi4ysCN7U{+#qETno#f;&YOvA7tr&o9WZL zpzLphvcJUAD=qybOFz)k-#X9R{}#&rdMN)_TKY^&A7SaQ&hYhn8mfNx!qwRS4ECqJ zH=Fz&lcOeIZt@(ceCI)xHwvn}L*Z7qr`(U9SKwR7k3)@{P4I1aGgQ7-sC;vw@|^-T z?#97?!9h^@J^__)`*ff0A*g(7q4F(<%6BE)3nNhdHVrEO6sY_opvwIORQ|W7`TUPV z<=+HV?pmn)--F73Jyia$K;=IhD*q&?@&`lNeG1BM$GP5aBb43Gq3l*e*?k?#t_jND zR4BVsq3ni3?FU0)7wiKMBHm5s`2AoWRDYch)n6yUo0Si~3lD|+lYWrNe=PIs>dnTx zpz{9+D*sLJN#twbV9GfJYJYoms^2f3gg-@o1S;PHQ2FkF4^m+=g#)_k3rer1%E;QAH&Dsb;eexdMtpyg|ndQc{bb*-zfF%{FCu9PmbYmAFbKMAV5BjK;n_kps1d$LdeGt@kPx5?K*>M?W? zl)o0JcGf`cS99TE$QMHGU+0^A3Y7f`Q1&CC?2k76;ZXMfWpW70{@v5P{cb4xSE2m> z70UiMCf^NZ|1&86--n9BcTA2$#p5C`*Ug4%XBkw!Nv1ymK7u?Bs-K2Il^cdC_YkOZ z2b;XNz~_Gx%6H8)#qTS`V2C8PrlFp8kGHZDEmJ{**^B^}p8SB~bOa9IF18K-K?ZsQS->t&VJ{0c9I6nyP zA^n5X{JQL$Q1(|t?SB_R?1r9aEHM@sk2fA;3>ya<4}g4zesHSi9^+2qpNzjVZZY0( zyvukyR6V{2wIAL94@15NG9K%$g6g*>sP@;w(b!!#i9gcAf2%#lF;MmT0+inapyK@A zDL%e$!Ji}l18Tg#Wc)o;|8$xB2$bD=lYe2n1E^J12YlT~Kx}oBTXfd4DkZF{tv^d%5nH zP=0;}51_nTjNgLt^L3N2hO)cTWvKXco4n2BCr#c8)t*O8UT^Zfu#@tC0_E>}CVvCU-_<5x z29q1LP}*$~VR2NhXgqd6>zcGkKuNeN6u6iN2hjQ2t&p`AL%>fhzYtlkYJ3 zW~ex?GDhJh}ROaCmC-9StK1k`@Jd!p~J9Z<)`7vXBspMyjB_cZL!y!0Emf%IQn`u%Vu@;&ev z_#>$LuZF7sH{fdI7*zb185bKbHGT!ke>Gf<{cKC0Vd-Z;`OAlE(N8pe7%IM>H#rw> zMeb|z-V^*h{wCDC^bFKI|D?&kf%5ljsQTRrkH-Y@5g(8JD}vhK>2$P%HJj^e;Z7`8_M4rlW&BI z|F=#4I_yGjH@OKaj?r^0wXR6m?$`a(-T)zU{p<<<-(J|@3A z!PomODF1(gs`s-dKMqyzjV9j<P!}{U}tuZ-=V) zZ6@CgRqq?2@-Ks`_f;mhK-GJJ$+MySl|lJC5z60qlSf1O`y!OTTqu8^GFdl?4lkMf0#qEHH2GKXAlk7Gs-1Vh1M&Mq;|-qiZ$gcWMoXV=oM=4ExWDn`ao*35 zjh7lvH-?R$gYQx9K_>S%xsS$~VsB z!%hA)yaWAy@Ne)RBR#u}4;t4PuQ#?q`CSC%cLDq&@)Y=a#`&oxA7=7FCjax8Q0Nf! zuRz)V#^g?uZ-$>k|1Fa*HM!R0QaA+t=_Vfu{|kAD$!`;6$^U@z|Afh#Oup6R@4)To z3*f=nA8+!X=^UjmH}W=eC%-^vDg7GwGF%FW(SHkJU)o=7`p-bcWdKxMKA;n2{}wz7 z`&XgtpMmmM0Tusq;S=ygsQlxg@_z~{p6}2YrN0T4z7;Bt4_Nx$mL7+S-xZeLYUwkf z;&!H`=UaL|sCezAF{;NiP~+xasByH~B?^2w0%jKO2zX5=rz-@rrR{qQrEJ^=m<`E7#rFnkR@1h>OJl=lqO{_uUM^OkSI zIP%vl{mYQg(Ak!Lilu+Swxuf0s^>pBEwZ zj6VhC|F@QYr^!Dy`8r6w<879HxuwrG`8<;+ntYte2SD|UI$h;GN2mW0ISPLdFNMrU z@j5sdRzube@flG0PKU~OGJFnstfddN^n)$^Kuh1tAd&s+Q1&lF`Ppjek68Mh@Fw>A z??COxmqYEhUxXS@pD_NJPEh{eL-~CKQop(l@Bz}VGkv@1uYjGT&w;W#5w1thf%3B- zl%KchybZ|D81I4)B41_lRM?Gttnm=|F!BLV^T{qc`KRz1WWm#D72G zpD>s7ZBX;hCa8Jm0h4bt`8%HR>!JL#n|zh&FEP%C@-xlk0+UCX{26!w`G3z~RX=_Y zN-i?_K&bldZ+wTrC;1iQpNx+iHyVFo{E_hnV+?+Z{9iRLGS(R97)y->#<9j>#v#T7 z-~ssSW8BM5A$f=KdE-`Nr*W#WsrG)=>E|43xiU8&G={I6UL3kwUB&uUx!~K ze%HW((-h46O+GV@^vQHn|vWu zIp;x@a|Tr0CmF{XkMgWL$mISezr|pc{i~jJkC}Wwl;69c{Qdwc-ZvPpHMV)yHJW^p z$>*AUrpaG4`Gr9~?oYu1_o<1pi4#z*Nq%^w>e<2e3PsQKV#sBs)OUS^CyjrVgP<2F7Ceh2$E2=>3> zA7LN#`VOk{-wkDd6Vy1r0;;?!_zw2Nq4IqKu7p(tM{)s_pOcLGF7nq&zYnLpSAFta30iteLlPac^r(xS4ouJqfq{iGO)WRa@}F39{^SU2O*#DIjDYp4616Ipz=Rp zyazU5zZR;zH4qm=83WFaHo9`!q2}F15PyT`d3{|8#P85kq4J#oX`+^UPUf(!&(Lnh z1N#1*#tvhfvC^1t3>!nnZa;4NcN#m4ZN^GtzA!nnZa?1p zcN#m4ZN^GtzA!nnZU!-%{X2~v#x`T6G2a+A0+(+i{rG8O zS@yP4+%vjPUTN}9(xhK)@;{k}C2uo%JKK_ z-hVmEUw)Sl|`C`-WFj?Orm;El2b$ph*+vG(i?=kr=Chs+QtI6+~ ze67j)(vUv)n%vjq5|am*e7yC~fhPan+S5JC=fAdiJGmPCE73FW1YvP2Q{eku`XK=dl`Z$ie#>k7OOC_#9>aCYYRO@=utj zWS`&a{dZdZ^rb|7mId`SIcn_*TYepPTzT`o{guqSDsPPG>#4i+!TTRy*Z4#Z-e-6$ zwx6aBYoGP`b5uX{YdgGrhUqI!AGPs4()`a2^fn$ZGdce$pMSaPgTMSAd0EX+{X+H% zPp!jpRKFj1{m~`|@0-;6Mf#3)UVk%rC0E|-Tl7sg@ZnXTt`y4+>yrp0J4R3!Z{UJGc-{(t~KX||84%6p1c>A9R{;hs1t^UFL z6wks;{>J>$+w0v&l7shwzQMMW&EFogUwgT?f86YY_g{XW?`Mc`)0W_f+C^|vlE>hrew>okA!&0lzk*I#P> z!e;+D<_{Mi^64|z;;D6wJ{MSf^sur%Cz!so$jedF2k#%|G}rmt?bV@wTYcNk@d>$B zpWuDKt4;14=Jf-tewICSgY{4F{`VuTeYspG(Pxc~kKq088Ww8L7{!p!Bm9?KDS^*- zt-itgczK%ot`6p$x@0E=Fbs6)~_6+;)XZTy4 zp?@YrUXdYh$&jzekpG@h|NAra^%?SyGUR_`#QTDb_8glbzmrkk8yWlOu^Gp&PiEMk znGwIkGxn#?W{mGO8TkjXzM=_yO0%9Q3AJ<{gao?cTwcZT~#^@66RD$M5dL)Xn! z7u7~AwT1F8O6ZE}dr?)lHZ@U4Ukz2Wtf4VQXl-5)NYf%M{zvR*RPjS>L26yY+(_*u z`l;s%418*7TG}*zr8m+r!KZfh&^7@*24NZ09)1>3lq;YA|*fh!4d;C0CRNyO3IxbBbmnMys zr0%8KEsCM_L}8?{Wx@1FvrF?mkd~yFH1e~@3P5t(*JVn*etI@k(Gsa^JiT?^yhzjJ zhSqu#6h5EOY`-%dswi)qTh$Wjky=l9=Vqp=o|$QMg%57hqsyC-sH_=DX)RSPtxluR7S%@T*dJU`*0RJ% zbVgL^+(`Z0NR!VUq@_6YzFdXUQ=4ih*G8(E{LhG5A6P3B5`)L(Oe6$tOC&TYDv>5S zytJmVuBwsZ61%2#LPCVs&e$qWuTY(Qne{$_PJU+JY7u zyC5kS@{_koIq39Mz4p?iJh>^tfK8Db>Kbcm6A6>k#qyNd$Iq-OIn^Huep7W_qwPH@ zdqZl(HJaE#LKQP2)wJliS&^oOV2+vE)Up7fsn#}_$Y^=w5(eIs`gv$5=(0Y|LwDi~xURIHRex zxuvyE>cl2H2)$fSuIWux_02jICR&}6;tsk6)c=x*)iO1@c0g4#N^0saP7(c{pOWCa zGbN$CIg*g(wM1%bLlqT%2dSuDaB;=Fsv1)2sumX1*EBb@G&MBVRF_09iPVNlXhv}8 zkCd1M-TK6--P|>eu8$x# z*$z6+sjU5D5p0)mhh{l-le9_x5O!Y8+?ECMpgF2E((JbVK{p|}Asa|)k>9Rum>*Ph zK@~?04X%4KUT=5n{5k}E&NQWC7ploVfDBEcU%5~9{xwG^C^kg~HWmgZ5L-c`_i*Uw7!mA=T< zN)1g_^NEBTfOwr!=frvZAa!C#@`Fn!0cu046zpl*i=5hxazD5G1crI4IK5&1e9mZ^ zymCG#C$)>_H`E8dt@7v9G)00W--u)iCq(sgz0wtSdQzsW6ls2~FL+u*Yg08fPae3Z zaDp|rrm9}4I&wGEx17OlDq(VKZLQxY=}m_bWqp}(XO~UQNKxj3 zY11e7%w05n^0=(2V^dO7MwdJ_MVgz{Hj9qdaqLa31%NF*Z0$BBnPTfUr7%6zHdHgR zj9N=_PIX3WJ&BBUb*2}B>8SN0r*NaSu&SjhDNSp=$R{Lw_VjZL&yYdN(#rOfafM0` z2Dq1!4N6Z(!nfNKWJsa)Z7lv2T1rEd%R1^^tapmaU0)#*5WVK2bYV|J{1+!>>X9rEfuZxninc6 zN($2qjxfobbmC9->!A3sSEV+e_(vA7UvW*Od}zBjsfPqcM+bn^~5T2Z>Ua7EGEg)2(m$+`FKf}DGI^Z&`5drRMS>e%8vvDV#w zvuMxK&OWiy-AfMHHAUZTE`u*Yj7j zzCmF*_ioHz-uhbf*DFe2^JTv2+`XBTTeO!yrSAn|zu$+s^_I8g&77H~Xl53@_h!zZ zq8&MT56NstT1~>##C=9*txsW8^>G0x-xV$0VPT;C#G#xx%z1|ZC=hS(|94pfv3OUk zwP&H(%TxPvK3lpwx;Q9mMd^+ewDX;! z6!CohnMvT!>6HCe8IW>e(N(ws|@Af1nOeD&v}*yvLMh zjmxt^GpyTMQM6-4>CP49gne($y|3ro`xKq)qwO6JZg!3b72QJi(p!>64l3$UN=Gs! zw{*J`NOlo0G3UHTU5e9X{9z}lobzzbVfjIS&=`I zz7)D7w_Ke=Lvx3Aao?E+&+(yF(_QCnLsz<6mPC5C3k3nakPY?PAaz!*2FH~}SYBD$ z6%H&PDIJDXlOR^jA1Bb*c%pZiM!eK}Fr#Qj3eU$CaYEvZy<@c(3b!!WT?PY4Iyw zvTG%E*AQTKBy;I5XTNlBpPcp?bpM9Fs9nWf&a8Z94D&aAnO2t20>Z^_AfSY>Z=C6KCS<(6(@s1OuF;4-i^2hnHgv@8#% zXXy;G1nIf`CIzL&N_Q-M=m11pO}Z1EZ*unL_33`D5B$&}K`xcQIw*go<+~<5-^w6gke=Ib zWLo(LWekYr=4V;DpJjm`U%tzw@|OqYxA}Z={m5E+);7!9o=~}|?I2BUrv<~pW!b6z zEMBrnyX2gQ?Rc8MPP?FXdL6xYMO$~cecTodn~S>9G6=f;Akg0xMSEA2zP+NHl~i)C z4AxPJH3R!DE3VgBacJ*lkrAx868mqz{v59fkLHpQ<=rXc<9Q3xwnR(aoWl;S@iC%^ zDw09*c|M5G)0V}LW{nS*<>?@MK0<=PDH|?d~~z7{zYn1_vW6hFV$8lDSkp z#;~7HHd(&T^cHOjs^`;VMcrsxi!u8+3J&75KT(w9`S-%?iF zYVjULHFe(HZk6s%RNBp(1l~8637rgTC$aYJ?AdcJ3*F@R?4U<;`wa|A^^+K`x>80! z&+c@7x)MbvbE$l~*_Yq5e_Xz;LHWMllJn+k>2YR7oqqgUx@%14Qkt4(IU+m8#l1iC6A5!Skt|kGjcKW>&VvktdpGR zj%hPh&5^q;-K|Jx>Igm(`z!_-em>Mb-5{udD{bcy3@vNSha807q@nvb2<@ZgwwitP zvl_jAgeZJUch1g;r1DDyIoVaxy`@5xd(z>Bnf5uG)r3~9aMa)(#5ZwwX zx7@ee&T4jWGO}^W8+4jZMmEZ57fFvLk{)wTldFgorQI9`UgR+Fm-G|wmr_a}JiwJc zs7O^Q^>d+h;)6=@t1Xu@B5}GrLM!n=bf+YwIHwtZ2w2&ihl6;z{kbr4u#1*&kCt}F zN;ygHVl5UeeL7Z3$~NZlC^2MNR2*yF=DJ`vUBLg+#FCetIb*(<#s!F(bjVsdWCxwN zo6f))Q%Dy@(oOzqL~y>C43iD!zC0|g4!B*d_G>&&*NNbq7gx;r3kOl1wZG|4*i!w%r=o8UroQqiLp8ZRAeXPX&%Xjq5o{{Ja`sj(NRdV&(`9RR34?Ux}2Fv>t0DnC# zR=$gn`rSoO^@V&Bm+tJt#kQrt?!zhh(%1HrNp$h{=o9RCuE2zc^4(N>=_^<}Khf6i z=rghMZfE5EaoNsYsN+J_(tmhQtan@K*0zdc>$Y?CvpBYPm%}RgD2};|EErr4MTNPhyExii7%k2%iIsPi#O7=( ziO&3gsCysyx~uyBKWS2k*z&p2vUQVbWL48YV9H=C7DrNZ<$}4hU^7zJLS3Z8A+D(1 zs$Ziiw-@s1rx&UtvuxnH@2_rkmQlABA~rOs`8EMN3EDw7D+}6bu6C|sXH(>Bf6v$Z zoX`E2q`vPa2sDwT6};7_CTo7obAo5$TF8 zre4`Fjc4NO2Y+S)iFVhHic(X#9(*&+`Yc)+KZqX@^5WG0&6eGQG)ulwChn%rWWs;I z%13~$@6uz+UlV(aXK_##pOAi*S)V7?P5ekP^Kp(Ve_6{^dWvu)Y#+JrloZ(`)dv|q zzFv|elbi#gpKMsBtiGc3K$zSY`ZW7o8qvWF(9wZHr-F_?(Xq$V;q*Lx%3t}`B*((! zSpFa5RYqKcCG!#K+cbR(*B`f9+p?SLDl+^mqX_Fc>r|8DbUSpaSBwO?52hY3N z5$bnG)bvE4-yKm;pr!0e{Uo$RSgD`l?ugpAmcFJI?nuKKI8a$Etyh8@=wcEV&u1^# zk>YyT;I*sAhLcBCYGH!1RZe|FQCF!Wke)mt&nk6riFUZUO3HodyG4d&yh{C7LWNtU zC6LpFD~;1ps63{qfJq&syU}#uMmp(Msl2ADEXh!)TtD=S%kVHbZzI=Lx8bY5ZIoP- zM}kX+f;%s#_-;C$J}eG?c3@t0@bHMp8ZCa0zVWHd>8fCpWA9NXHAjo2a@xdD7i(; ze&Mx^laru%F-(rMh6DGVI>X0^VK@f5<6&~BRsH9gsB5TtxMluCMe@UJ$7ya8CI<@1 z$#$Rnh`RPw4@b#?D<*<_#11P<#G0&~{Q96QTHkl-=MiekFnP>MHbB7$V~|iV z)o1gf1!>jhV9+@G55XL)FtM^~MWPl6%p%jp$U{mA!~zMk?O3Ics)x9fn?DTLFY;TJ zkF|3;k0B8t(E_#q8%fyF4*V14@P|nR+{~w_Ccz881ph{4=c(Whk6PlA|AGhoYY$pP zJqh%a9`t`q!b-7hvq|}^RzBhaP0KYqq14t`9BQi21ve{1EmB>GZ-({S2TeF-je^CB zk>F3A?1$+W5jAy*h5f|kiw9czSZ!7%!@;&(`#@ZSNct#}&J6jP@L*f$^bkzl$5_8J z@DUmLDM)65=5r04KgVgiFL2%Y*uL=>ev+pB;(kYnW_M?J`7jLZ`X7>`Vi(SbOO1&|mcd6Mb)Qu>m+ z(O}~rk$;O$-O%J9Fkc8BkArD=Bc_Rh_@zwze9A-e`;9%ej;AZ>1sY?;o5q zDSo;3Vfg!jb0)<%`|~$2Pk)o*Wye8(+g(1B;+tOO;-{l;j9Iz<-tSUQO21rP2!EP_ z@i!@cw~w!*tC%W&z#n9~#G)ssmpwQAy>*)W8`S9eYj@71{JVX87ctech+6rFj!}Qp zrC;OYADb@!IWGOToiiE#1uo*!Y0@|QLro7(lm3K{x4H3D{MG3e{=VUyN%?Q}_6GJ% z6TjTsfB4um@uNOIIZb?QAEJAj`0Z?j>+hy%$}c0p`g_eZ@eS%X`P(;5{Fvs?{F!=a z3jX-&sjB|?^;Ojy64i-W=hkfn*F4f($p5i_rnlhF_YYN7E$1ihobis?>LK+fxK{o* z{)>a#s6hQq0rx?Iw|Y3=UrY&iFK|aZobNZLgj1b0e9PtQ+vk*U$AH^;)WP|FWJYwZ{maAmOdThzx5O7QKFOBawaO*sr@2{rJcMh2Ae(3P|errlNoyQ#TaK8VV z67K!L9Xams`F?ClxGlh~`F98B`?D$G_5e5WBM0aEwJG6_0=N4=9Gvgpri81lW$AOm z!TEk}O1MS9ZTE1#znct3AY2dj^`bm?+2%ZI|SVF zpZM}t%8RFC9_~rt#!osp-!D$W_pS!BgMaZ-@4g9_KJVfL?wfH})2|{<7hLMybG`cv z{jtLT5|?Z)xWl`RKKw7}&writtGxR~`hUT{+PN1mV?0?%{9AE<19zr(|B-R3k?+69 zeGBdeT*2LpE4ZcJeVupzopDd_-@q08=W%Jf7jMT^y1Q_d?pEA4;V!|w9QRyY(Q}5` ztKz?ltN5?tD*kVA75_hd{8n7$^FCbVa|3P@?owRAHQ`>$_v>-riu+y0YvnJy)58Cx zcL%)tCGY-E@BXQGH{mLun{buSuj9_geLb%5{R*z|o#)-3F|W|~aqoT`SLqMnDt#aB z0$kaVz6keoxQlSNdiM_RZon1(kKhX5`@P%l-FM;&??PPRor^0xCm2`}m5cun_l>yk z@@|03zl&ujTJHbyuIxbT`{TGu|3UA{4z#{k;EIlS<6egQHt)X4y9w|9jQN=2zvtbj zyt~i4e}gM}x8RE2kKqdcyKo`>;^)~*6<_}ySNVtN8V}ivL|)#V^BMjQe(6#mla<;$Mrac<+Bf0`Fsgi`F{pi z`Ssvliu+#NCS2KD7Tj<6@HgVVm2lY`5?!*pEV_;{FIRnj0atX%-lFLFOI+nIJIX3= z23PoGPg&u=@5A5Y!{6n@f6Iqo>cijS!{_>N*;7_IPR(}sWKUV;cnVkL7{(QS`*B6z zgSe{qzx3{>y?Ym~=)410a`cDZy~ew5^X{*Bx7xeU&vN-agRA_8aE1SKxXdFjejBdv zz6Dq13~<%2Jo9STugG4N`0zKlioXX}@vD6N6+Zsga8<6KpXc)V2JS+>Wp7OB{svd+ z{s{MS+^cbg_bObalU-ZE)!_~?U*+S+&vohd;wt@TaFu>DuF}iCVI!{W3cdw* z8SVnyx8Yud+lade_gB3;%eymhMdyDocnQxlxGMKw;wqm%!Bswg+t7F@wK;0o^hFhOwN!4;mb;*!+`U-93&a0P!CuHaYW3cdqZc;DgOCAflP z8eni^l%Fil8Sw6Q?{<54jdz>9+u+?Q?~Xx)rT6Z3?{<54jdz>9+u+?Q?~ak!(tCHi zce}m2#=FhlZSZcDcgH9P-g5@LyWP9p-d*F}X74t57st}wfO|d&Vm*=SS$6v3b@P7^ zZ{L0$-smi-T~+mL9PhuCO!2Ya z=&JtH$H#iI+5TIDzW%<(f8meyM4$BWvEJjY#PP52_Xqe&zoUxpU#)=8R(yY|;`?(I z>2Iote-wHMD*QcF5&zwa@0%*%ud9gvV#W8XEAm%00#f+1( zo!5Nm-RrSTgq03&YUiEY26sr_@qrI_7BLtMH-pPeBgH0=iuo%8jOZw!KtxH{3U4B( zB*)Lg}+5oLMtZrn^Be zV`hZ_(V{|Cknc<9IatXQGtd*W*MU0rO$iuB`P=*D{54cC*{Zxy85U4huNG3C)Zw*= z(hKZm$zqxOT}P$aH1U3w+Izv_MA&~j%$1QVDtHv*PSHaBee}hbHWdF}>OT5!HC?7_ z>HMuZ@1qENd>ehLd+1~IrBw~CD^PcSi@vA%8~HaM!Msd=3IBaAe*I@|XMZpE9{QIa z^$EZyl!-j=Ytpyz(d}c*DctjB5~IJ$d(?Y8o;DXUHa zra$I>?r;A~-5dA#G_m5ZlD;O7ug*nRHG!{`&7Pe;R_TBLBOfVz>ASUMMN2Ut=6hc; z$oLn3(*2hG>0bMXuy+^#Rnph&>D#7(g1_d9^19ICFZeL@B%3zwuM*#pgD(6%5(@r~ zJmK8A zU1uShnHK+E>K^~{BMx?8mUEXMEw5kLdP@&|5*>2Ir2sYzQRAd*Rb(;Gi0W6ti{;z>89M_6RF(Zb?7=%xwl)O)|)NiNLwy< z;?$WlZIMl*($Q<$I8Zk{Q~K~$ceIw3u`yiu`0b%W(LlL=E;A| zAe5(-NuG`URve^1xZ72feUsQ@P#H4=4WSh={~9o)a{Y}2QhlN(>V3a{t#+&qee`2$ zP%a?q7hoKjP}*EpDB7Z`wy<_yThz=!?ACd8si--T!jtf@29%2WElFsi%GX>W2;W|( z0_Ga{2xqHprJ^ON@XC3qXhU5p{KO<=oijBFMtEixg=c01LBrWu;J^d6TZAoF$8YSf z#Xp>_iXqIm)KCRES?i4~1O`!=f=UfOH#1c;TZqHzC@WM`#I)2#)*zx@rKt0P(WczGX^_r}ti4T@Ix#sgYME7IMAT$e$k2Wx`(3K{xscS&Vv4cH zH3Kv`zn2G z98zz)`l}|w{$5#w?|f4cqB#o@P2sl9tBaN=!WFT!yPOKbX;uJydK$$d{7J z64K%N%OIQ&(%GOy@!rD5<7*I1pM)|j{zglmQn^E39PH9j#{N-?sqa+`$~o!u6{-9w?XeH?si;mlI^sMBxg-0iZ(Qy6J#4i zlE_HS3)9D(uaN_s^3m1MT_jKBwUnl^zrA0uzF=0^C03w*-6wfem=-_IX}NF!Qe5ec zr{MvOq}D0=OaJ+wS-Q(VJqh6=hcG4R$w(|XwjhxIl7nq3g-vDp_08DuAs1U^`DPVp z6duer;$>i%&o4vU0{690PPA8Xl>%7a;X2vMWgXr$lJaCKJm{;;vN?Nt8!_xB(=}QZ zWUqqE{jgX3y^9&Tj0Q>X^$jrK~a zQ{gEZh$B04g1vD_O~T#NZ~5K#U`peJ$O3L0WOxGAp$>1AK z?z%~FoylG0vzg@f;pF|qaLn-jrP#B{y}|iyd`aIA1Gh7_6KR(Q?$7^|>NICEib#z| z?HsP%)fOeU8&O5Zt}{4qStrj96IIfmQed2Fj8yJcNimfH(4-BSuh-oa;ccXk>-GEl zz{N@5V!bxRJSielkopEgRIISwa7>IXuQ0KeUQ`wIdo4HG$>Xwf_boTL8r;c5)^&2f zL=Bd8a=lH6L0j}|pr}emuWJiek1yZ z?7V_cX>!fKIIgp>E&xD2$nwlD77G#Ogd)t&0(S+}^Irj&$tv;8(D-eQvO?{_rl8(R1^#E0vOsoK z3E2lMrgsf!&Pw6m8eGoc90_6e#TQ>r-uIN{eS$PGRsX}~t(re;-m3%`ms`+b_IOFw z>>Np`s))cR?*s)juahO8U%xM;Vp%SUjdVd{U@FWGqJE1EvquVKM!oW<=5y)D!}gAr zM9QD4K9I^Bs7-~>xSWOuX=^HyNFpaWtmHx90$h_RP%t7CtlO9-m~U@i5r0h2?qX0* z{?z=z6xU`!X{jSilcKke3`rRsIaj+r_ppDboE(aa_X4!9;r%lwvTB z48|h&dy)OuFBd9>Xe(Hl?E&6Pqr}Y^y;pITG}C{Q5X>sQ(KWvj#pkjPtb7VrK7tNs zhX7TLM&^rhqkOY=J&dD;s5VxZi3$p0g!f==HLErS*c@A){C?F+uK#6c3+!%T%w;V} z#b{YhVgV>;Ny41(d-{YR%q@WjQSSgBVQ;fZ#o5Yh*0jido6G&B8HA7-Y-qhKU)wF) ztjl(1A=}70T$ZgOC+nJ0O5}9r^kJ(k-%-+uS-xR*xzSslVo8~bTA}tNe~p}|U*z%ie)lCR`MSk@iCDfqh(p(<1gY>krtQ6o$2*JkD#;Yt zgddwjq?K0oOpf(O^ zF2iJ}@wlGjv#Cy+%j?L?<%d8+b19i`E zHqI?FUm?CO$o&|)%2EXnwba!(uujd~l|k@u?Vkk?_p40YTFd_B%S+SxXI$;;&-+Aw z_;M4?AkhzeBCX?J26e4}Rzsp6x=Lt<46!viK zBdx*1SqVn#6$3rFw<<8J_0=oF()viX&`4BD(A@RP(aaDU2~P={X3&(E$6AMzb61|C zoR>;cOK|T%Yfn~X+HAjs1!0FCEU{p?6Y~hNW|&jg>f&7^$i43m)#ZCO+DeyI450r=k7-2xn^_T|lpO z0R^Nx{?C!pMf6%1Q9$}`kjDHpPUajZjk)4xi441v7iGBh5qgiD^&TU>&Q<))S^Zvi zrY9=~Z?@k;{r>^oD&x@!VxpXS`I?+6JJs1MC*0C|;%AC+Sy@=&H#x6b*ZoTyiE?Em?J zUDO+2e599Bxr? z*x!KDrj>PeEEoyo751pS_n*EbI7)L{8r%$6`Re8T&{&i(zCs`(u`A zeRgX}664OiFBmmBMUXAVpa&^-4_{&bCVpe&vwzED=yn)Dnv>VZFB*}Zz;;XojYXD@ zh9o4O(I{-Hu;pgJ?9s@6VDJ#;yKL_tE;t(+#IRAy<@j4C<~Y#Y<&W-Ue0tpPV{~l? zWCZ#)fV!|DVB1;>iP3LEMZXPQ?QfE6tgBrQ9<t!?KH%M#>B*|5-vnUdsK3QGsA zQ5`l)Xl}AYLN6o5iIE>>Pk=bnuivU5SBm(NB4U-;z(E&01j^2d)Zq8oYyW<=V?vl6 z2f=Xmn9%UYQq}t+3-c8$1=&iXY3GWE)k-D>86iqb2}d{2spi}W9~iw$bsqFUJ%k#F zHEF>z0~XN03|1p}@}E(+9b4vR-M^baI;s(YVxKZM8hZ}oVI|8itq@X=;?r3MdRLLd zNf)JgiGI@|CW&Pewj(#aeU`d?Cz?-uVS4x3amXTGdXLQErTdWczVf3B$pHpm&_I|5 zUwliGeL?Ov^&E`1$_jCa=4_0=)P>h12SQE)xaeC4<`6IvJW>dWLD;pegjqf#4k`d~ zAfW=$6zQ7gKOch?5~?3J0t*x@KW9?Vx*1cXEKurGBKwSo9$Nwb95oSZ5asz`>!o=X zN$53P{)H5CnE(vVtH)EDiF>3kH&Pj>wsT3U+j`-`_9==^0dE{q z*RHMlO{%!qE|u)gCQ`YsBhuVr?Zn&O#eDkG^pRlGJAfpg(X(xXy7*K>+%d(owLAW* z(Ef{te9HFI*bE&|2DxNktKRr<_S3@laqXG=zBbd<$0nvuwX6HU@=Selw|opj*lS}u zQ~R4{)@4_aJIDOH!sIb@t7sm{D`UXX18z!{K=(%Yl!=0vw+NB;g0JGR@fy>!0}E^VtG z1~30t%7)RRfg0JtIqWIO|GgG}C0IAUZ~&A+c9qK+L9|0*?c>dxFFUWfXZ@4G!(C58 z0@8O~!!_a9HR19GymN8Uie8t%O{Ajww&)rdma4lZbmy!XBq@i)Iyscz5AO0jziN5D zZ~8owPi6+1<7`vm_fz2wmMyMji|ewL!trV({Fl8{m1Qh$6*In)9it@WkU)C{Zwj5b zw7V%LzEbTn2iCa})9Jdw${XOZl%44j201W%xIt4+RU`8$vo9qhXA9cSr!o`ma6Ptr zwg}6q2(>pecUZ>I+B%aXZPB$2*U$(2@zf!Pd z3fVSVNEB*X8ZsL$L~3+L2L_kLzzB7TCVkkDRGHO5*0di9+mGZgo+ibG)20yRdHoax z>YrI!((i30(7%&FLkzoK98OLMa5#BV4oz@8(!3-+zO-d-kh?-*odl@&B~ZnP5=+}( zL{mT%pmbGv%}0E8dT1(4p3FZ&@4|^F^#HBDf8BU|dv#USrh#C7zs?o}^Y>~>7R-N8 zvzlQ3=QTYD=0BhbKrp{oV{o!X$$=eoK(X!La4yftX_l-;&HX!NwM-yJl1>bnL~kPM4JEuWP z4o^(5+&GdBN854_G>|YIb|l(zs}s0&EyK;VO(bg>))8W)HZ4GFj;UxiA&e_n&5K@@ zTAH44^IRrSYs9Opt%%&IWCTQY6t9TN$0zJw(qm7A>rblhj?ZYRug1dj$))WW(h@4{ zZe_+L1H;J^%9xf?Ze;6(f3(3&dz}b!TFs?={#YVUb+(_RBV|#V9&hfsjP6AT>*!;V zG?JKnjpz4^k3Lan`ozK7I*$10!Jbli+ijSW11v?vm9`w_LR|@1|@B>8Y57zM%4N~#>3skp>n4mD!2Qg zaw|h6!)I}*WGw7~nLTbWTm*$oP9R{C9d_mi-GtltdBfv?pU|MM$4yAiSgM&oy*IEP z9t_tX^LA}Zj8N`UiX-|t3|E1-p|oCh^~~Djg5?@nF@aZ~J~W&hAvbCdn`_5{+%m)> zN**=tAEj#4tDguSt359>abB=#j|fwr#xyy2%mxkm%2zgM41smX)Dr4wYp!j`e2ngL z(>#Zo80&$EX=zY*N$1z$%5o&%GzCnwocS#?0h>0qG}NeQ3o!0qNc1ieQEvA-8rCXD zf;&~?3UVyMH?t<9AGzW20uSrcM@l%SMSF)C?Zwc(4C^rkakDN=%#HaTam08wlK*=e z+e_u=h&e>RJ_x=uBbvrMq+wDS;npV^e$39I8Bf%(R-fEQRrFyhaAIwW=L-;@Zi+Ga zyq4Y(q`yaZ;q)g%5-mXNW#0^!C1iz#jYj zuamRbdlH6AUvnczX6y~H_?-pIPxQfUdJVb1>i~? z>>pL*K-ZS(8b522bIOy9TavM}CSm$jn#-7y7~vJ`n`VgQG(bBuH|xj6Ix7oH4AvZD zyytMVl^F+}3DkB?@KA^NL1*7S&iX-W3hbdC1%p}vR#Z!M6lB?q)Rp$X19TeFov5?& zM>(m|aZvO5Cv_}TRKwvr6LRd7>)xFW5X+YEIg$#O zQKqi(Xgy0LZyqyu!8lS$X?%o}p4GPfe;Kq2PBikJrrF%1b4^M#=`~?rW*yN8BT;yWG=>9m? zsXW78Hx=|>$*tsRAz^YGmBMFoTex?N5p*!>m8TT(T!%yRKoYvIYHk`sY=5jC{ zOK&L#&npSuR1AJoNpL(1Q%|Ft3+wynaVSiBC$wl@?~*z7C7e4Uu0*EHMDOS({w=o< zVi94>x=hy=-e@XqI~SrE$aM8oi1j%Zx{21L8BC_DyCVL3TKQAY(fR`AkY^lRS0Iac z$UGvN!rn1QntesR0`j775k=9D)}xWxw=ms}o{Dx;Ko;Ks=^b^5M$G9IKq|bW$BDhg zg?E_P8+AP~Ut{XllpyT0w6@-XMfSx3GYednB4ogMQGQ+U)Th;~y40T<#*i6b*HPH> z7T3ZU1&%^6M+-`awnyli+fRho&dF;{DE{fG)z>pWVvlx(V)iaqBI{;7It6FO&kM6{ zipegC(LpM*Iv({J#-~%&Kjx?{Bma~1GC&&gs8?Rj{c0Gvt|_mb(6gj#EvA#Vn2uzm zJ7ROnBl)ipCw^x(G*w9MBH&a^<(KNb=0Z0exwJ4*cx2R3av6gQ+y>{1%p5gfGls|W zohB_x7`Vq$JeCMhbMTpg%g&eu_f#i^{CPYK<=%e(J>-|WdziUI!>}T*>*$X_^ zyh8Gjj+J{*2pyVmFfS`NvaE-SD(8oyM~_MX4#(ShNbEQ#`{?FN4pRq@0CAL<%)wdQ zRPyRW3|rgmT-&0s5A*AT&(&6s*gOY3=z0%wBIZ(%js=gM#|B9D<3NhFY;}ZB1P`|* zqzNN(UG)_|cB;R!*cm={hGKuaGHs2Itx;@4X{>8Yb#c9f$rtm#O1zV}Jb6Kd+++PmtpTin*Hg?nyM#*wr)}`wR2u-K?r@Cdf=riI)D!te)gg zf_tMm>}8JQEhG1zpl{vmR_ce*s>v5x&)kmr>d_vDXX+L7nrj^leHgCT2oaUY`j;|%pNI}pXm%qtR26ShLPVeeEKWjAV z(VJ(wjv?Xq8?FAS<;9QpAPsb1>KLng+P@WSam+ee8+;CCeQR^_Thp+r8XnO^Hg17c z>l~|U2r9D5h+qx*Q1V!O-3zi{2mLWm-|=i)=r&`~uK^}t@dL!0XwE4e$&7s@BgZ}H&8qQEo(UFv)u6#8F@zYgu>C9MX)S8wkZPjz^!cRzy~!`8$It-!%KgQv(yA=pSK%fb@?pdPKZ*+kODVjZYAW>(iZSVk9J5NZK1M^Kn z`kJzLypVNCc<}JKgJX5h_wMTIk+tE0;E@B?K+4DWQuw(s{NQs5ayB&Yo-z1bUE!mq zdPIHsCde%6gVc5SHs-a@jAC>oKa4w)lddEA;pXHIr|C#?cUedBtvl&R(yk*339>r2 zQJL4rl%+i{aWcp)H2(=-Ld zkH-?G?%i%~k1tKl3UX*fR9gzOJJ^0;BFD_>3xh3Aec%K0-!=jBz|>n2m}f<}5<4rt z0a1+D_;?kwKzkyF4(Aw`uPj5x$Ms`~{z9Jr@{2y-=jGKp^X=pW`9^mIK&5yT#@_}? zi{Ny*wX+Q=dN8aZ*rHvJja|ooiWA(E;1@1ltd_0`lISDylp?qM7QcMFppSc`R}rM5 zT#cMyL#tRL2tgIN>B<;eJ>pK_vj z3qe*KHw{FNiu$&*&5wK&XDMJBN|^pC4)FA}`#Dj;K7wz9F~>OKhKBRP;DO?_|8y#& ztM7jLw-eeJb|1_@V%CxPAVHSi3PkeP2iY6N8fr~NpRh<|g2^A3DhhHB}GzO zE?a9(PFf%bEn0^7Ne>w%SO_6%VOFWQ^$R+uGFq4w0;gU=nOkE~bdH+WY|$=dq}PVn zfwyu-$$d4Zi82V@{Sn0CfrS);cJptrqJYCqjJkh(ru#XLEDyrIvPH^ecZds@pSuw$ zT?m#`ZuV6K8LcLzg{<8Cby`F}1Otd3>ju#xhe&p#iil#4X=&e?9$?gr+V=$yF=Te4 zHW`U}jTyNKSb{d4x1nObwMIFyJwB)ur3cowpq%JT?n(K>P-|Pm1S+E`f|t(#ye22q zQ^nSjs>ZUMD)t;t!-AY7K|4>SnIcoo3ARJ5Dk~%E6k)o>5;B!yR)HQJc~8@sdII=d zn(hnkcI~-Xz35bZJ?ycua!-D#ZZSz3^jH>}2{pxv@!s!;dX)fus%-#if{H)-lP1&v z_{NwQh9}q$vPxPTCjTXPWc|NLb&>5ro@n0anF>m+3KbQj05kv0kIrG;p3|6A2Hwe* zH;MtakzUOIE!|P9r~e%O;F09NWF|0vV$;&#nwCbkGs4G!xaRLnz zmhx8K9j)Zf(1tpqCVdD6MMeWh89AAO^8j9$9vytHI(!`AK}{F$3n`-)^D|3`JWX%y zh@25*eQ*BTpEB|O*Dl2S&w-_#ocg2}ZwFf&WUr>rs>rvrK!c~N*M>~;l3Xp<$>J%? zRRCgYR|a%mTzC+0rnD?>Rvd?-u7F^O95RFFn~)8J>3vKE)b$2;YsnN>$ZX0A@0j&+ z+Ib(gL#lrqJkmZi_#F;zJuh_~s=DO8CLqBhqcqHWTbLJHe?zf{u(DL6_t1DuZC_@5 z2A;Kc3f83a(>qGUzi*i9QV2Hu`-e2`Ta?3;B$j5^lmNmlP$r+KTdT%UDi>)otmeAd-i`I0FOBVxQd{X{;gb+&!-em zAa1G7r<@{d1_67D0bcwl$-{^y^gXPGR9ZD3)&MmH(pw+rEb2=k?IX87y&P#*PYN}B z)M^+VEabI6G58(M%vvpH1|hF~PkFVwoeH*RVbPYB>QTDc0fazvMA;P+ZOX+F;|nqW z$Au!6^c}{Gm!{j4-!JAr26C#MPGVND$;$vAvxDp+pKS?hMBnvaobvDo(>TAuE>D!) zwKTai$Z1J}pB0LAqsWx{wVLa+|<(UJCTa!CD6HzLSVRHLffJ(Hg9GHZ?OOxA! z%&RS{9b}%r-Mj?fAKa;RN0i)Q-S@8i^?X%SYvR_lviEgLFBg|+Tg-;6_MzDJs?oE9 z+cn6qZ~^jOgV)B0yhfb3WuImCd^;LkWcf88LzbU&vb=yGlVvxibc3>7AL!SPOzfCh z>7{gzBXLR-9{FPfC_e`;iq&w4^|L5WY0AlGTdz16xrQQu>4PuE&!d;g(KhQ+iw6-j#iSdT_8$PW z5N)VgNTs)|6RX|i(`mY<%&*DkhxSTGOi;nKvS3%%9J#F5OkT%(v`nyRJ4zBd1>)_c zU>*tP@Pm#9=>_k^>cb{Uu5?;Iy@vxf9Vk@ypgh~nxx8Je-0GcL;Id(%EXI|EGSfr8 z^{Y{}YPpaep_~Jhv(L}mhm*UFYnsDor{e&6wRCvon(&`3KU+eqG`7mNml?D|&PIoo zNWwQ#3>+y04ip0i3V}LGE)^Te`&?jt(BTl`i|{hPOYYGjQ)urHkKQ|AL_E(CX=-3J zto9kc8DP!Kcama22`FcWrnlt@Ml6AdiLrAcZ941&1}q|D?7Pp7y)Uee1+L@wrqC}r z{cBi@nJ)mt|6}Fl#Xj70&<5v98PJ-=n8bk zjix_U`vn|brzfEjyy76y5jz#6dYT%0aYkn6jz$e!qA@jip*MDY(TH!l^swpOAVQ084*=?*FPHt5OHepBDqjnb@CbxLr z4H3&`K7_mRWv4r%lGlKVGSrTGSf#sDADZEX)ujn`y9*D61REGUd;)pZkCZ3a<#g7C z1X57@1oAquFU?^Ox5)$(lVl%|$8{iiNr2dwCV=b@mL{+dmq1my^PaiqS^U*nPz7HN8oGj^4ETt;qR0i{ssv$w!8A!g!shLmN{kUl>690^Ysx0ksQVg#^_q{PS2!J2+l72hWYF<|+f%yFs8 z^<1*8UJCc)kYK%;5497lH{%odaQ6KL zpN?|4Fr8SCkDUc!;d1gVY&m320%gpVeecA=f1od zIy1`zNE2}!RpNJP_A-8h-0C?ZNM|e@89E+e%^Cy6cwMcrXKLpv&O9DInaRJNf^K7p zALe9FDY)xd_MTF?nJd7=K9FKkopXAylXm7inSK?Y9-tBI?(uZ9D#y7lAsFEflRT$R zV?`H0cbF#SvhJ%RjpLt4!R&+_ANr80x+ zNf`(#xM83ok15dI_p;CliX+ccqjMxX>aGQFx_ILGPdsjJ`zcbK zu%mBS1Q+Zeq;s%2vBd%{FK7Bri(pHU|7-Y`e}d(L%YQOY^dMe-Em=(m@DBn|{W#Q~ zx-Dvp`3?LOIZ#QZBPb>{G|v=Be#4N&wNgYp+`P)^hlk9dlqH8DB^v{XQchIz^ z1NgQ8$k>-EGf-1juxqTpahFdDymtgu@c!Pi3PD~~A@`RB*0{hOK2Vaq&=u%3roGKp z8S~tn%#z{uZgB1cGB3vW=hxu|S}9ZAFp(n(K`fZAPnqcgcTMh7 z&hdT9^=f^8%wX=yR5z(i-Ncob31c4Wu<|o>WB&iM1xwo?V{9mN!&{_*FBznEFwc7> zwPI3{PmyXmZe34Y8MmrqZk;1;{X&L;zbYwNEMS!-djfscD=Asr5&pvEE&r=fGF`_# zk2v4U&9i>U1Z%8X%YAqFw$NX@u~Hp}K~{_*>I4ccKW=mXo4`!}3J||8$ll6FaKpb( z!xI{g*%OZ0;K$qS*P* zy-FNdj+d3odm+nDku!bw@&S)^1OPg_#eAE5TM3x%RuRICxK0kcnD%96Qu(q#H>(~t ztEZavn$Wv?o;)wP5<2{ZPp^TfmaThU8-?}9qm|PY0IMSOpv($#{?{Bpw}PTn2Pc*s zQ1cp?F#&wkyUODFUHD#w#mpKLKAxa)Xx&%5e6T>be8}``;XqAP^g^$vfJM9Cm^KoW zSo*K$s`^w;4ro*)$`e<{mCPW^3dfVD%%qwu;Uyr;*dis2qoM@=r-Z{vsTIZbj8>a^ z;?=JvEJ|k+ayuwsX7E|9WNMh}H1iqeuH-kkOYe}gk~xQ>u#!sQN;);g%jn_seZ+q+@!tdf`%3?P*ncc0>9@09-@;k(!@{^iU`%-1w9Q(3;K7P6X_NC3P@ZWoUe24#b1x{pF`S0Dt7ug?^pBr+? zrm2R+gCfhAQ<65WX-`st@ty?F>%@b~(lPcnHgH}4^r}gWy&tACIQ)0=Hs+-l#ca&G zn71+SV&0aE>dWGlm&qTN+KlOv2eOZ)ZrUThi?=eo^>6*qUy7|EM3AkvJT&vI((z)@QtG*>ngH7 zyVKy`Yw6YojkEtFT~)O6*xuAj)c=4mQkO(^eRy9-{>lR-bKx3)T?AfpGXIDKl@w07Iy^o@0}- zyl7$g)Y$kKy%WQ?%pW$!iQ!|x&l!hcKh>r!9yj}RO`&PhOr_n?RsPc$?<;a3eIjPs&+3JZfHxFvvWCDBj_)(!t zwYu6p{uI2S>f+;!*QAj975=aM_cLc+;Qv4Kf8~!|+{~YzIWxqodsj`k?|I%;x;U-u zHR}I+!EqjGh413$&z$)^-p>n9y8nW`9bBV7I&+~Vgb-cl=gP8>f=9=0EV zS#%w#%yZ2g-cD)>2Zw9tiM_*En3HRQ!X{5c*?xF~9cQ&e$;#1_2}v^l{Gwg(p2_Hgvst`1-To1 zB3B%68@v%P;FAooVZIb=c3XZKSo04BITpA02Xx901wY;)GdUHX^?QJl*{aDcox1vH z%t}7_#>aNJvJb-m$0?bj1VfU+a5bfcRSik zuj_0a5)N$`m+#MLzm5A*h#&vgkL%t;;mnHe6>1^9vFpeOH_@g0eX_$#GA z1ao`Np&h=J4=bJ>!^J#^yI5O#Z)%Iq(N8Y(35cJ_&m}I>%?llGT<>Nh6x$*xEsd{u z{i5uA{Y2anth)#xFX`bWkIt80e5w1hoaTie1mw?Ij zC9__-FM&Dy`S#q@+{2-Uf(4462PUbsMj`+Ea!aS#atbiPPZxYFzq&*+=F^!wsPYEOWB1xR- zz;?tihUCA&by4=G<4Z(rC39Z(YhsK;Kxb+Qu5RRvSVtYlv(6TOo)Si>CJlS3CU;Dv zZ2w%{nzNam?T<_nJfG7K;I zyn#c@U`2=^0--N+rQ<=F&?XS4D7UXRm?RUUZOmpCeaiN_t zpnf%n_jM3gqBhEz8;38~ekheok1YOac#6Z97;aLm#)&b0(mK4Y#GC{oi*3B&$bqD7 z97x*cQtRS1x8pcA7bdqOXdK9+Kjhe4rfWO0{X1|o)3pO1^s3X|4yu`du}oL+#A#aj z0EbnTld@}9cB_@$&4;l^iR6x$WNO>EcAn2sg>|RukhgV{`PTrUh4U|Lx@SJl8G@|3 z7K(1ijX3jSxOC!<-OZ`O3pY)uM*VXd>Cfa<`2R2 z5jwE}O2sM5OSlDar>4*P6mW7!UJbxv?Nh!T+~3?ywe%@uA9Rm1*eT*9(^}P1(hWu6 z-N_-6oiNyjE$SAQ?xdgGZASbi*CIUS5GW_EWo)p0Ko8=|#JA@yna0m`MY{LspYAd~ z+kJVRhtb|#D!u?n&8UComgxF@^x?Z<&VZc(l7$aWzECtqhAna^#z3@wpJ#oKh)fML zgO!N%6iyZ$Qb7K1StEdI8%K%QAcud2lkI;O>~H@&UCzGyTXnh@eHY5K4UDZy#?gU- zZ;khrV&U*O`;nT^3_2H?T|^?%3lk?QB2nNq!6BqX<1)UA($Gre{5b+e4r4IyUjEg8f+qI}6l#cFmch1p9Le zn?K@0o!ylh({7=`CMK^1AnYXbgmJW)@5rK1ii)qn!}WvTVItu_Zl|u-hR+21pW&5@ zQaG5;;U9x?(M~hXGaV` z9mG;=FDx_YWMhL@n^r(0J@M9P{T7~G6Rg<^#iEqR=7yHa!CUV3VK$vwqX$&V=mC|Q z0i#s|hE{wDy&dPf^DV9+*j`@mVBu~VyFVmCgTgN&B?h?`!fSiN=|w;)>e52dN0c=4 z;Ng~88MjTC{rv)l(tgH{(-gXzVE=j5x~_r^n?fFEgT8i#2UpSaziT;IA7=ckphb1y z&`uAcYH)0n02DhsTi;j>#yC`24%VwfqVyKG;nluH=kjhnLq|tt^;(uzH*Ps%Y%h*? z)adre#zF4!v~`ZQRlA{^qll)G`k)w*+aPN6K8rkg86YaDHG5P$V-^djsq5gvW5_8p z^DR!Tm4=`~4;0xhfa?w6bYwUFYjP?M7c&qhNesdykGh4Us|ch#~at zd($fAS&|=CE78TGkLCKp>NLw5B{y<~Va>H%>3LdK~LF>)a9Y~!y zpdD0F2alzyn|r<Qf7t%KfY3}Xsy;{!YAxAzQeb#nIXaChZy~?pr z#5x;S*##&sq7Hr~W`}G5xN_)`75=-$gsf{+7D(LC8Y6i)-=jtxv#{ClbD41}{PQQ{ zKP&3eT7bTpYDtbhUU<2YTH!9qWYY4_le;JAP2Kp7q$3q13EzE_@l8QbB^8~MQ(@Pp zl0lWJE}onU0e`7fr#RmDGD=L@oYpIq>s9m8I*k>y**Q<7QMaztk1X51ci{QpI{v?x z3a_{8HgnG9PciDvy2JhE3U%j7;ZGl-dfYu&-!_4L-m*$askLA-&D zZ>fOr&eyjwJ}HvD;vIcyR}6{-Rwj7qE)8>Yjk zJ2z8eT!(S8nC#j~1v%%xt03!YfAJ+b$5o!q8&qZax59JA;TmW6QtO|>8qr-%=M8w^ zSSdDB^={EKStbU4VI8k7FGW!78pqvl6Qlq<1`mzanKPvl*=ebx6h92v2WGY>TKym56&Yk=cZF zsI>S6pO!Yx&ShC~B1e?jIVvj)ufT)4hQU6)rO-7ta2!Ug{LTbFze(BL@QT{Oci{K6 zP~P0-BUjOZzm`!mm76^VH;t0w48VLwMwCWZQXRE#2~nW=4ZAcxSwcDy=7vPHS)J!8 zM3rshkn|>8crlEH{W0F(5~Fj;omd>}TY^6s4z}f-b=eX{R!BR2Cj5GvY&qp_p(I$J zT7!c@NPgkcavVd=(+*_B2;dFJ4o7!$Bkx=zOaTPM5@!V@Be ze0VP9W(?MpU>kjrRB6Se()2~i?J_NKZ*lss8Dps-y>~UMte1EGHcY;+PX5{NCdkkj zYe6BcoHj=6+p-+yi@wbn2zIwx#WZbZ@K?5r8Hned$Nl8@cyaP8ONuqgBbxT657l5~Q4?OLRVz+) z{j_!J`!RQF^-lGVQ^Ph(eRCsC3T~zoGCHcv9!yM^*kDt>~oQOoU>03_x$xz zf_o656Xm9DHzZF452t2jPV*G)s|=`5yAIO`eXH#RYGBQj$a+zu3&(C?x}hYi8QE2?Lm zc_JLm`~b|fg!cP`yRHyWZsu3ypkFMWv(qa{Tjm(LA2Au3v42iANEq`ihm!K`Ur|jCPsfoihjwxpoic}Q;nS{XxLi3vO)>xS{8m&m z3NQFZ0DdgJEclneQScoF%pl+gB*c_oZvD{WZx}{b?)9D_bIy+`@(hV1R-8YB%^GGo zt}r{XpTQna@-z7zl7Ux5(28m;IE*5({|BDL=VKCIU^6|Tt&K4}_0)I?t)(11D{D(> z6`@;w>yDdGhGQet=oHej+Zx#J{0to|(YA}M)twjjCyNH&=^0O6BqZeWRsuGAsNeOTg6=l z*RHap<7nkMspO`@_KJ`sHwlU#wpE6c+cZ#mQxpD0q$s)5o&vF1K_|N_Y~b;*T}}J0 zuzeSi#;2Y6e`2)76a`Wh>42e!78@04y7X?K_5(+Z`S{1Pq8{GJ0w4<{)=B_#zFVTd-2Wc>yAK z5V@5?w?4s@5xv&czBRankFq`RcZiNo`U7W%Y4>om*8Yr!x=sCNd_;mMZHTb?+?fPX zT8IW~gS%vqE-zip)KFyJ2AJL+@mwvRD-tw|=$@BG%)#j*+{?o}iznx_wIli1?xzb>!H)cm z2)b{9vE0;XDv0^_X#FlHF>c3>*XMSz)l`^9XcMhu$8&dKoQdDIDzqQBzb<(`!4GyL zGF|BIo%p>8)=JzFFP&x5afW*FG{L3lVhDvSI}f!6fVWqXRz1?ppUtCMnTKkhQ@N;3 zPTJ`t>^6GI`t^rsl)`^3Xw*6|UdyUpT7nw~gkVVVV?LgxuhzO9te4|>fJpD_@((?;cH~yJl`t|aB#DsQXP!=7lky@7zS#;bCCtW^T42!SIr+owwQ$D=SRh|zP za(0b3laY+oG*U2EpyYVeL{j(IjyJTYGeu2$%2Ye`O=X4;*7*0*c)v`%(O{I&CbxQH zWvkO@X-PmkoT*<8AL?(0_WIi(xqdyA)_09+>9kAPvpDyQ$-?Mvh_YcAqq4f9TY!rGOVWtxmu>ZhnpAwIoNq5LG; z`|#cnwZ+2Oyddt@N`ZC4-1!hB4rF0Rp|! zlBD@ush?HkR-e4zNwAF=-}j<>zmrov;7QV%AA6&@Y53V8A$97vZA7U~I@BOt(7g%* zphHd11#MLj039;x;)1p)2!IYLrd&{uf&j3Wo?Or-1(8RGx_uYatswH~NQ1(HY@1i1 zz;vX+;zG5-pisa%(jao7AN8T2>99SBIAWcP@W?uBBRr1N)&(LxK^r{*O39R!I?=B3 zuU3g~7F`d1!Xeq~k@YK~33A*@5zpFrw941oB&UGUHpfAbvjp4_^~68m$-P;;xlP=V zoF`1q6Uj=XkG)7|@0%aAVltu$;ELu)plg07xVXeKbTl>fy_;|g=XtEzab`+o#_&>M zm?-%D2_QRf7TdQzV#|YM!fcex1sOI<+H!lhQqoGh*8O&JJlv~G0Aa7r+lM*btH6%6 z4zpvxT8GckDD1>(3r{&~CXS5ZY!87Vb~xMZeJC1)F|(vOxLY#;{~gs~1H<;^2Fq4s z7!mo3xLpiB%Lkm&$M?RU zsvxAGw@w?-)0bv4YM@?J;zYq*$IScVp}K@nrXRuQeyxmx>NW3N~PYzNU<(W3}! zbeJ1(9QVWQT$hVwrnT&*BaY!NcLwV0at9%Yf;3;qPflcO`gO;>K(nHSVGayl=PYT+ zkYHher{)N@_ds*-=LehXp6`DCO!s%NH~K=Vlh?+WTf|mzM^HAP%lYggbU902E&uFq z5@e*>tS6Q0->RGo8N#mSIdSIk>QRR+2rHIAzWguKb{!I)Zt-QIdK1QOE6WL&t`G?h z`8nP>t88lfCBZpLxGE?Ro-lD3vtkS^*ohN!IHjOWzZ{DCM=le688?GVEKTsI1r^s* zsm=psZ28i~#+L4duqEl(@;E^yY>7kzhGgfKt7*zDYrR)Kp-h+&U&4> zv+HnaQ65Tp5j$ri4WL(;)G*{0K}6LgkY)>fZ?9Y~!~EK_oGRji%r_Y#zrk=w`|21K zDhId7+_3jbpf~pGSF{Fq>!{ptHvW#x*TXTHZXjqfBRIiB%j!5OqyV&!(O!k6qCZab z%=#r)R4w5wK3@%5Iw7&D*n~|It#P%IS(#`y87jMULiw6!5vd?ZZ?2PY*Oft=Ab*i8 zqURLgfnFFyWGkH=D`n9J*Q>FPmfz@gBq|GGmoV(F2*W5#iOQ-?E;X3BO-+?C}QIqLrXlBY>&q3EOn88 zsc5lXQ@$OTb#=Uqt%tEYVYXXqg9HpAqJyO-9?C{d2LSsqO#L_vf6~_bBd%BIOdg6; z8Sg|xfn9gm1XAZ&4LCxrEv4z9{QoNUrJmERv$A1LF=FY#W)~hTkF4si zgqEqD zhZ$Z>1TST>m|+UFkTvT1lleCpuvHW+MbKr#`s6~kaxmld^!QUu=2&ut?I-j9gcs#_ zvtJ*%^)~M=SoP@DU!F(MjkQ!xN(w1*U9)i#cqHW{a4fn#!3r9M)hN?gj3r`CpYBW( zKh92Np-HT}|KOL5Ox6+X zKSrvhI`}Qk-BmYw5L2+-8CquBjNZ-;Rchnan@3NPl!E9Sbv= zD+wwYvW3NOHL%lT%F$m!0Bk(vky`TA*p-?ES?NQXp4h|T{(_128;F=WMB9Y0(Zv9hKzScR8#+?df5CVzi}pTjH5N;1wRWg z=?vJNUx=%VBONvY{eY#=HGoBWOUcwmZn+2b31>d_h#SeZ^^!U8qCwjFuSg1nT>^}NMS0|q*s8}cDHS?DO*IZwN>lvX}#xX<;)i*=VDj1x&S!K9QU;jqU z5OO1DfL48#nnJ?RpfNt}VlbH?QY(l0IU8f9f@>waCNBO2@wJMt-I#xlDXa<$Ka&H& zoqb*);I%37R!M>76lie5>cI58CE>8il)&}LE%Nc{)yRDMN5&!B#}+$4i{%p?&!pX? zLkiwADR_^9DXGV0lEG&}8PnI}oB4J6d)(Pim`e?_L!dfk=DOXP6o-SPS*24|E8D@? zVV8;6{9%Gf%In}%efz!m>}U1;z^-RZZ(BU}4dhd; zl2F==!wgl|o2s)E&m;h^168_2x?4Thou6~{ZkeC}k(xEQGZe3Fw%y~03YP?W6Ybsn zJRmi!@w@^|kvXrU?G-WsE88i6<5EtknspUgYdvNnW`U>qFC5Lh4)k&eex+o*f&!N6 zk{!XnkQXt%)6PvLV-n~necLnxJs z5E^XV$-S}sU!P=(xpAm)g0AfR9LMJx;z_w%!~Ldqewm4nqYj;Cq;dqz4grEur@=}N zgM`WP{8O}KX8#R-z3lDL8xkEHv#IdM>p<4%kg>dDC1)27bm@Rjg*CKZ#*N=-Jm}%H zatX3IeL+n_kYO0A>Ki?`stVnYnGWcCKOtY%b7MT^Jl@SmuxyY>I|RiP9R*8g`{7jZ z&=Xt|BTx6vEP2Ogw}i299_)AYp-H#VG{Rv|zD68*ocjbHdLUFeI8iF0#dOL(3?5C9 zmb{&RoFF@AmzzaVVPRCXkKyc{>yEtiRO;uC@ncJ&!d+r_Zy5C#3n7*&rh|DKzsRjk zOl^K1e75*}UHR+9r&xe89{z~4Vvk<$#=|oNxpn|Xm6Dtjh2>p}dHu-QbljhJ81EOx z_c)Au%P<;cLW?^7!r)G$xW^A`RI+84Vx~`fv$zlXIOL-=ZW+W06(b?L#f3P&#GsXf z#A(mczO>-Su8DEbLpIOV7my5$3Ub6ujr2mH0oPPWZ6H1xBL&jiSs}9p>60?%WY!jg z%`0MhrJ1y$dZe6_%m7Bq4#fT*%PH#SdRF?6u5q0FI6=j_$@lp#^H?cPa(oYY1)I}x zjs;TwbUHCOae-y^eU{yi{=UoVSIV=Bd*`@Z>=;$zM=Ykpzt!QtOZeaK@DCDHQk3s{ zVk?Sr$CPXvED^v-Y@6rudY$rG>+)J%p4W%T%PpHsd|W;Cq@M}ym>aXKl%W!LVmBwB znP#o@_sBXG^#!)89=*lo_@4xoln%6&9kV2_gqbaI&c3qXFB@is=EwZLD9(0(>7<`f z$4jE*)Ut4g%vmZgX8c9D8w~ESw)JWf#hi$Vp{!2_cU(uZLQHAW5sSXGB$_4=vyg;m zVd2x8lTS~>!atHaD|h)?j+Q<8M~;QV1Ql6G5oSK*iZc6)xW2`?<)+%Xj-6<^W5;tA z+Tc85q{Szzl9-8p-D!g&0~F8okOhCu*lgr~GyexrrFLKa8^7@nzm5CO zVw}N9&C35zy@NQx?RRb=u9<;Pf1k47m*IkM;6EEr2=A1C4OIGJ%tUQ6QFY?~*>Pzd>1*A0L&NFs+*miGYU7OG?s~(?E~?4$?~e0- zrS4-v)j%+I>StY_+<(*m%ij0LM^&7ApZq|Bg1c!$i@p9>6>a2aK(JU)6WE1CvlW$8 zP+|xnfk+53$tqZ*!6cf)VQsWvX$x)irES{MN?VXrfhII1(Nc}dwNYssEv<>ot*O!) zmCF15&OB%L>}C`6w)gG*xzUdQ z*h1sLmkr|r&vEeIkk_*f0|Df;8>8Q-55aW}YAjEApzG_U8~xd>l>PrWC_xbKEXGt(31q?qICGHWy8 zUjAt2_{2FW*Ta2ZHQaN4-ZJI*+<^;D)ZO!QVzaeBnch1G9|& z(;u99?XkqqdlJvtcwWl*-qhsoGv^#nyl-4WT5?*?lgZDIsBZqn8)tmpG|o9|c6#E- zg~`=MW?N#l*SN6O)01c{L`E{J6AjM@}Q0u3j zO8SJ$i`G^*XXJ)VkK3J^kdmz3_li6DzIIK&;kh^7Nli_d_C2US=^xefna$e0p3MaO zJdNk;jKEUxSLRVL^q=&^l$r|@jKq|=i3vtR!rf`fwcZ57lU$ozoq|u*)~fcGbPrqE z85bBvt!i%@Z=n0GN8d{N<~4k}LAkFvKP9nNJzYrO|-jZyt~4^X-L*k8t&4KWn6* zoqdRw_CeZ1e0nqJeIyO?IAR<^o>_B{7e{=L!A}VnL@UXC3)2!YMzMdaCXej^9$+@0X!ehGpeM%N6ytV=Baa8BC@ZEpP_XG9 zo14OFmm@qX&qMvU(~r$xJbIfS(SEk+n0NZwDV5EK=nmQ0snf6ic9S5 zI>_=X97QwArL^Rav;MGFV=yBQk6qf|+0S=gJE&o;q#jEw^5ndtsb7BrDBd zLzWc=vWp5+f1?vE4X*JNtb&Y&NSWeh1(xMkuF{-9>?vNsLagJT_55>Z@rue-d|0K5 zuL9Q=6;%{gDw4?Ky8IP)k=RFI{3s)2uKubJf z5sCCDq4MRLIb*BZjaOSku`VhuuYfM2nE6NmWvx&uedEHcxxVzvrd=8dGKOOD1vG*D zk`hnls=^3$1+r4ys|Pcue9*ayyd|nV@gg%VR^-r%JTd>iYulp4;GiKm{OjDn`0meMJN$tXN%KmWO6no?p7cSe`-RX*2DVG^a`< zLpuT}2u6u{9x^h&WPRDH1*&+#(&B=( zD+=@Yr)(|aGvk$&IXC*RyJ1nfGBXoAg{3RzvXyxzc&3eqNn8__)%?OrFe|!FH3;K^ z;?knEldeK0CsSs2rZrL7svB43mlZBr6yJNAu{Ky)7Oc!Gs9ZN0O*ik3!t%;uSZL3c zS85>*3b7fL=U1TENHDKrZ8;iFUg3(Bu;zD7x@tu+Eo1T8QaTFPQTUiNH zj4F94#?&IaT&th~C8(N`;<7R+m9ahp@zzge z+Bz|nfU#~WW3QVql}{+;I@`x~M?#n@2f0$Pb;=X06%U~xn`mOgF)cBw*NMIZ%rezdA$t8;@uh#NRVj2V6Qt_(BOU z9U{C%!uJjlUd;t={BF}QDE)p3Kfr-)oc! z`ki0Y;YCBl&s?m-e=$US_su$d4R-eM8)xXY=4!?#A2yx

    }QLFt3{JI{9C@ND_u9Q<$itlnw0$B9PPS?>E2=Z@CqQqy@s*E3Pm zW#U==;?R{aV3MYj`of)*!TdIZEJf&KTp5>6*@O(ukK;@Av-w?9ll&m+l;t>v|68YO zI*v2d&!)?+8S!B9my<|03Ots5Uen2VGj6)mL6<&H_-VPurCSQR{%bXzn6bEYwV?B7 zYdRT+#--Z{IwPRzWIP&|?g;2sE!1?Yb!p?$odDe~p_B1xT)J@>Tl)D?WBh(F48Ls9 zbqbw~SL5=l1l_tDH9r}*#--Z^x`rH0C*#++bZwwZ`J$$ib{Lng4|Hy!lksd^x-{s` zVxg09ZCpCqyndmR@oikX6`-4Wlg^)vbK}x&0$nGs65x0LFmm2aetC-QWEypXKU<%* zOX>Yl&}Hz73x4V1ACHb#BxVYojDzFyn+UoVp%Z%^mu?a0dW7z8!=!sR`Q_{U$@n-f zza5}UDbRG%&&Q=Z47xI*<9J#9Y`Hkv`Ek$<@WtZz$+$T#zjM&Gs|z*VxM9lS1zo++ z$v8SLzY@?j3Z0nsxOAIAH?v5m+c!+Q`#@)`)O0ewj?3>D=+gN*OZ+m2;Wr9KJyYn8 z3_~{^bOS;+oLrW&lPK2d%J@5O{%S$Dj)&9nlW}-lx}BhFXokstxWeb*`VtVYJM_akDI?r(52j|={RmzKU+`z z5q{f1w~&XE@ssg;Tz+k!8(6RDWE>xtt`BsbU)FTnB-wcOAPs$_zd_T<@G>sH*`R9_ zIvL-`rCR~I#SdwIGR}`nw+VEe4{JKrw=<8nTqM8Lx80yy^%YH5FaGi9j*_3y$@n`i zzhtaYHE-7ZWF8QgZX)OwZqalrhe>x4=(Y;ogkk9J23@1j4VS+ipsRmGr<*ejzr&zw z5jvSK#4X2h=I^VTALk9~XUo~4f9IS5eodNA<_~fCc|q6nJx#}XL=-4qD}E(KkS&~g3|B^O73R13O}{hD8Lk>qDYZ?{|W(yG7Ho7GTrK!%3IBw+ zPZKGY<|N3L?-zZoic%k6mcIogA!P^D11k(if z{7Bc!4+R^6%=b5dEZ3I>>jjqqq55N{0+WF~7?@$WKIRg^^8|nQ1MUBk;L||zZ3B{T zv*3>fXMA6WX8;*KPVij8`@W~kbEDuG!R<{t-c}&vZ4#^#oC0M2uK%va1%e*I=f9)l z9|kghi{Q@$mjSOuzPCPV7;Av*fTf0UHof6<6DADfh7q4jNq>@P+&Rd3SI!De*F&X zDt80F4rIOyfb-zK3Frf!1Iz^8@--cQ`&YI5KY---Q%vZH|G7ouVZl5g%YP%#3(Nq{ z1%8NiCZ^l>kPiQ?;EljJ@c(WDOam|n$aLTNvc`8G)bYL|_~Vdad=BCF2+kH9DL8AB zme1ut%4fXbMS{mIM8?18fXvU&#Qhy0)&g1X z+XSWrct^|_L^@67fzE-3Cp9fxT80Q`md`fUG z@G8W6=006d4+)+p*suYS5MByoJ-&OdroZ+}S{|PPGW=->hnNRsKGJ~`fp1|zOMU%M zAm#nE;C|qhaIXc<2L2L(vw%MYejd06Ncw#IxdM18FcJ0m)}5GJ!Tn?4Ooju`2i^$$ zG;mi?=ks>p>sNIhO$`hd)8tGvNNd;03@W_>UHBgEBL`Ot2oxLwB~|lw$4fTBWglr7qV_AoKHD zkzq^&?k>c28elGv@!wvd(GZ+lU>H;2|H5*O#X!-;?iWWAgRgeb0jdWm722lpmHKahGjLeN^Q+s*wz+JUn}Mj(NtX(qSY&VuWYVt$=K;sV z{nCwwaVc;Wkox=P4LY4|f{O*u7JT7)U5-saw)+Qw%>S1JD+NCdWcl|m)VNvDCzt}H zJhoq_(_09n`-3lNYyp!0Q$X^6T(C*-E+FYo6Z}pAZT7(5a%se6Iu_bQP5o)hd4{HlaMEbjXS?-l$rI^|2i z=cmAnfg#{HU_KE1CQS#H0F!{H0awn~?Qa6`Q*fUJ90UC8Je`j|AmWYb7JOOo$G{6g z_XQx!zd-!26ueyUlR&oTcYGQNzV&@8%VlMf|bCF;LZaw-I+kz zoBx`t>3#uZJ`Mnx-=7HnKrnZXwr|sbYe4sxEZwet4;%~kOF;5#27VIwE#PN>tAXbL zuM_`?;y)V5c61Pff>N~4Lf{2(p9k~+e|xo#w+G1be@F1^K+5+nAoCjpGQY)w%LT_t z`1#`gq~IvQr_q^FKKp^^10M%6|7(HF?-C%>xmLobi~C$4(;W+Bx}yX~2p+mp^W6m` z-?wLL`u_rw{x!i@1n&Vd-HUK*sA8d|faEB;Dme#{2LJjgJE9 zf3x73f-le1{=0!`2yX(C?;XIga4!d{d;rgZyX$k>zYR$LEFk;43xJ;io+0?o<=TBz z@DU*SRSM1ro(=a1asOq84*w&Nd|w8B3fKu81FQj3e=Zh$b-H#x24ueP0y5txFVpTm zAl-iy_Y30wmAIS5{bO-|Q`}z_cdfXq#9b=xmEyia+|z)cMEc#+4C52P6~I*BRKX9Y zYWFt;akxx{Uk!AFZWIuvanc_%uvP{99ngg;=>jtUzXpyrj8Hr9Ecmxd_)~&=fau~T z{QwBMa~~6Y1W5V@asLdRY$Eub2RsAxC6jR{3ixT@7lB778OHU%9fIEg-VOH>;3)7J zC-|F*I^Iu!Ye)|~6XEv)OVM7}0n6Y&TilmO_}iBn#?A2O+n|~L*99*SobXxAx9<|e zKo>LVdqC#LD>xFk67EDGc!ldYst|Tm}D1U?DIK zxDI$9jNVRQB=G$8q32V=tg%?47Ae}FNe9QOiQ zjv654R|#AWyamRB@fQIZe=Zv7Qn>#UjfMPo1DS3}-1h^Sei4xI76TdY8u3pDvVPA2 zE&=jIc@@C6RKvIjcq5SXTpz83dn}Oo83km1yWKkfAt3X;6i9!(JW#p+fJT=KcM0%T z;AOykpa;nOBm>ER;4H&f3-_zQdx4LM`%ZDM5c~{~@=6x>8>2P-5y4%+YJ{6W@?Q%i z{{kS(Ghf`9zzuLu689xQmhUVeN8<6pSEbi|E8Sh~r7 zAmcR%t_NNZ_ZlGi@MR37n=j!Rz!C6I75DpSlyrX|NI3_A%YcPIrZ*1A_$N|yI==@N z!M|DDj{=$A79i8x2qgV&z*TVjfXv@`U^4J&1X3S%1L?mVm;|f^GTko$@o&sp{9*WF z;3D8eWW3*_u;lwJ5bgKeCxF!N zABp?Bz+$-h=3|E64O|0vK9F+18MqSe8znp-$h}a~UkPM7XN#M{rT-f!Jh4^q%Ys)3 zjulK2>`Bt}zZCq6;CjKuf*!%MfvmsL;yw*X`QTEpO82PXvw}YZ79u0_dEvjpc|eeydj*j4xCod4H<~AZ=dx3R`?PN84Y5VAQLtKYnP8@%N6--L zhQ6ryf{lXJg3AOm1wDd>U^gm3#TRT8tQK4*m?`KHGz7b$FDkxZqhPh*GQmtikDwvg zje1w{1sesc1(ykC3VH+$!EWe*iZ9qGSS`3rFjLSYXb5(r{#AUzM!{;qWrCT49zjE} z8p6AxDPW=fp2Vz0hr+3;!B;(rurk?;<_&lPUT6v$(6py+_<_;(i2W zI}3T5_^isF@fitkk??CrX#Vy&bFbvzJ~zBV!tHay7m*+GW1l-8L3zP#pEJKu@^7Cj z$6K~^_?0?++EZ1Y+1g!Wmrueikx#=_I{Z0t8=2b8GfFDHxX0S*&(YxlNzXply-M8n zIqsiG{AF`B{iEXcc(r?uxb1V2dX3`#F1(o^`N? zIp_s;{obg8jWb0a_BrQ?;>KMk^}9ym+vl9OOMdKg%|XepeUAAwsUQ2?@_I?nKBwFu zZu?yFGI87IkUzA`kHIT{A4qxZbH)dSzkRNF49dpx+2@EiirYT-3)`>DkHHCl81pH& zeQucjGvimIbK#HuGTq(co+#zD&++nX1H&^cP5)WRpM4J3FY)bjw?}RMn>2kIfbF~G zkalNCdF^w!tA*Y^cY93g+dgN@{dT5rpR2u2-1a%z>k-Cq``m1)xb1VYJln!>`&?{| zq-URleV6$|xP9(*l+=%X&Xup4W4L{;mE#<`?Q^U*K|U_Ht21=@F2*z6_C22c@TS|o zw=+e;?Rz+ni@ODS$lnWgxON&NATP$Z?=^M7pKkje(=4I4@8vu#;r2ZozTS)U_Pri{ z6rApAN$(wTH(sn0{4UB5ukcU$^RW9ol-C(v13peSpPlZ5$iLJ5VhsOc$kQ4AW=#CO zG4v0_(9er;AA){3`JIT#-_jWRpF$s;^uLTr?<+C!AB}Op7el`#hX3O+^ao08siQ(T76OQRolzi62qhAg6wPov#yfuYu3VwpL zw7Ak4Cn6jznpn3Im5xA;a{~HVikH7)MV`8W9Fy;G8E-7WD+VB~g~jU%OXOt)R4^z* zIEq#x`#y45>QVQvZC~E9R~NEv5BnOoR$yH(Va_%+?^stDc}37GfaD#Hyo%uR@`z7C z@d~ASxcOeT$_}G);YALUi^{@;^Gfn7D+^2K2Fvfjm1Ub>q&CA|LtJu}7$`S|`NcqC zWqENyn2{Do*($%oAFlu?NB&FJt_9$^ykHd`?5rsbDTK$3g-R!(|MQAVaJ|~8sFNY7 zB1NQCH0+KMM>zAm`d@~N%!T=-!LqQgx{#0C?zTttWp>*)fGh6m!n!sLws)RxO63Iw z6dmq!#|Erf8`qm}vQX4^OGgP8mLqn!F)LSIUVa5$Lr|GlURer@RskUt`tZhq(hA-t z&nx14F_>aG?{Mc86c(2ld3kWt3KgtcomZ4kA1x2N7Q&VdExU|LY!k#3F*ew4XOZju z!Z=!Bj$qZ&vP#NUyF)Jecj*o$g9MATnf>Ua95tn5cVg3x!E69@bbbUyy|7u4WLFf7L=^5 z0BV~@YYS}%N7ovrNb)N9?t(}Nqec7Km8@QJ5GE|b+ZOUF^OxhbCQ@g7#YG<8?XWW9 z6YrkClCorI9$xFBYShlCIKmnm=B?Wq3JB&5y`ivTZLqumE~jp;4Ca@w2*+XX5cST9 zJjBmO_!_+DV{Jj0PV%I%1ZSD z3O?vpQG_j&;=s4zFev-FFU;2^#rsOaIi-YG7FN!T@+gDyMttl97vO~zi>8GMZEyXi zifP6f_+2!0%CrnmhMPb8yxTDZp=SX+=a~V)3@@+Hu4U-1txeZ_7#OZm4C2csfWdUWjlQ$e^UAF_VKyQbRoo{ z;|@q%dZ@T~&~fpwB-j3-)9{8bB^$_`!nsYR} zz*j%V^+Ym0E?S2C!&xg%-XFt9jqx|hSDjtZBHp~FCf-UIkq}-0wCWfwDgy5-_=K#AOTov+`D^i0*^hk944m*CFoT&Iiizz#rQ=3)C>KZyHF``-&5fvZ9qWW8XQ~_IT zw!>v`C~?VmvAQUSBlweZRFaX;WT|h}@Y`38fZcGaPg@1rq62m@pap*d`=SGOGN73O zjGNOPPNRtdj20k?BVY#u7#iSH&M_6k`SB8bVKD0ZCD1J@{6yagQ+?W$j`4v3^`!~+ zrT78|KDKH4j`w15iY`3j&G(V-SB9`ChieJCZJ1Svo=QfkN^Nuct*R3>Z(Qv!_>Jp{ z*{SAx_%wO4`ZPJeiK4z-0h72yed&W=)bJ<6#h8m*CD@-rpMLtt=Mm%P-!|kdKC+;c zb7=ri!Yz{Dn!bguoBj@xEB|&s?6DWG(C_DimP3S3YAzB@E$qXeH9cn4F*De0<{ZTr zHW4Ki-{aw5RB&ol2mS=x+I>eT2g`S4mhYG=^eUbuFH7`yo*Jz23j7xGlt*UM- zcobjiR8^$DosN&=xhCTqllPw^v0DaxH*H@pyG(L!L9+a$oqVtjPB-PbR0k+0{w#@g zBDYJJ@5TB9mefQ|0zbD8MON8m0pUd9m*}tdb)aDAY)s#g-m}rB7}$ny0xV>mMClX0 zhm+~L>AyfQV|(2&Vl}IJ%-}J6;Kt-<=~9D7_y>umt~uQ9>p~eJ%C1@X1W9P66quE% zzW}L3i3n~j$|F|QF)P?@g`1ixf_$YhQY@yR;_G5DEqq(n*QJWp)fU&7|)R{IuHEnK&Vg$aN$33JuN4`VkK^E{KyKf?v3Yz+~`CQF_;dlA)anP!PUhZrn zDn3R8cKkRsKGW-kO51!|7^odqpaqG+%<&7D{46VUJo@{)9#uY5KG2J=7TH{sNka^L z$|+plso;js_^MC&+J$zVUyJ<6_k1_>c`%&yhw40#bhf327y)Z!Hu8Yan~sI2-`wL? zuq8!7$N+fFx)b=0Fh19=N!oQLLi@=EzAA>LV^}(drD8~C>-rhHWSI2?!yFXfYIzs% z`@3`=a_oUG#n@;ncZPpFIIC{;{ zab--E6}Pr%!dP3b%)YgSX5VjxR6MJW@w73}eTLr}>7T_uqpk-bVG~S8j0ukJzs2bC zgW~)IefvDtvcc!}c^UH9ulujP9V&!hrQh4EiSWg~sy=_hheFU9A!xy)?%<=-JGH#x z_IGgw=C`)!p7DQHVo~F4ot1T!-@FUoGrR}iNxW;U-@=Cs&2kSrFC|y= zi|Hh7pEJE$$%u~`>~Ix>nu9Yn)g!iurE1Ci;TA=P$}t~N0+tbmwnwLy=l^c~J9Ym5 zck9Ec^Z&nF{un~0myC|UB6`#(+r^_+8 z=-sNRhU6xeyf#PEb;Rk)n#|x1tkF6KJlmoMJliZEJ_TOYWCeFvIgR${hKc_NnTD=x z#M+rEV@&rD8ToLy8Z+NHb$$Qu)>qx1-hSUl>QC)qu}2H+D#VH>FnfO062HzlPs6BF zOj-b6h8<>pwV}`bZU?Acs(xLRab>KVN_Q<5Aw)+gK;2X4Y%f<4hx+^|dsnd>QdP1SKs zZMbLv%2HC=AxS6ARxq8u{{w_2lt2%~18gYNSuMa%=b>V)r`>}k4eURiaoCrVn zSiU|zFOJuqP9?wibKJNxA1Uw^LarwhN{@6a9E zKL9sB!iz*gWD8dGvRwsRn2JB)dH5Us^xs2%mP*!a%`&y2Q2h>9OpqRP0u56djK-iM zg~k#t?Jy5wp@9S@248i`(^OgN#Z_TsVL!ce{v%lp7eB8&ZO`lmmWRHriFNUxg*S4}Xyj<6F8VneAS))o1GUOC_E2 zw3K5Tin--DVyPA4_BuZDCr!Z$(L-8-8DfjH4Jn^dTox-`^LKOoZ|8qs>^;PEQV8mc?I7l7}?S9QYt@DvXQ_YWh6 zDyr!_(L0fTR#hh~DXghp|ChkS^jFW=5I79ujE&F^%Xb3fmCRw*FJk-8As6apIbEdy zeOAl!=%BbPqX!sKA@LUO6~WXO>;->Wo!>(iI<6jcT3hsnfLaF9i}dCey%wYgk#UxS z;`V15vGYMC=vc`qL&F;m?LHh^L+{VqvmcF;*+C6mP!*{mE$|E_@YwaDQ_Tm4nO}>D z;|{tJHh5vpDbVmpoJ(!CF;vTS(Q|>1n_qi;8E-*QGW;3}Zp!*%R!-KU z8!<5Cnx5tJc&(hVUMtr<_0=r%cdnbbl|1^jl?ldE>@Iv$PiE~?y|`J`X$B9QIUQ!8 z4c5NdYX)|E&D>pHGiRsiYeG}&v~mtxfey5*wrnfVZ25MB^)9g9>9y80Wt;Ds$>Y4{ zqH!r+bLluYN4`6dRu2B81{(EYmz+lUX6A17npK;%^ft7y=(l7o&C1QXH7id|fxNnZbINBd4yswcG8AGJ z3bD+}UF@}j3%ypA-)j|SqD(W*x{1&g%ZDbk$D^8fFx{*>NBMcoy0PkEtXY?)9^9Zx zQB<1P++)xc+T$mf+^*cOe9WpAGiRR}fQ)^+u`}4jeIdmJn><#CY|X$n3UDiBw;6wO z8t^A~Q??ai3W!r}ZDBslEj&i%HGjBH!M7_F>@QQWhbO4a?W>eyJI^M0%`M9amMR!V ze>{l;0qnDKnytVNRBfZz3X!GXeAjEfq~#gf&k~^Km>)Ou<7R%`xtpLB)lM2qC24J8 zl1_j1Y_^!~n3~K4FGzx*NzA$ode!VFz~XBwq|RUTZbC)E%qj_5!4@lLH-^1U$mcfX zlV!HlVL7k0MHSgnrL?x|LhfPdvMt3o+xj+Bj8ajk=~%B>InI-9-aRfo+gvd&Lua(k z%M9s=%EwYZ*s#V%9D06gjzhg1`^irI>OkIyXn%z(ob8Y2K(qFLv{qQP+Q>(*@Z?|4Mh2y70Re?{SODADw?g)Y)9l+~zoE3ipg=q6pU zXk^ktm&R|Q%ruBH0YtyxP%X6HYp$s^bF01PeyW#}DkMo6IV3q~{^OJ<8#US@ikgn1 zdaPWSwV)do%x9huyOvszV9=xuC(Ph36Bf(NZGvUnfd)6MWrIkO$PTNj(X85*ZN3qu zKhi?oIl7sO0NFfpH-}9el*~gVONY)v^cj%VN49QM37EA8$ZnG@u~^d+pZQ0-FUY6Nj+wr#dX^u*Bd9`0fURvxEq4bb*JuT{!blAk z9+E@9kh@ED3qeS)N=eVRndSF2@Nd9`cTv#6&k;!kRzRwP+VN!ErX zshX;nO%-Wuq6!ZwOb|e5i^eU4#1}*2%d{j5#aIo}yYTqkDZc^8&u{tABjor|qD(6n zvJ66&Rmeaggt=y{8K|`aZdzkxT6e9FAT3jwP%J}lp^2LM0$L?IS8ETQX0XHB!!}?B zBOR?3K+8ZgHrGHk3nAnx2szkj=5B+$(SCC_V_~Nr<1zdXb|OcIk)w`qSDXux2X`T7 zFan5et=YlT0m?L5JYP)Xs2J}j~s$`4C)X+k>byaQQBZ9UQ9Tm2Mx?jQy+oF3WN1fR=8`Xr)b_;XHD)Zx6_gJVt zJnL?2(YVE^%4K#VVAVLyM%?;KL8X8E`g`Tp*!oikY5uiU=!>dCWyc3sq1OsDno4d~ z&Q?=(aOy$TVa_&FiOJ%Fsza*Cp2d{EdB{|C_CT9Vb;|%3NlbO3AJ<0oFkabrHgS&el&!YVW0)b`{-5`vy|cTeN$2FO zjxCnWU1Ms9&0de(d9nKTqZlw$e zRELDsyp9f@6IOPg4y=vsr&6o_CTF+BX@hSk=JHUj989Qkw_3TIp>dm_arMx+T4-E@ zr7qN9CX9%BvSrq#^VwHz){Rr1cjK?AHca((o~WUnE4|H?e%O`%pRV-ZW?Ne**lgGc zJ@L|`IZnK&Q_!RBOoqckG~w+`hR%;;Ss6XHiZ&{&%qXKm za&1(|K^qk^RYrx$oZ6_Mw$%+OpfY?wHIM*q*Q$0ZqeH!6y#j@UTR6BChe1Y3H9Q(6 zYP~W_YzWFI`PBoAl2<*@C{fY9X0%Zn#?p{EEeb6S`P;n=ldvrfQ{gi-MAL3N(f+E3ou=5NfGvdw2;9WvpRLg*1G zw(_vl$3iK$T1>42m#Ke;d6$FprmqX5(XN`A39dSC*w^msX9;SmcH`FIbcoMh{W(tW-fSI~81_YJ40SpMF_OZ* zI4^7TeoE6OyXtu5y4`o2(2M_r{=5d>kcpK?nK@)q%hDoX90J;XI~X+_t_6)bvMy67 zu!Cg`siJMgfZJblD8*mXGRiMIvQwcSzHYlRbgXb;cO>Z!CR~6N=8_BUc6}blB*a;t z)I@8V-<&?qZ(c2H|D45B4+ z10~o1?C<@#qMXq(hy|~K`$KluVRP9-Q=}Q~Q8q>KQd3;TZnb82$58Cpj*)hlopP&u z$t;Fh+d~tm*m3*c7EgM#c;ePF$a$2d8|vx7BPt{`BTeFA=NuZ?C#@x_C5??{jn)Q1 zsiA}4On|G$Z)QREzJ4H2C@524A4`eTpL~%k@zuVh5PArf0H9=<)Q)%4zmJC4mX4(1`Xw1u-Jp(=n$$v=<{||8Jrupt@{%Y|Awa|rL!>x+(9Q21zD$Sp(xn*d^ zRVrb|#b!TSI(n595Q$3KWHTg14AEjjt`3LnhzZFKhcv~61i~RZCBzD;fkmLlQe#Xr z&{w1O4j@>)3a`wwI);ph)p$=|UEe>O z%%QrQz}{$A0~9cWQmRAymL9PLki9_P6&-(U8f7qQ4E-|;M{Gt>gWMm7*lZiMhZSk7o03m#;CB@lXbyuPbqi|>EMEs zUKN}VcENccIi4ZcO11={P`t6Oy6f;H;#l31q%{sDdQLU3cpA6*@1VjsOjkf5*5lOP`@zQ^4qc5F z1%W2JYI*M%Pa|A)mnc6B$sGDgy-mV>~8J#@1oq?+_K5A?)M7;R^5==CmMG!>%if~a^fO+ly= z;Hu@xL8ToyIR=kOAid12JFLRy4i1}P)^(_`%NX`~{86PAqsEV{8oe@1q#%0F#UIG% zOg^XTXO^{BwMIO|)l6D>RXVe-4T+%>S@<}^}YPGtkT!m@kgLm4bjZ~Y~Cm!Eg|tOzL+L(Q}M?VUVB-1|BFL3riE z>_>EmzLRf(=;iDW0qazNZU{Shj3>qbGpi~Qz5L_17sLX{hFaeAn`a;+jeheQ3?Ktd zKnx(&-Qn;zGODT3&-2}ve&ofs($_Lew z;C%YZA1Eiq4QEHqz$c^C_~@$W^p`l)_^${s+tPdB_V$`}B-0*^JD7+Dr^J~}R&wTCO_e@_~ zO;sB%NbBCA4HIvumeHJoKhkYstk8znBbgmvvjUqL0~g7IE&kR&p$^|wa#JTe*--Sj z&tCu%HQM8J6MY#MrS-98rUkNUTQ`q?0_n&^o@tAPR=x-^q9$qsIKsq%vlL2cE~`=W zm1|epBEyEoo4G-cHndUqV&4alNo9oEnRt&>px3>;8hjYI)$qkNGYN*rM`;hc3+3SP(4XM94V`*Z@xmigS~JjcFV3*h!h8 zHxK(R+K_-5=f+~g~!ayoZYSm>RJ5Ih)+YR$Uw8dAg$h?aPZ{oz4s|$9pwnbceJ+> zuGPMyNqk;qha}Q=P%&7cLDx1qeD~EV%*B7y6&R79_^jXAPxaJWA^P-K|6I2 zKcryyKR;cVV2Ezv2)}+G5Hj8^YYH56_}kSNx}kOG_*r8a{sMVx35wC_wX(3=!o{wv zQNTW+8`uv_10DyrMp4n0_$rE9b8XAiSmEy&V0<9|N20Fm=P`J`2>-cu#{W~~ztin} z=GZ*;yx@(P)UQJ&W{1XHn$5Ey;nj)kP!$@F{iYn``3P2{QGGmPgdtjFi6TdL6Iv2M zao}wT5Y{dudf4$2l0dt)JLTTJsC0GG_d&LEoR#3{r6Aa;+cDp#b`;v~db|~Nh0|9j zaYLl0=XAV81ltd6@)LeQrWuPmnc%~4np!}_|J%@wgsw;yLp+&Y4y2ykrC ztxOPZ_EG=a80;^q+K^T+BM!qXkJgjG|Kv#K8`+UeJxY$>D0eJ$+BmM zxa3#Woz26OTr~0NrU6E<)-$cL6l>uq%b$h~16>q*knBcoV12N?*OdiJ1Oo(sh3p5o zVSWHF0cU{akK3n)@-uTR2P`juu$8-z${Ne|CFT$c`$cF^al&2 z^331~yfncIo=~e>*z4e^R$kHafO-u-x1Djd2C42t;r&%yuMEeZX~*}c`_0$QYtpg(;?Y<8u?=IEkA)k0QI3kr z@LTJkD|g}lG|?(`hrnq+VLCI&A6n&l+&{`+@VvkE^+Z3`gV0szNRTn6mPnRkE&>;i z(fwQ3Bg*xouIO}y=At`70lHC*C!aQ-sp&lp_N@!cxvmEi859~ZQBk1!?XD5yg5%`k zw^B1VPDjU2ra1$d_0#XuK{4Ky_i-qJD1-dNaSwU#OFC&)9j|FmFsqLDej^Df|LaoG zjQs`eak7x40u!0)#nGu2S<~kfnZduf_E!C+^{q4UGP`!{NRD1`1+Ppl!FvlQ4rJ92 z*roT@C*McP4R5qyWY+rDX_`I`o%g;364tzN)$?x+LzJkA5{lJ2PE<+|Rzy~7G1PF# zN^;$Y*nN&%e`V%yx$fKWMz_lK2r1>5m74zGpi=7G_tm^{{&0D>r4m!GzhFNZsaMJC zo5<^%t#6Hzv`7EpbHnBJ%?)qx)1|F%r3{k+N*ILH`PR3Rhaset->iAVH4KSE)=AO% zkJbL+^ejQ^S$ri-RDl>K53Qle)X*A~$05IeUHXITD~ahjhX9SOsrrrP4qW@oSr>_H*|53 zVNd0pB_81@vD5!k5r6RPQKnGMTl!@fG9bec_EQTZ>uvV_6|U2=^GwDD8S;>g-orNW z`pUdl)+fZiqX)+5Vy54mjS&QUg}XU|ScjehXJcXOdsJ+_l>{ejG3jyp7kN`j*qixs ziCzh$dafFe*;80ubur_C4Sfw1x7_{(SL@ESS;6D3+ME$(hkr@;3ksomSUiZbhiucA=GMc1>c{9uF)-++57I{cgUYDy&LE6$iy z1jb|{?Dp05Go5ryf-hs)>($oR&vZRe^-Aj-BSyZT>3ZVBqAYVD%e8l4C{5(j8UD{FC|8PE^f6x>x>rG zhEqoSwKG~$&70FQUEez7`j!uiqgBtfzHufOgP+Z6?LN&rvYpSr_9e9F$3sP!o%&pR zTj7M#yeEuAX+~w4Ia@8P3v*kbqnDdfz2zJ%el)?iL*R$-|CjjR2En&z!MDT_{B$jN z21N<}lF1RlpQoN9g4Z_-V+7xh5(pQE;6bVdj~iog1%JpHEiCv`M*F2RT9Vy*PZ_NZ zt+&1P^--vvL#=P5jC>ytzifRYd5C7L1Quz=Evhbakjj-1yCSpRR#@ zF*SfmAGM#W_myBrA@Pn`{!#j^LiTc0`{yGGKS%8ats2d2;y5%O)ecgH)M_hC z1Cnu!KJ|DfTh?+7Z_s6rzY~V3!{IU7FH}wNR6_!Z zKd~RLDu*H{rg~gXre_QJ4hIi4=!jzaPP$GS7uprmMh8=zaZ-F|m8IzIPd(D@pOpp8 z$4i{BVPL-t{TPl*b?cKQSS`|rSI}y(L1YiMX8F2Zp+`~8kv${zD*7+Mi?@)m6-BMLL|w!b|B@gkZnx@p&oAlalYTlJ}a)8`Y*-oCsJ4+$eKQ z3>%=VoxSUA4FI_egl>eF-BQ1ZB?F3;XATMeQCL+xhE+v-tsfI2m>|7Ns3%8PDe0*t zT1=L#FQnl-BSWz2*kxh(iuEmZi&-wBTtT`#J2QLDxU7TkxSHD+8DucV}72&1Ui=${HwL*g04i?t>S~fGV@+ z5+`5ysP%bnAZp!C z4Yet?9@W29&j@!jm|>Su6>3rb@cbV7pkA$|*7`YXKb1X#oKXY)F*Pvt=_fHCFjz&p zAe^crr&R-9Yd$)_s&1~Y66h<1Wg_`2zINYm-mO$Uht zWrGvhv{Tkg8n(#1;qw~R$lbq2WFo5p7>w4}-Dc<4-o@fGO^qrpq=v%}@Y73NFpYXqLsDo> zG>S*?K70sBjACTO-WbvI!zyowd+*YEj`a@IOdBd20!KweowknA?IulSR|^WR`we&_ zi0^8kZtoJ^rjA3mSuJf+8_}&Qtn(4;7O9^WNI?(DY%>?Y<`D;fRd)BnH$3|F^+8vN zBMjM@P-mgU<2bx&JCu1;r@q*|Ja`FwZ3~%;l?uQ9F3>PWQsTl+PIAP(*%^0`sYEvj zgUGR4vm`Khz`^A$d$^|wQC`>%B{6mIUrN#qPFNf}X4qvtMh_SpeBwYKJ;7aoS-uml zTKy&??5PHOaFRwbf;~&3@d|XQ;`26zUHliYIDuNjdL}vuoWw^Q`%I4HAKhOPPDQK8 zD8DoEi{Z#9{4pH7jvU>Q$b7@QtCq)(Sh{v!6La0}+etv?(ddzFyg&x}10Bi{6F`eN zXk;9%jXV(JYxG-~=X2bJObTi(ROq73oLb9Qi~9&k`tWqB>ez57 zuiC=DKzCB0hds_4D$}(Th3oMww6|*A2pg^BjW{m{78CHDoyUDWxSTQ}*o_yzsW!S* z1vg;A{T0^}L10z=r60N;Kh!#q0(X5ve^z~qx87GT1P_70bP$*}fhhzJgJ7eBV53d2 zQ3#MsmE|C?Yyt~ejFWp`J%&jrsWJ`Ky(tlEQLDUadw+-761C)1wIbJRNCbhp{`(t8pagLmw7sSzx{%Ft73O9a6xtz+FJB!3P?%@xGOSd2>p@JcC~W zK|=M}=5yvj?0nYr7P>wT^TaBp^YWL9*DdT)5D<^Pq+Bo^76*e zm@QZckpgla(P!qMiPK!}=OIdUYD-;m%{I4q;DMJWoCCm1>)ilVK)gSJ2f@0Ll!4s9 z@~AM*Q_^5QvaL*yD(4)OGjnXfoP%;^x`8OCk!>wT5n0Sc#mx0dUl&$3)gMec_cJln zFq7V;DInq&_%Qiw>oh$Kn5TyU))(APJJ_P8jCLiogfCcys<0$FF^F^~<{UlbYs8Au zqxka;)~Ot3A#3>59}XG->;2Y(v8cfY3`>%Nn@n{w8JEsX{j#WFt*P#h;X0bR zhimdE=iLf&(Bjmw=4^fWB-;YpQ5XREfrE~4)KqQ8Q6rw-MpK2&PU6wvZhdCmw>jb= z1ys#*TW=~;V)2GGnwTH@`dpKJM_u>tMSQh;Q#_F~LG@LwTYX2NMsgkdW`(;Fqzd-W z)J3A0th3C}D4+_m)Z;9571mX!)(cb}xv2(AgxN&29yhs%J@o01Ug;N5ryq@;rG`O3 zPvJPBzDxGXn)P0pQhBr=wivtp;C=E)VubM-G#GUh7n;rq`fEDM>3-{8^dIZ-KS9mN zb*VAjfPEf7YdD11qYs`2^J8W#OkcMNkeq+-9^{}zIP#TU+b%}|6ICEn- z_qxBei=SCP`#}WSnTrj)`@sZ++KCSiO+@Hn$=cx1q{#fRgiEWsso84nTf-w*P!TKK69ffln;d!|3BJ%9!e5 zE{5Z}{ngIhxB_Ue?_#KFrfopDvLwfPUr?5WZ}|&i zB*@v9<^^YDWkPjbE%Cc9Ir$X*zIMG{h7JN9G747(Ug|t1=PLdXuY+(>7hY58=2=yf z?dxfO@yV6Akjm3otvy%cmSOA33(fZvu;F+Q=lqZ@=0D~eesjJDj~&3VK;#Y08^Ywo zG~48&9NM^jmpk5kqk%F(=ZX%tB_^L}?>J+d!yyeC2<#Y_b(r!xbdIkrFxMmHbz^}@ zd7T@GlxK3QdI63SE-`VD}CcC!bez1U=`r(5_aaflEWAU z_m1+r9>+mHS<`?Wjp!k=KA@KTxK$p#m#$X+{1l1Wd%&EQV{9k`v{4Oh2CR9b@Zrx1 z>RshBUwp`CdDee3j7kLIN~>0N)I%c`IQ;Rd)g^6ib;r zahbeJ%@b@9e|xZqzw~btanyR)hQ3A=6IMm+Bxa^KP~5{hsks*?O``T@?zkwtwAOpo zXlfspSFmExhtXEefIE7%AP8b7fqBs0bxJ~1)f9#ugJI^;t*K^;VO1L?xXX9}a}4#v z<`K3{oTr2qL^6oAjS;Ro9{$Jb$7!y*aq6iLe!P#Sjw;o;g;9HE8aG(f8xf-7fqGCp z?D#n1sm-7J6vyMq;q>q%@$e++;mHw?v#DMm{@AMv|9N48DirbpU)VaV>00)d21L~nu-uc1x zR@>@ae`dt+a@B#xD8&`}EWG7{5NNqLeN9SIU^h>~av5^eBVdbLMqOt6gsS5>(r&(o zw-mm3GPC}@`amaU+b{FT`UI55Y!%<<;rojAh3?tDFTfXXFeYtJ#P>z`c5y?#Gs|rC zPQU`I`E=Hc-QG*v%_{EQzs#`bbr_NehjlOwhP^NWv%gk5N}DP$3o!@w6NTthh46K% zwQm#}OVf9;bzd>y3S}nh55f1Gr6vNSj{!ws+Wzi_L6x;ej5;@>Q_eYzu^PSterqTC zskamQujKV$S7<)|qJJFmP2u$QkIxAUy}f8gMl(6m0YGjzKNvAz*v-RE>QwQ>&EJh{Kj+C~e#7EXYvk#JP~P8k0SbJo3pbeL+8fJ z(8n@o&yCbYdl5LOXv1^Dn}VIiYLH?zu!7bJ+q;2riaCs$Nzf^D%r<9kNhfXC><^`2 zo1FRIB>CsdwMR6kXtC@A4wL_Q+T|#~AZ3WCmR*4BB%vFDL(AX0aS$t|SM|;U)Jp;C zhs`jQN(~IKU?N6reLTyyLM+?kcxe>`GI}p?Q2yAg^giA2eWz{NmJ74n{#(pUU#+va zwNl(#)>n#fb_3%SUuD$MgT~kc7DI)eLhEdM@b%NQP#yygE0m!Wui9CVYAHxH3v#uv zo(~+pAn|lBQcjj+kj_NZ?+aq1J4fh}bOBFMl0n?4f$Dl^FUQDwP@~;&;vFPhAU;(Q z5;-g^GFywxz(I}z^;WVN`;vk^=3igLi+}LJfvUcw zsvh&b7ymS}AMOJlXA263jSCzaRx|G1*##XqyE1?;1{cjYldnO0fY`7} z*ZcJG@T8huI4`7r3tkwWcZcV}8`>ICIPS$%1MT~73pp86b7JchCll;1_+c+5JZgUv zjIe=2eq1fHN9`?eE2&}*5gE1j=uvyW>j@0o+b?|%7oOsV>pnqbG z05D;*>8#ew5I^2S9rJh*-MvxI+;0t-6)js|Aa@s^f;1k)U6 zX{i?8@^0i$A^Ep)1*0g5t@@ZAL+C~J?$||ktW4kfGBT8l1@4=3kG}0%`pVm`n_m?l zcP?|xun56o61)hX9C$AYFf4FXZ@i>HUMdf%+z)Y&2qh@zcqAz5$wos zyYfv%1pWDdy>K(Xr=KdnG@0P5<$HwrJ>twSd?dekO3k$iBKd{Sk^sYS%XBi%3p(=) zZ}*5vl3xTn^80DYFGwc(j?x4}1u!cvhYB3Rgr7V2Y$-kUqrOU#uHi_szly2gMBkAx zjh=U7VN$cm{wkWhy=GQ|qsP*l*~^l1;DxnE3}n@gLY!qu1bxgVj|KMdvLs^LO@3LV zJ)qo(B2x}4%6>_Qv0@WxbzVfJ0hw|{912M|;klv2^f22H-{$iOvT!B?p zoI~cx19XSjit5QOczOXZ9+*|TaOMH_S&lzq*;7uYLr$}>u^K8ym7w+042}=?c8b-#f0QZzAZo=vaP* zR@urb!G;a;hW*ncH0}Lp4&C*m_9F6MW4Uq5sq15K$=;g)HgCtW;YKhrxb$`81jQRZ zC)s;B#Cs=}2ltM#zP42DqvK&Qw!EY`IAMgfX*uiHU7x)dJC^qLB;VmCDuPRM7@-~Q zwIV8l1C@Ok{ORr;cFwWqMk}#PZ|SwjX%y_H@k}zd+w~#%@b^jZzJPzS{!z10^^bas zQ~%HsyZ+a_e~S9gCPDoA$MphT|409s`j5xuLGbl) z{bBSn6_n~j7mkBjw)&u2o!=Ia5TsJ)p4!O087Y2)9mC6ta#@K1}i^x%QFw8_has@#w!OFif zeaI<3E`@Yx50S};mFTdQzRgzpu87f7IY)9!aPQbhqZj7GVvx^4Seq6a&v<+yY9Gaj zX7A%NvUNX-5p5qzsXnB&G>7>_Z7fEWN|tm3Xwwa#OB=v8W$oH}FNzpI`@Z5o^Z=_7 z11ucNcN)MhhXF*eeJP_!3?S^GGJp-(C$EOmU?bN)k3su~Z7a7IXEE>*6zK$Unhrf; zceo9_yrA_D(ii^T*%wCja1X?=!s0>aj@Lf30`!O&bk+A;3_hYz)D?NzaspRNMDF+$D z2=LTBh~vH;)&sCN%XjNg^N-_x32q}`r}-J2$D_oW^^11oJaE)B57#O%(ok1GD5R+; z4-^2TRk}x9hcn;M7|tOl_FsWB_7@@4KJIeJ*M0Jk?=}2?9smDu5(nsU{H0fYbXaaY z9>VP=-Wb<6$6p0W7fHZ`16HMF$JE_pp6lS49eKxsgi2ox;Uni*5X^$`o)7!d6kw;Q z6kaOE7dk}g({S>DO45qTf%_2=V(s(iP=iI5C zibgly*Db;tA2?y#siX8i7WPLKN#{%hg+MnpLJye-9oYpfSa<5d8J?{AgWh_4oydNAI{fs^A>Xg?1&)rnX7Yx} zJnGXCEw$_9|C0Cq@lh35|M-Rk4H|kE3yM}twA!Lrg(|I@Ac@WD(qYI|wlZn95-Pu)ogaBn?15yqz!zIB9^`Mq?oRfVxux~y;J zDF%q1_@ohUvsfgoLKuvDRh|{d^G!+ARv261%fnBeJ5+hDcawmAILJVVN+sVDcS>*% z3M_hKt1(v8Ej_(|KMWF4DSj=JuWq56LAV)HH?IS}I?)^mUkOuV85mY%>4{#C6|EA~ znmq|Y=p!Syy{QH!060UGUNWJsm3(jewJtEJr4*{^vsq0!$?XBQERIjtRV@52a=Vt!L5W2rw6)fmQ7U)bI?TMzXg z`m53UUm=`QE&A6Jr8K_N_pZMi$Neqq0DvH!%A-(kC(* zr)gRQ=gUk83K;-~e^h9B&A zQ@BQYfUICOeH_qr=NiCPJe&bqP4Pe&yu|b=kBQj~Q5nI8FE~BW@J|)y3CvQ4P|443 z%#%D6m_64`e$nDQ$wPtR+K1;C?VkzK5PW6fU@ymF$S-5KlsSV!KTdbh;i_a_Vl$$HFDnWKRuHM5ES(=n&wPLYFdAVk6g4CE$8hwe90x^>m_Y*R>GXC%}q zBc(GxX+1cbGy|zI2kV3RSo=h4HhLLxOk%$Ejjl#|ENYl<-9kTtiQNc#)(uj}@Si>s zDJ0*LM9-3%=PH)e!S?K37>jMj9P(t9y>&_ANoyUf)Dkaf@Ew3PZi-+rhI3#v@wmhg z-F{XBFLCeyWkH$1&X|eDzfP@(^`1r>vnioHHycQT6Ws{M+BYZf83}zR)YJO|#-nWR&QJ6$JXLAa=`hoUj zXV%~h;dY*&GR{FM=hhz(m^j00ItBUzwlC#~r}T#@9oT(kcj!QO*ad;CoqkPm=Bg5B ztP;-gGn_dvA?F#Z6Trp-4am*DCWn7Z+rgC)*vE641%^2BhO)4Y!6!MI%D!jN1$zYu zO%Ux4fWlCmd*2hP8`Za4hy^VmVQE%pYSWK=Q9pf{ez^I)68A^p2#yoOo!!q@K1m<` zRrVidbZy0W519h4P;5FrsOdqc>qdve-K2?jITV^`$GWGA7fQWYZSPa{2a&o8iU9+) zY457!n||dyg;&DUDc=D|85Ln0%{H z9DdMhO~&6ICkl7)5mae8??|m#YBi}bVv8MXmJ5iGsM{&Vb(*+b5LuTyb<1!igE##0FZmFJbnCR#Cb{xt$@HXc@K}>`#gWckzjof zbOoiVl=!=Pln9nGke!2gZ`-B}JCT`BFpKhS2P*U#&*M6TV#zb(D|o7s)OxIu9nxQ@zb%OQg3!Djesn#Xi_4ZGy<0<@{+w#mLgo% zp{n|_jZyq)+(KT^w`{ojktp~Ze50Kl(eJ!@rvsAQ@n~K=gMAA<7-DF_ux)OqOK<=H zdnM3sWh6$QLLByqxFB|URqc70^S5mnTjH5iKfFg(JL8BotYdJa9oe)OfpL57E_t-{ z$RpE@2k!sbf=4w-g-2IvHU2Vd+|hZozi2yk6Jii5kIdAMV0xE!m0@VQ%Awg^?@XMtAL&(e^C{(nH_Zu&OP#pA*UNJ7;(bh^K+&40jmSE_-)@XwLAvJ@*|Wj07$lN-mkvJ|Um zWm1Tfo}d=AnYA|{SocM#ADB`H5mTpyMObTu@OW%tYOSCyc-Cnl=sdwp23H68D=?iD z)5*BUmn@ucn*ovFC4w*6a~aXiVWum!909D`P_?|5$NYE^`yDhVW5cL`}Ygn0Etc2-{Ev$HTqC~P`=i)}&64<5BXI>WMU`RmBvvWzr# z(}e(wejuFZ+QN9SF=(DV4F6qr*_FD7Md4p^6W@xgOaYD9ghC8-E zh_cpY_-K5$0XePvxe*Xdw8WPv%S7q!K+duZOR(-gG!YN>4_&)aQiBD6gc48#zG>7b zgH`(yg!uRG1+hcngu@h;-4X6a?up1eN^}d(1{avDQho%Y-h6 zgZ0J3VEs9ev`cW!i}fW4^%HYA+~0+$MixmIT^PoFr5OgYr+5+)Yb@2{OLjlDE&U8Y z8kwQ&Cc#3u+sSbFfJjQdFBD4RgPqLWE5C2yFnkm_S%Biv`ymxz3r?`9&-(q{-${GbjQeN791 zX1{f2V10u{Oh5Xi%yn?P&W6gK3T~V7E0{XVmYh#u=JaSiue=U-k_SwDpc(;Ba z`+Kke_xgGZWB^o4xIHjkPtJf6s>wj{7X>&Chidb#L{OQ2pmiBPf2029-zPgCz>Vq2_<*i9Rg=&&YIL!^~L zYG)$KljF*VT6gYo=kK$cI9p;O;Seq(yd683Jpo}F6Jyg&FN0mNgJ2Ah zZ!%i5XR zN|K3W9qyzh4$?Kft=miaRk36WG=hU!HP&;_VKOFt)m=>O1@2;%w=(txizHa4VKjoCD%Lj$ zvxfuX%PkdG_z!edOvam{PqG8qxQuHQv_zwTAaJJ+?l38x2Bz4GX8E`Y8X|Ko)U{at zE3lH^Rgi`0T|s_<+6oAZu9$k_9o0}@8BL$qj5br|##@nfe<{n(OzVARh%x6eu*VeK zz6&*W%?{xv8GCR=j5J+xVJUdhA`obhx~LV1$PpQ~s}nC}s9nqtXwk=G-0P6{u8Q$U zNEFbfKgFB&dIJBr;?MOv2x8XcdBs-h9QmM81EEBm1tmbmd}!Da+|X1c=&_6}{j?$l zvd|&MDBP7NS=7fU#gEhBIvR0ZNs!|K1{s=;0T>xfbu|J|%M+k06K-E=6 z@O(?--VTw-v1%cV2x}2niUE7=ZcJ)+%P#!gn))67Mz*GQ^3f%WH0J0MHGz8D$S4VG z#~a6tE?If1u+?rXXM2W0#_h$c6q;(4Hx-%{kTuGC%) zJX?+LS%nIbOw>7>t8HJZrh5l6Ir$yY}t2P5|Htk`?bT4}deijwa|tk|}KXW{IQ7!2VRj%8v?h=}U1DbK$% zrLzx?i6pM9(krMwRM0##zGSCMk*dF&=G+)c{RyOLR0;x6#Oc@NTLExi1k$AXE zR|GyHlP?vBQeO9tMIl^%3|+TET5~u~t*eWi45=$ZIqpIZC4oRvHp6(-N?iq%yHbw> zeOA?xH@DY7_Eg#}kHK)@7+Y{mKi_Vy-;SrsBdyQiY&&bS@DN~WW#p$6*Hid+8nH;j zJRN2LExmviuf3v_>nzs+(9ME$uHDrz%(8=|}c9kRbkZ$KJo zkvQgw*nKK;CpQK8Wh{(j{COq|+}+56fvFT3GyqLBIDhjoU?CDKt$d+ov2J8k61`8} z+6{Rmn2d@X>prw0!uhV$psrG%#L~kM#69aij`4~gU?Pg->g0I@arztaNWdtyIVCj8 zSENz}vq)YxEM;eRfU>5WLP}N&B>Nem3M9Vx)6My^F317?KuyvdjWf zX%=vSR{%IEgr#ahkJ4V@-gPNR%`#@=s*Kj8a{y8PJL9I$3LGmL@kJ+4)+b-Lep+IPw>f zt@uDBL^tyaYRGHh%p$wx9z<&pT$wm)StCb+)ecFd(rW3bZ0H}XZ0IeBS?fAfbGWoM z2*h#mVXlP#Wz1ea@H($qBoqs~WOgYWh$)=rL3eQebJ_#gCPo#iZ6|kJ=E4J=fvX(p zO+1*OtHcov>H}3jJ6@6%9g6xyoEHIx5OSO4%>rzBX;KIp@e++S7Nn(BPKNSF6?UQd zfD19HN4^!!-6J@G$O6o2TA~nRL6BuJ2wuQ|%vz3S9s;V`%1K~8kRJoctj@{t=o5Xw+IF0o<1;x9RB?|VK;)iBkn@*5d!H&fbktXdvv*1=y#CdzsKKxhv=dmIdtTIv&UB)@+kwY}=p`#F>0t z$b~pu0prH?A%%(SfEJ#P1iS5>nd+@?+uh0R@yOB!cYW64r7|#&+$jTjqRq7)r<$M2 z{M~X|yjglN^kGXd62&^w@^@=R0X5ypjzON-fbE!4fa1w(zmuIfu9WD=ZlusL1K>jt zD}+5l(jY#fI1kEwh+=Kxscu;1^jS*6nGPzF+>4+=s`VATZJeqF`CSA9FPvSpT87E z2k{qc=azD1uoQAc_Ywn_t%xt(rt-)~b=JesN|nZQFWC>}mS$SjS_kbmwnx@2kRq&g zGqneOuw1$zTpK@p)fUpKPhwaL(QKx!&G7Ka*jp=ex!zxn;(A){XSrhQ3I87ebv4(KfJ;hE@m z6cL(CwYi*XKYsYqAF5yRJ@SW1z8 z^7GvJQ69ye+|6nNe7kx}2q+o?Ge+U8=QS%~tCdNHNy> znR<&51Mhr0XW;c0pql3=ETB7g8d1t2%!9)hzyW@KS7n}l;V+8R>=0ws?6tW?{gZVe zfef*HbvX#igr+Q7)Uy!|T^F=dC2mq9?JD8@Cn&l23sg0Fgv4`l3(VoaL-NFMWhq`4 z{?l{U{B1IKJ=}#M`hytfu|&8WK{CFE=B`yTcX3UkhhjN{im6NOregY9T8MdT4t{I# zTZ0<;e;>k}#qS&O{Dpq^$Nx9xtRpZ#G3;!-`{Ve2E8?EV@6&j9&lht4-b|-Bcj0^I z$(cUi>{>d6y#<}itIOs-q}mqsY3Ptw*DxV_zljpk0w*GL%ukQJ0CXis6+?18Njju?Fd%BrR(Q399*EoBIcS3kMn(Wti!3&l(` zQ<`HCa!dv(+f?Pv5><>8W}s3vh`W0to;XH~gHZ+hVg0|SY7)Iz?!M#RvNC`;OIhQA@TO%Y|0ER^~XU^wgm3ECJ{`0SfL7jN7xwi8Cx!g}=#742s6A zsu!y4mI}N(DW{Z!wPgUj_uo*yD_9e``Q-0-TbI$X0*TG}QFC*_ApIe_8Y7 zCcYhMWf}n^t_>6^KsqCfi7_|;uTk~d>x>?cHycOK-IQ%!%62bhhe_G(rCjQzT<)c8 zH7QrQDb+oA1_5;yo{K|+NuT!Bu^0!USdU57DL8hK*TU-5Quv9`U#NF6;<@VxgH*o0 zbI01HcB&L_&|E3nPp6Sitq^2V)g~xN3`KZjH~f-Ka$Og$V^ zhz3v%$8rmvG<=tE3K}nx{W-cpSL#$i;in^SWl|A1ijla9ZXDmrq+l!a22$&;sxn~< zibS{8G_{aI`m?aArOi%_MS!F3Av39}T9$fAdejws*x4dKI+7kOqZ;Cq)|w;Gi^#QD z)oi7mu3XBe!|3z~L%B))ALA7|h$VdsrBpZRK)m2RG#p`}dq?E)I~2<|(D$zpqT!Nw0+%n@ z+YSm`k^{=Y69S{ReF5>Uv-aIwBo=)@nKmIN+nmS_ZZ0 zvrA&n4xu*vVFz%{OieunnP?aG;vf_K96^GPRGbj4lsa9x8$dZ_&`3C0iFd5o)L2&2 zW3B%Lrzvaw1?RtKRdv!yGroJ~SJ@Xq#>N@e0HI*{Nl}mTTe1VPD73LI21|$m z(naJfvYLa8{r3MO`hWgu(tPU3O`!kNivH&yC`^CZ>kb%cC#Mr{kYDB!(0`qx|2jo~ zICLh}tI`)iA1Bm@uXp`uBItLmAurB>>Nb0x)a zX_aCf4&|buJzC#S`{q2f_w)Z`BcH{c=^|>;(3E$g_2Y{4A|?NV?H7UVdEgn>RWB-m zan%(lSX)KIp*5Z8B{k>tE-6kY{tP60mHx9gUA#nnr-h?>)p0x6#>b2u^akR%3LTVH z!(JA8Q)k1zK?qfFM8J#4Ie425h&D7KTCxlh;D*zW;rr;HAjsE}(*TYW4;w9n#H_>&+BZ2#C$|0kq>7?I*x4ZaWl1gl-~p|<0lca?h`-rC)3t-EBzmpTZTx9jY# zD(K+zPY+kVGk{b~QIUpMFG*N%sDyW-da*wqGS!Hz>}dxH`bXmK5tNPYBj{)n^bk$- zhfovA_mB{!iBN4VzN$0Y`Szb?PU#RfQW87P){4;XeA4-VezDeET7*lJ)R&B=a6`Wf z!>qko+K}w4&!Ue-dDwE=xIs5BMQFMW2If6T){Seh!HP?eD%81dLl8yoPV~tRI1WAv zuDI;jMqKi`5g~mQOU^wCvNH~)PjO-!G1$oNtPKwyH1e3(c?VQvoUwTU9N06rAm1BM_UmJOcub2qy+ zFGviWMWCY#{0rE((_cg5-YA;DiH)b1!^)o*a5EuN`4r?j$i>QIgI%)&C1dY#dli%* z@PfDn#@+CL5UsST{$yW^HsJKiS+-4GTi*kX?M65=L`0i&aj_j+#(7D?mO8Oz>J6R| zw!?_0tL&_l-g1YTkE9~9NVy#wE131SI;A{ZUx1z(_SsBzr$$PL#EyZGq z?<7{jiNh*LRkVXaXJ|mot~i#ca)6@-my#93x*8S75l;NYK?7aNpVzy+X>ayd$5MRR z0xPaB2@T;NZM*f5JNS0S;i}xf`&*67AlFlCL9Q1SxgIs}l>CPLYhpc@nu;J|<7*7)f-b4K?73yE$0Do}JhnJEJ`I3Bf93v1oj zV!MSk>5469xD#7m7HhULNit)K5dg{aE3ZKzCASU(BE?2)aRNyI?PI7bWXSUn=I-*s zZN+jRx@*Z;^gMZONRKVZeuz2pN5Mh78wI3vwhVEH61X5{rBWcji#_Bhp5VF3lWtErXMrJgZm z9hhB)+`ir+1zMSl6rF_4$$3uQ@=0~g@mfeLiH2cV)@xsCO0%EJ3%nu(T=D#&dV>f0 zX9P_j{JD6OmrNhb(_`QwXHq??(WRpqqGf~;-H>lYDF!&NP9QZ$lmteUqETL%%ULFX zV|W%tNTBm)S75b>ApzZpqlG8$cZR2&-?y<(O#SQ{OgZD#%B|vO{uw%V^jG?f7Ai2T z#hbaCni;vzl0GF-wPRstvw84k`Z1-A&+26T>H_OtjG1ow?A!t{3j3E&8q9{)GB!)FQi9vRI8?9!QAg~J)M&@AtB%zE_SRI#aq z`xwUc5QA}%9O?&o$3~CAh8i1}=8TQh#(85Szr1lIAengWO3_Nomj6=Lv*n7*uA8tb;I{=D1ao zdR2Deel6o>`ijXOtC-L%%z6-{mo&X`=Zf)I)?g8|N^9vMw&|KiU>!HLJjE-0g?M1_=Qyk!79zo)_pe3*LyYqR0umyK<|6b5#S<4`@ zC+nAwu$s9~3oCFYf&jzPtaW2L|51c1aYUJw5wxMUPj*2J-o!6xOmcE0U$%zN!LHl~ z{R>1;rNI|J0rHx?4M2enoY8#ZpTZ`)023sb1G@80)s?*}7Fo^QoykGC^B>qpd0$lo zQIangzVA#U-hZY;<`7~Qr(-6}^UU&i+0`)vP_|4b&3?ERNi_|Ielb>DwU1@Ax8A#(_O zLV=gBub+znYS_Mhh_)P-JrCWg!?Ne0+ZWjjhwB`Npg*!h2RB6DI&_;O`^X`)AG-CC z9jE4pDE-iUAk&KX2kSOb@%$29a;WK8ZU;!#FGFu$hyg{*CbAWr+%y{l75w#G%?JsC zrLLK$WwPYT37S8q!>+W#n;5RX1YGuEWXzrn^ngJj_GX9B{?>nw z^Xk+$Td}shRjn=GLXfQ7rMh|1reI}I8A0EXE-FO(X2GD)sO)o)M-HXTcae8*ny2!ABsJ;g88fptDIJ)FZF3b1EIQ{s56m>Y~2YG;5V+9{9XUQr?8Zj5(l>7Mm~qF|%M4ZY+jB9|17mo-FH53T6-z2veP(QLow> zNKVv<;ZgQMr0~$kCLfv_Jhm4b{oI`}K9DE$!?y~4&c4CHOCiC1?C*nvA3ZQQ_y&G! z_6`p2#P6KH4G!Lq-ynVuy)iiWHh$SGH0G}j4o<-DO8l1M_Xd8WUPnbHP;PSV+e(#V zez?_!0T3K}!$i$@m6TYWKy42b5$%mk?NuCrl!6V`817txrJ24Xh`wQz-6ISO&Hgyx z)0|N3{{{+`K_9NFs@XdUcLMxQI2D_;sQM(_jj4<%VecRFGi(m=K3uw;otgs&4TG8-I zL4~z$tE#Ws{tE7YnexJ=91oxd9@^pjPV3Rl4VaPFZFXV#+LISKfL~l@5qjlv3iaF0#de>aH-wl!J$vp($g?)3)!Niy9 z1|9;61^aKVJ8)9Let7*(!#bh^xm^2#L!_T?!^{L3-1OStnporLo%^k^*D-`>^U-wd zb@zSBuhQFCr<&K)(MId3*z3uGql8ypTM~P16=oi+4I?okiWwHsR~<({$@m<`W5P2l}@~FHGLVSpkEHvr;sA`)#+HE=!R$c>9he45C_3mda(gxc!n3v*dhpO{)bFby&E zD|pj=CcQSqnOT7SDFHBZL;*Y!@>YsDauF>g4qmP}rZ`)T%qk6Tx;O*(Ud*APxI~)5 z3&If-i{BIk{O~GxoKCQ* zhNa_gZBHLHMn&=DA{uUAEJ)D+p`w)Cfp+SHJ!G?#f84Ir$;9cPiIK7UV~Ei`Rm{KJ zB_#l9HYwn{M+WsdMOG>kIFLzfb2_Mje8H^vO@lJ$4eY*d{BgmTHsKErNu<-H8^{G6ie z!{`#0MCiM4N6JfQuSU1Onl)31nUDQ&xXPg>oST;g6)g!GMM|lAtW23MwYTvQrRD=# zvP8Or$3Vv&ih&x4wEw&d&TC?rLGSzsB3$0f>6F)i)^68x-3Z3|yDDf~f-Bbixy2$# z*$*mK#@vvs-ve$KzL2*8M7Bba7}j0>LE#UGLMSHOFR>&!2@}~+iefpkVuv1{LcM7# zkhRsHf$z*Pa(pq~hRX6)B+Cwu>t~n*zhP+R4p)*+{=nw~L|Uv#DLQmPDH5=|lG(K? z*gkHP$oZMQ7`2iwS#sb&_mC$h010bd4-Uy-X@Ie&5cdxCJgn}2HSTDC+@e{PvV9yG zq~C~d43lKJKgnrG0$ky^kIf51Jlh|8B*Maohvh}eqZn_wfI$@ooI9gsbvVH^ir|b) zr)+{Dh&z{$#lfH#deLD|mh(=$Bdcz}xp?dgefGs;AqvaqmC@5T+gC=V!Fk(Ip79Wq z3XE7Ui6(oGBo8-@SLGp?E>WY&myXn~i7;F0VVhBM5bOR5Nz8;}8(*TOXL=jvQ2UwW z)&g3E*LJ37jf5a42|BaIc6_V>%a5p>fpwvI``S5ntc}Y^)2X*Fh3=t~o70)m83f57 z=jWB)A}doWIO(<~HsTQ-`w6x0rmLpymCGk!OZqo>!-wta-hyuQJAA*XzTe>Y9yB&2 zvPP_gBN434O`D!!$|O@ftLsjup|v>AB0g_1vsM;c_h}wD(x3jjZh9ER1u{&u?mJ5( zO=85I1>-TBNab>d6>15j#_o|PW>`30Wt}}PVN4OD^a{@|~9`;&lChQg- zUh0yA7|0Z2Pm3J9tP)@B&wER%g1M?PNYJ%6+7MDm<(n$aUQ7YVaR7V1_Dm)R<1o`=6flu6gc zPKpVj;$xw9Ri;e^%(pk|FdSqd(dOIBE@e|WLhiiLH%PP(Tw#;c!S)xC+$dof3^?#f zjg=`NPD43zOwG;|5tZj&=yh87hN?GHU4n7%q6dRjFBze$-X28)1!s~F+|EP@q|-_9 z`2sqqz}A(qn;t54krn4@3Tt&tuBl}n@)W8AKJqtA*$tR0v^uS;VICl1^{pF~?<%?B z86IWM!!s@CqLAb!{sl26s6_m7s#9%9&sQ)gX>YB6{36mG_L({1BznOBMSh+P8EgY$PCi$BcYfnZ$ANRLf)H{*;ICwF@v2NK!}vml`261a)6!qRwjw9%%uns7q5Pl&^MUUP8|?{{3|{fnGwSB zarWkP^Ej5OUWZ7tzlx|@ma(%5TXpEJb03>r-#Vsg1*RAw1LvMmSh~goLyav6=hVLsuSY0iS8R@o=Lh*NNy{m2hLFj4vvJ9R%}c&$!Aim6#A#ov!KUXx0dxo z06`e3+*!-7!nI6f%U?{8y$H&_gY*0WMldcsmpMUlE@7dWwNe^ROtMg{6fns1%`g0i zc#h|1;u=d#)lA*kIldTywJIBAvoyZnw7yRrkmryDs#$MF@Wm}Q6uB% zjqeyMI56ZpujuMi)R`GqR$_;rhncWT?Zb|5`Yc8~ZaHDuIZ(Ct04xyd}opItS52 zgmZ3MYE?)r#txS%dX4AOB|wU-?IXoKGLCR41~P&LBu{{S5a&G)vt-;%(c@CnnNbSY z4anIO=lw65`iuQVj$)A{NNr+=Cu~D@o$jbAj=qxjTT*)KHN zQ2`u0(YJr#C`D9i;PLu&0L4ONVX<}ZDCFX; zB3ZSpWBqa7RO24ix0Yb_Gnl)7Vb-JmH7BY*;LM1Mtou#>$rmUT;IrHuJA8y{;>^@7 z_o8roOx!g4}IG?&`>!Wy0L&Q(#ky0D*v6OI>NX28)`jkT}BVo{=!n~UwMNT~s= zI>%f0f0+|vKK~mPLIZRr<^Mu;cl%B(j_Uf8-O=JY7Id0XxT;k9`sn}9 z#OVy%G}eEmq_K``L}RT(P0*iP5#%)%HdW-~X$tU@prCm71>W8Pbwc3&9qeBrW#g+q z`cWj(Ifzbi@U)s5y!IB1>S7$ew{OSyzz9ip4#rMsN=I=|m2v(3j4P5j3p~^LYLOck z!CcrmP%Lqr7CT=pHgN%cb*X88)!l zWqNb_t$mcPSMO5y0$iOJf}X@?caqmKQ+v^4ybExd=&+ER0p$D_ z-zw;G@oiqr$QFVb+gaUb>p9hT*W&?a%DfoB$k=>`j7?_MGPbeLm@FOuV%{ls^a1cX z53FO~aH~1HAPwvZAm>RXO;5avlulC1FaF{=PM|M9N`a^cXN?%#5TnLd6(cS+hQGHe z(0eh8D14P}9mYX+Vs90s@G6Y@P@)6Z0sFFInfUouf*k`DR!TunVo!D8cS_!>IpL`B z2=K5?6+3`G30ylkre-hxTno{#t{1yvN&}COi_hd2rv@g!crw3GfciR@UnoReAZ$AWW zrtFeVb}JLDs1i1Mf@=`DikMs$+XgXGZKL{=#)nASFZ(2k0lRXpupQs#Y0)O%crW`i zwJ@zL@|tAQK=X9=D>+@VLBGFyp)3*ddkExm99; zhWp@D;!}Nzw;(Za#@wYcL$U&^VCJc{1y1Kng%ocH7lIX{w7^aKOWbE;;tqJ(2oX_k zwt-=?aS|1rDvKeqKx93XmhyPC7(aJyW7Dz`E(k=z*^Er@`3+K^1Z%A(~YZZ{Kcx?E+0SviZlP7SKG3LLyYugbZ0vUBakDyOcr z%BhDRjW4nj_F$0hhN}$9Ss2P6$57r@Wq)yXm0iE8%C1{!U)x$`U%R5(u33tOR~p=} zR$(|g)QLO|u+>Gi)v|4iEgliF6IrTJlfW0q<<(#`IM%ql*r{7(?}H%<{IBg)eiigF z+SEOm$CLGsyRaTtC)bCDRT_k~0QuF4Ut2q=OY|h~s*YHXxU7afo*>h%RBhY35N&(J zC}G+kBB&4OYoQEF(d5EvSZNN;YM)m?t|5>k6_ADbfIu0nIYEJxdo#2Hne6wD5U%Js ztRC{WyNK%4?42mFM3p!Vr3cYIEarYpLHaHsjaHCu&jZQy+Ivet7=!Ygm@dG`K-u)7 zKy(kHll5&_Z~-pH*VV~xI3mIMx7Eqs5zVEuPTflNc7s#bs@`sL>gaR@K)=F=nwDX86s@d+jLyA9VN6NV zxC+Ejspj$F&F(6CwHwX3T>9b&YQd4jn12UqlvC8W!d2gxW{hnc2g8H zh4V8)?0lsFH-X^OZd|J3Nqo|E0Yl@?3_S5&`%M||Y2zue3w11>5-W3niCxm5i-Jp6 z^(tuw80w};dui0Gq>*{UO|x9m=pkEromSEH#Jd_=5y^k-#c*h=(gNjLTc#XQj-eur zyU z3i;cD$fFQJtgB%c-q0_o+C)_rfUpngpq&!oS|kX9imM%^%q7*iY`>AHEwCZ+clMQ zE3d2kyj~9i$I-2GXu&upb`T%14nM2Y`gVs{ZYzyX`1}U-sZ2fqO(b(D9rn}Mk%>I~ zj;oTca`jb6kF@}nh+ed$jE-Z%J`L=6kRL4c%mTE+ZLk!982S+ec`O9Ui(3Tm z`bE$jx#0O*1xlJwZdXvU2=bs1;{)<3{Cf$oM$pKWvzZSw2uOwH!nSzl%SCjP$$}pfZ(p|)EW$e zr6L!=T5ASi(;JXi&HjkwTD-;04>s0oxWms6tS?auMpXvw9jvQhOApqxCUy>`e*}G^ zLvf(&-6oUM`baiZCzBO_5X6SF`TeHN9mql>x8ym3BitV-T<-Qi%ocpc@26-@j1K49G! z*CAimAn(*5Z&y!3i+*vynn=aZR|)^GfVd+UGFc~!pUXd*5Y~hShO&Q<9uozu+evch zQKI8flJo`L9@9X^JoKP_4xo1T)@+ko}&QH@^+vt_@cGe3e%iWUhS z;%IP-HMpdDp0r3kzet)0Em*)@ka*7PAj)s>dp18u)9rLP?^2Z2aL;XNK z$33Q=Cw*5vPy3E~viec#K&70yyYcdO6tNS}*Ay)b%MD3~y!tvb{{nixsqf<`{m@fi zq2M@&Cl~_LR`vo^a>(rN)VJkwk{~y`JL?&JXXDm{#%=NSegHliq&<; zGf=T)65HW(mW3b#25S7NQ3ut434{B@<0tqun%K^{4?B%^{c0Y7f!<^*@n6Y8TJ4$@ zf+g=6fXR8C&Rnw#Dw?Gd+SX+@h|8-vDc7>Wgxz@llb=!8X`& z#EAwZMw{Sp6C__%t;Q|nEJzVy`+p=IIr%b|j7A(n@MUo}T)zl6m(7D;8|=r^CB2pk z`xW=}vtjo#krYJ!YjKxKkWe8qVFS-t8ce_#38~_hFJj95U@_lEPehPpmBGF%b^v&y zWw51?7$~be)ymNN1kJJs&C-iz>C^Ir*#R~O$&}#7suO1l3elMr0vP_KC)MwvR~`hH zwQmRfN*F_!tA3#thCJRCSkm2jv*39l@jOxC`9lPGcoI~yeHU@HnqlssrYaZ&2-=N3 z48K2vzf9<)`7NcVcQ7V(w*C&Rsi1siI{stYt_G&%zbxccA0S%Vx)7Z-k)VqpWI;FD z1vlK_f?e-C#d@+`>~AwgmKqHqF%ufpbER_I|M*10ZH}qyof1 z-Bz8Y`GEqUC1osi=rQU*_Bq1dBO_aU449Z3HgkhBoM+cI~6-~>MhK1*gR6* zSvamwAw%T{_VDB*UQ#H-B(qCHdAz7~_Brg>rr7bSS~T-Q)yz)@*l|k7q}U!*2K*@3 zs-B{FaTj=T2Y7L}UT$zy$mO~nlj?W9FRnXTq0{{Zpwp<(xiWx`n38F?skrBLuhq;& zTNZoB($Z*lskpyA_?~=PF={3nPRJ{75QhE+J14KjPuA)3wK#aJBTJ(+e<`4kZgt)d z#Td!DK(E*38XZp0Ip?=$;tcXh6<8U7f~T$i3|dpKuQ~Q$)iMTG4B2(qQAOX!t}=Em zxl*4kB9Tmc_@l*UjP+4Yg|pfB$Hcbt6JfKt&d_UyZiXSkAI4crWmD-u2NW}=0CRn; zd%rdN7yGeTY8Sd7%T-yWtqe(UJ@Nm%Hhs`+*!QFZY#sXp@EY!BJTSQ0S4xnKn zqsOV+a{f*XcDQnBAMQ1mYnO74Ru$bqbf#WD4{SH4i0`AvBS>ncxr3u|FK?hjH^ob3 z5g(3vlobrOSMdY%EdW38c>q6F0sn9Scvnn@IdCBM-zOywK-c!bv*16}Y2;&Zmr$(Y za(p_89ff3!Gq?!DZ%j?MlQ`&;ZJ1GQKcls;Q@qfD6*Pl82B9S+tJjdUMfXa7N|mED zp3{~XHh#3Ek!w*od1)=-@aOWkp@X*2RCf({8H*apTxbtSRAR=7k#I-06ukvdNA7^a z1<%nvc)DUs0C$i8W2;xYxtz;&B{rh9S&5BKr?#cIBF zG3a>~tRja5^GyZj&({LXBn9TjIbgmIFs!^#b9+8EIZd%iY`fQVbJzl7iW)uQZv*kc zx0B%S1$MRdJ1}2kn91MZM>ArHjH&WRje|VzU6|Oxi=Z$w;?73_4$rkava2}`N_Us@ zDG=OwcC)tr0EDH&cp>HZfgJlprXhz=z{janJ%=d!M0N5I?j7jrrn!Sc9y(gRMt2CQ4DSoh-y@_G}73NuK&@4<2dMoDzluB!q3Vg-C3 zx|#<(UoU`!U`7-6zT~HUgCz8av(ac{WKW7cX)e`hm>hG*Oqnnf14^ogK zBiV;h$RS2BUG!Xz#iHRG6WgMPVa!4XdPKzQ$Yqu}Eeu;r@QIcz6@g(7HzYOV9Ufkxx_%Syc32G69`?0 zIAc3`if?SEQ?s2fHQTe#0)iVos}r{!s?3vA(i-SZa6i#T&GYS{KJd7|542kunooeR zg|Y2rvB&j#2D<8;>PZrh)V_GtHVH`nV`8h(9){avtJxBOt;xB>qp;!R|Hfj)kI!x^ zbFQkqEQg$XI*ZVoldl!nI|VAJwnMs=UDd6m0BNWWQY5)$9)$jY{uz@Le7!+(FRL4{ zG88VL@#E6?2zkXO6&IFyRK~EeLAf^cd2yMb{%NO95Z?<(VlDGBbUAt}zKlC+e?dtt$))nB}oVx8WPAG(R7Y#X(d;Mz3vx=_p zXuZLlPxq?S%T)@lZ|%Be>VpHRUAI&c);`_Mgq?4Wu-~)mnxR&-*3`Ay%A};W9?&4& zor~(G!N!E$>)g>*WJBvl0$@L5&4P(`T?1hezli7*Tss(?g9z%kJ~|hLWu{VXzTw6r z`93<1F-EdV?*^bYl+;H~isPP>IOIFe0>)OiV06V+vMi@=$KW&ezT_KlRh8oH3~@Un z-p1F`ceSNx%gmBO`a64Z zzWF9(bmVWc149X#UantZ_9Yl1C3`Tw21Dm;MvBuP8nwc1R?a=^L2<7H?alIddUgV& za~Kr)s(1wWHc-VIh{AAHvBOhRmtr13AUwm&BQm5<YL=t2;E{`&S=5i(uH%JM>LJdNdK2{r8pzlzgXSz~FNF@l$TUiXdXEGLwW12z< zR1C@D+}0v&oX5vsUy@*h5imzR0g-(KUz!kRc$6z|g0y+lkc%@Gj`?8@YsXyEppJ~T zVVvKAaUMFw)pkoC(&7p{Tm#KFUJ9;;|Hdtp0$?Mx;oZT(NB)8HPdo|)VKhg7+qky_ z#RudC$N@@$PdNa^bM}WE02RHK1A5h4v0b;DZ}HkiQ2-E$LC-!Eys^`;;0BQs_;!ERmGBh8v?NohL(I3Mqn)_(s8AuN|LlwE03vVPiWm6a(HpumviF{wB7H z5tHN|c)MmLu8b(MQuRnB2TYo&BUfv9Y(JG)&Cp+(&7GBH5HK?d1o*jPua)^2f*^RS zi!7kI>6Zqt;mVsn>`Z(8#%scrY}nY!><<`pLoth7MZc}_352_ue&wfHlf z;WHy=AQ>ili82$t<_LvZT2SX@8Ze1!b?Udk?A7cNtH2c@#IcO$QfK5B&LIXXpnimQ z8CTB1nidX8j)fwUO4M#A)+&`^1S?hYkXI?WlMG;x-&E==tkmO}qXXD!DMTT%JRf$; zLfB0QR9DNetPndaFliRlN{+Q*d=V{L>Liv+IOc9e?t4AV){=(gr1-4lOCxA*mzt{U zd)p_7FC?G7A?mvv>NiCQRbNvR-E17nvd?3pHQ~Y;0s1e^SHtE|4GsPOG==yy2k5`P z=t__NOW!yB&kbWo8Ci2E?*+}n9ZezZuq`9pQ6bnh4TYUqb76iAU|Hnjk{=G;7B5dG zUV!dvi$L80b-1?R$eq2oFw_>y{IzY!Q(M_y4^_AtnWzo#B1&ri-Pa?WqKE9w`{ULb z+xDYRz-c8;R5uJ+<5ffp@JMsbHS-v>0+NIY7q0oc4^ue;k`LKCkTrxXCmAApf*{KT z{sziLwoj0e5{5*&6;MK5rcxL4bL?5GLofc8$}L7+_!wxiqK8a{H6aQ}h;Lz%G2udp zq@NHASf5-T%~^S1^gWOHBtq(i*@N>amKy3@jT;yqjyDnuA&T2Vw=(D-2s7b=*f0Hv z-82MZHy}LJLem5>Mz}aA#B@^-lp7PqZapGHO>u?~9(shoq6(A_RG>^1G|kTjysW5p zGSfbeo{eSd=c}+xy%OUzmZ?(^Bxt#17RZQs0A=EIFK0|Wm97Ls3t4vf$wJGFxJ~sGJKB$Rf{NP?$+W|ZJbaBzgY0(roY_FoEK zWDHglM(`bY$obkXTw3wPfx*E`AmjZNzZW3q)kDs^?;!4RfUKwW-IUEBR@D!Hu9s9P z1`)$oi4WSVVQPl^(NcPkkT>jLi?FA1(fbJ|W9(fofC&L433*?Lckl`gOI86jI{`)b zUc8`5pu5;(Wv-_dMfrm7filvr;XW-SOvtd%J=)MV*6g*`)b!dlu)^Acx4m`^bc}5R zqh@1SO-F_G$X4I}=uX~wOEr$MNqRUgo#6_w(}w?1o#96a60C(4rgS(7^njXyN%vBi zl)e_$_BU?T*(PJul-1h&_8!Y=wHbpX>^ z{3Qr2kofLoCUe#BSabVm2aNjR5}+)$(R$zsG=xapeN;H{eBR@@&RjcsZKF`v53c11 zRI(mpOJWt?604vUmjl7pe|E--yL|>=V5*@1B063N!KXn4-9S%*Ao%^LRUe8qa|3S1 zQ@Sl06DY-2Y!#MUZg9U}rPU|Ha9_5J1I%5hCR)r_pI3eL;lkih^=V~&S`WWIkH@4w zU%e3Z=~DH13RU#i2U1E-eOiaC4`muP1$nhssdaGP+K*=KzYbX~So;q`6hLd-}&POYx&Y_h`osU*XtyM=JWmRe&oR_jcBW2$~e+yE!*X@B=q4vTa z_)w%xleFo>C+(DrgtV{0W_&|dk+uxf_DI_mYXS~Ht4Vf;X_kaFVPUK(+|SaWwi_I% zW0Q2=eMr@;_71&^i>1x(N1V5Gis=O^#uwny~mi8c) zhe5@pwO5(6_9~NBUhM=;0E#SofF*=HJYeL1H(+wyhgldLef#+!dy69b0D?TS3q7PL zr@a>d#c2}?u5IYXSG*Hyt4d8mlJD&l^ z2694G+xIIesrdh+ydwFomz*fV$-mY2YN_S9cwc9m)pnh3wmG!{?pyobFpcNuCRv?q8 z_Jm+5i;xoTD<$MK!3y-(3ae#nh4r6Z6~%tLxg6o>=n7$+3qA#EM5TVC9f$+M2)YmD z69HB@u~v7440KM@6E8A75i+iH&b`?`aZLIn3JFnbW|&&bgVb7PsI}CoS&C-2Ynrj4 zXV;`%YBf1E%MG>C)&rES4YeR=G+?k1Y5{J5TA~%l04LAGr`hiyU!b!c@k!9^G)1$k z5ag#>vr8Oz&{mq3Sc4lAAR97-XAmz#zDdN;xj2{3D@o@%uy%;f>q2yvBNqWuw}^s; z_sDhFvYC0a{4KOwsO@wlTHRc1NZ-PRzdF338$fnMtp`4d!i=;dD`qF9bOe2qlnanh zQ|NVZhR?%qifV{EXo|0&i>4@3O|czQimxd|W#ZD@YYmp8*57WVzd>}ioHp@i%hN16 zTX=f+t@hoy-(Q+Le?7^j1NUN1G`;3R2K@liWT-XwgA5TlDTS zY0)1-cfH{X)uR7^FyU`e;_fz@*P<-P_+-~IzMsY^l`W@5{n_%hsLGbpqW)}o#5P@8 zSaJ)v@E=ZoyEm5+3K{e$njypp_k|hZJP;zt2~Wa>nwlY1_N6;$cLadteCkQMkmd{+1xq#1PXN1^)NaI<2C zH!*8_tk5M}uhL!QO(aSj2ZW-OwJMarkX$J@aX5msKR&=I)Q@q_lKg)A3^VA82|}=& z-eMXIVkYGu(LZIOe>x6&r$vxA69=`vN$Z-N#S~{Ky;y55fjcoMjj*=|SF!QJCzdmY zM%DSxSJ2;rI!K{*^NwScd3dMa7+}E+{GePp2=I_%VJ$3FbKSMV34!mtQWR}7x_UhI zia1k?^W-?R{UN|a@W@IDj`FC#Ih%@YG>Q7KiW+@_JZGCESL2X;bo8wVlrqf~dpOa8 zGv2VolCotHV9v8ocIyLe(cm__C;1wzfv`TQ!Nqms$=;cfydVS=>h+0S2Z2WfIj6ha+D;3 zd4HeMrVxbIazB8n51r($kE4_HVwQjo=bH!;(yODlkj{I-oF4*Hx8Sz}?}7D>kNEKa zfTKvY|4?iQsbBG6z}^r3Akbb1q*xvNuuRZ?C1;fL-F*@{o<;DqDuvDqF4s zwq+WEM9$<+vPPsq$8gBsIizr#Po!OWQEb|A8cM0lj@ z5|bk@u|aFTo4riPWu=Zq2t30|L%93VO{cl(=JOUDP7wOq48B4sIp1!sTQC$tX+$VV z!*4o3js{cgA~P?(zLr0 zl82J3&>lrg^pF=Feb)!2eaDTK=Nuery1D}g?Jzc;*-??kI?QAxUsuR&+-w-Hg}#oj zye)JNBQi%0&D`VIor0Xr87;SNB)^rxISeFc3Lr%s;GjCe<|ydF6&)&A9_scbR`Y(T zCX(xL)*)T=0mY+U6_zn`m>p8ry5;5RWj+di>KH}AUytE4hk^=aKL|s~yj1%=`T8nI z5$}T|#smLcs#PP@$|#Ot3d0d&S=-u-Jo0hGjZ%;3xObwt^_g#zBXm~QW4?XvXTszh zo+G|Ka_G8=ZDf!mq9`P{Zs#G?$|R+Qm?95Hl&D~NggL_H{;x|NqvMXwTh}gt)%jIj z%P$Sr^=6hb1nUqnf4k4bcd+vv#H@;tan14!vJOa%8(%^o49WAdP8(V0#G;|eyHV&> z0hsP!QjCvW@+#K3Ly|LvBmE6m@o57(xnxY=OT`*JBm`AMM|AXAsExWwG&=eOdB<=P zx6bUbdwBf};2|q(V#6pUG~VBh;JlUl1S6(%c`5t>)b!XM35)9a*B8E z6#z_;hj--4tJ;h_^74+U>Zfs@!&LQbc~@2KhQ86wuc~@~xT;@a**UB;$Hi-S*6D=! z2l;gzp9-5fo6WfGtYy6l<;Fi=FQIIj?V=@lDZ7?z^Vea7kYz5dUACbCd@f}b+f++( zrZ6MU0lb48^6-r~UJxk+;etjY9N4{)`Fr@vi}clupgcAdJM`xwO{4r=q!l~NmE_87 zKWB2Gg+Gv$N0=SFa8rq#hW;jS&24CC<-ox#F>gcXMj80|Tk$;rGP3q%lPG6Q9eoO9 z?N4I@hOGVPiCWfM25_28uggM&?26VAh$@ag|EIJn~A z;NaWXgZMEDqP>Ckho+Wc_kjy3sG<=e@^i_7VPWK^qvVNY8YIyBFilG64yKRU#yA0 z)>GEi9mqwe?{m1FE~kO<0_R`+(yLZ|eki#YwjI91LpVAkJ2lRohiev$<3?N=Va2~_ zJk5e}o>C42_3EQU-pQX1NftccBRd{uC#rc07%WTDV+l$PLYa2UG8W<7HA%MjFxG1R z5ByczC=B3RS^QKh^Z7t9?2K`3Ks!oB$=J7Q+l6SSMxArRlDv)hU_pn-p6c3IdvyWQ z!6!A;m9V((!}&REWr(?T4V+XPTWdmceYuqV+r7iIs;#uv9Pcn91EN9^tV0)YA5imG zslPq-c{FbqOd9IxR%T;GW|s0{t(gg(&1Rl#LUo0Sq^Ynzmk+VMIbQOxooNQtMi3Gy z-u@(cC_1BL4;&cGI3r|ngR zlP8dt{9xBTu0F^}HeC{Pe=u+cZ8h8j0DwMrwhG!vg44&&Rx*Q2CFLl7-yr;USnE2& zXU#GnMb$G?|MNr)xzDR1_r22$8Bsjgew8^PwbFWEJp>u>qLWy4dbb^G#epwaHQ@vr z4K5O`#td3?#t(5YfrT~?h|#x|V&fjL@oLqa@YV%C9D}$%DVgQrv;~-M>MZ%<=v>ep~q?naqr zmstasMTpixrD2(z?9htu0B|oj035+u-yKe^g9E7zDvd;CS}rQzMLlok$tV~($FM`6 z4-qdo0Gj*x-sXWz6E8TNTI<^bXd|@_4x~0{*AQ)L%0m=<)-(_7Od4S6oF8#7H~<{M z`4IPl!>RKjj@0=ON3h->2vpMx4!}0mJdM?4Q-rFySXC1Wdz|RG2Z_356Aqz}l@{V# zPV`(VpNuXH?a`S=k-Yv$KNgZlWK2TLKE^*%f_paPt0qW?n?0^+kbxj9wIa35`y26n zJY=Gk_+10JC=zLy9*LAzMj{LF>!?6Fd^7By`K1AaW{VAgLwJim9f{Cd;+~5ZAN%ly z--{hP{kIFV*jS7po^cI`>&1Hoey#Yi%ehW847<7eU-R?0Bs>G0)Siae2vQ2))5NEFXrq+vZ* zF`Vx@t-!&%35!hs&Gu$~>#)dlY*FYiq#ayziLT3Wul)41Y158cJpHGaTtDrK_Dcab z5I_CIvl3;DV;aVTHRK;)>wmp01ONI%&t85#izaV#b5vMo^PD__2q9o`0*d#_PCPT_ro8FubG~> zdTn&x*HSlq_IuZ!cTs=wCuaS1%JV;YGgENYF(bAJ0IJ4;O(Z#cP@Q= z$$gzytXp{3mAjuSyk=iZ&2JvMb=QO&PG9-6oe#hI(Mz8A>Gi)l>GMa<{p5R3|HmnR zOdkDM?Q56+`TzI&|7Lp$c&%ajSsVIb00RDYe~JU~{j>^mznKPM=AXp-zY))Wge6ZM=YEI7 zO}u_e9;7kp4UE7yhArM;#p*Rd95~|9v>`f^+U4d*-E=j6Ujw zqauSf5okfVKPvxb<6kM_N^5VbyXEH6TfTNj>CLx%?ao`6VkC66(J{wFijN$1#8D%U zE-EP;J>mleP<#3QLHvq9FBch!ACgBPAV!Mu!#Xd*MKCvKWCe{U%Y`mJ!i6I@Hz(lt z5&W>GkDP-a><%Irq$8ihuNFVbR!RIG!|xaP{RO`f264O}&Oavi|3={3|0~3||Hr!c zf2^1PhtI%2!X`YzFmxadSbx@=b><@EWc;S!SBc;C_%-6!i63`K8}TaukOBZH0FVL@ zvH(OZz+PrS6hCa_7L?*Q8NUkr=0%452T)R9Q%6%bQzugwwv}lw(`KgKOxv0EV;gc? zl|R-=^bC0ZzxY=$qKK#m{!RYEch4U;VZsF;@44lIaTC6K!GFE8^@8vI^okQbd*R&$Wgp#>EW7^Y2gTQMP+vk;(Z~gwb@*PzZ%1@tudiggWJg5AkiVMrn`|OPJ@2{Ix ze)Tuzl`sDOSIQ@yeOLL>M92Ut2!+ z$D7IrU-@PEz^rG=uX|@_`Dc3mT>jsG>?^jz4bN_OG8f?SKDq^0fMgJ~l0J>Bpzt^^tR?y*2jyX}|f%^l1e%W78h|zs$V} zd=yps{##*pBXLAT1!-jwgh0Y(6w*l`fq(=e5J3Suourerbkc2ihfTo7fF=eoDhQ6~ zLE6fJq>l^K zq>r+%OaG)#efqr48`H1*VRQQX-L|H$wl$;|P1~0KL-qFb*)Q)%KRo!6^eHz#n(jF1 z$@E>Do=Lwn<@xkS-r1M_x6KFAvr1k~|1|T>^p+9tq~Dp`l77d8kJ3M0@M-$04PT_s zZ9bOXdEj^Hi)(&LKl|EFcE`l7_Vqn`*qtAoXg_DqDfW!tCE2IlcA7n7LvMS(o6fY~ zv!$>7)Cc?9cf5F>{qs);*%$U1YJYUbaQpZTBkd2oIm$kH$T)k?>Wl1MKAB)2JSWp$ z_2)_UFQ-ni|N6CQ_CJ)&u#Y!p*^h23u%ABra{B`(F0^}IDzv}1sl@)GyWD>E6pwwt z2%r6qbAtBjK1=QW`mV4))+=NmXS>c`pR&gOe9rauW=DFq59(&tfyz(8pcj~+LC(e4$Ui{?;cF)Tn+jsu{uzmif zBle=zU)cZT|H@wJ{$v^wvj5r>Du1+(dD_V6Hn~&AgRgeZ_|efdqtln&GWMzG-!B6%{R#zoBupA zW6RyC8J=rKXPi54Y{nB8UYK#-Sr=uj`sw0~-JeXzIPjW1<1bB_8G9d@m{E6cc1F(D z$r)d5%FS4P%e0Ixw@gQQGcuZQ&(ApPo>>|59-5O;^VDS-4<4A8@mk9j8Si|%Amh-f zj*LSioEb-E6lZ*JwJYNvo69oZX>w;AII<{X&)Jn3Pv-eD9=pz;@z|5WjQjt+IOCDg z%Q9XLUXyWf*Gf5OX84PYVrS*~L0hTU=c+VD`2DVcF@I2Cp>38c;H~l(yKJRykIPo# zbp_0`S+Tb==yX@w+!f9;Bs+snV}!4=%otJTE;UA!m-sdJRMRb4OTGRIXVA z7+Ik;=FiEQXPcUB8{}SS%Xj*n6|SJmAGjDc8aN!VRk(eD;a1E+?lw6JD%m?hmSI+~ z)bFjZT{bH#&o*RAe!);aaB(8dpE>7Z zYhc=v?bgSRgUjzK_Lfy*WRw__{9YdhPI1s#S%%|siMu3NZu3?JZQfE_k+-U{1bZGm zSM2nlI>jP3B{DqP=Ph@+%gT{4US`#pxwV%g8ZFU%E{tZgnASSA324mLS)|n+zsjw( z?U3KjqjY#deYN@vjRt^CD()mm`$+`qhZIeKjzlh|kIyiy#NrN(U8DW%Thpw};H zk%K&9tYW0L&K4!^V7beW-Cj`HI(cfM8xu&8&liwU0}dT-Gw0OQaWHH+Qa#=!F2Ak9 zTY`x@oVV@J!cpP$$b_`a);8O4TWcA5$d%*Z!W3q6m6l@cMX3%(+e}Q2Q>NS8m6(qz zogPj=GIpd&LuL(fPZ{K%ILMtP^YGNl(l+zb46jUE6;3qBx!CFUIEyg4WyYB^YwGl= zGjg(Kg=Ydx$|wQtHv+*Tx5FV5n!{OH;_!I`L7(3%lfEMj=M!UOK>$$Q2D z{xX-5I&##=F(cDPrjARNv!LupQ(7F3EwOBv=*zt&rboLVGR5q5j}zx>%2JYbIyT#5 zl)C+x(&Tc~tcbf3^R~OhmOp(?juD(SW46s%iax+;C2Nk_MRMYHsX$t1ip*+@dI`oQ z#ttS-1B1ehf}`GBTH&fN%nvf4#bpN6-K6I)2f9i7*x`3B5wWAvhJFns+uapq_`G6; z%t&n$hovG`(B`W2R+W|OIVfOQZP30jB)54CJBpSCG3FzqdHj1S#scFFbESu4IkEpFySH@65a}CKO>;RUgCi&>g`q=7{;Xtv%EF;TS%|Fe+-P8w z^4q)qS4(I8%UnUL4d#5Ta}?%dIfvQI&fw?&H%e#kVRG}imV4bLhPf~_N1wItIVZ>j zXlb@)D++}jDfok|K7&>G~`xGq+GkfbyG1NAU z6=;)emO509Br7_r19{Yn{f}!Q>lV&dt#yb<{GZo=1FiKKF7{%T<}P--DzSX2^5G%| z3lJO)4i9EAhpq~e(Rz$aEDD%_JvRhvh@r(Uw_IGsaJ9mIj5YPe>ZEoRYuiiWZ0#m@<#1b@0?nRcft7Nx?2+THwbeKqwT>q3 zKbzT?r8L_1qMjqMB=`DShaSUM;q_#hqB3J^2cw3%%!nAK;WRW)CNK@E zhj!%gBd2|g3f!8|lP^Y_bRD;EW63f4xECAcfGh;b~z(G;2b^X2|8M2Q$tdIHoMIGiOV4x9vn z%N&vWQ}*RDtRKVECQb?^uBDPQvgVP3A{RPIW!A2XwkKK#xp6M5AVX9yBDkB{k5KBu z;lfLZ@NT7orxk0|TJ?xLK4O#~{}2fu>sDk;gst;XIPrgekaTQPME%S=!r9rg^=5F} zyKs6#RGfP6Gb{_=GY+_16*k=O!W}iIO)ot4ss_h#o`~CB?Oh$)mo z#NEY+#E7~@q?%V-){Sc2C8pO*H+QKl7fRh_Rp!Z1Z<&WLSzEudw7$TU?__0@?`Yd^ zu{83Xto&Ht-&)`6S}`ntG>w$eml6_B z`hCK&lQt#1baE(R(bI(0wQ-YM-@{W{G(Eum9sufqwY zr~ftKir!5L*=IbQFtAT*=O6q0*y*;jUh8yv--kM_>bJhr>*x47on^bM)2wqdJFPr# zQkUNh__1@-puL@+J^z-@cMmP=eATe5&i#`6cYbDs(K#=rvFod;1zop~>E3nLg)ek@ z*7Jt*@ow93t6nOgd*yww@dqdFEedW>t-AAv`y@X>-9(0IusOf*P zFbsLPFq%JK^BGsi@Hf++9K&xuQ~_Us9-!7?s%rc$l!q;_9Z+=er^tbfP5x9JwhsP$ zc{l?bpTX$hFQi|duff*AAEICW%StqV1O2zh@Mp?HA=u=Z9c&%q`{Hj*G zUmiBWHdfIgelz{$>gnLmWXHscpNapN7c>fhe+ z&@dhPCm+u`$;Jb@gTI;nxhm`6PdQT^vt#({>G#F(W0E#E`O^{DI>Zmr&uVn=H~fsh ziGG_IzGM8BpYfXy&LMA>mfWHIeEc^J*yW>NemrU>TL*uV{D}o@)6~)xI1H!D#;aA?lYu;2F)|GF1J8 zV)&CdvCIC6mOp>E=6^DVKWT*e-;3clIIv>*kEUvV`Cq%y%5NF1{-PM|&mX7$FJk1+ zOjG|XSx`qAe+?7V{{nDsl&4L7TsW{BP)ggaf&PAap6}pq%2xexS;$8zziEp4Yh(EH zr>S4|AGQwhLzk%E9mAiQr~XBV?@W+CB-M6no~ia%ijMw#bvzowUw^4OSWJifE%ax` z$Zwmaj#%@1i2gfb?7vKA{47TNlzHm7Acnt?{>3r;E%b+Uoz|g!A*W^>6l4E2a$&GC zhCiiL^Y@71&n#E}FfF-5`98P$?}*_~TBQE;82y*;RsUZU9pc+~;*`HvfUSeSFrXQq ziBW$WJN9vvb;#dB{~a;>p(X0*7NdRjOVuB1{e5(q`sc;SpMQ<|YfmxRv3@n`zcWVu z(2eT1DLUkDpuagr|M@m(M*07J*gE8ItXKbcG0JbeY`&;hP{IS+A#&6XBZH)LycdP#+g{t(k{=P?XWek5I{d;2g zQ+}(C+!+24{b$AK--dfNqjY0}`Sicq*6&O%942Z)hx*skA8Y<6r+AE^gkcN-}r<&PKZ&zrl-_jlw`6)`6;|H(5G8;f8%SKU;d5~whsAy ze^Y;~_BGPKUu7NghyJdP3uE}3=#O>(#CS(D&ezBt;ujuN|9^4*i8lTV-&6m!G4i*( zul{Rd_zOQ&|HK&m-}tfm{~9BI{UP-~(kJ@y(U71S9V$~pKkIM)2c_F$_#5cIHiqBE zC0S7ne?9&782)DZ3u5?Fx@eW>#PHYCAM5ySqJLP7{732kCYGOJH&P3us8A^oxDhkE)i)SMmiH;>h%`7z?B$X_+b#>?~$`F%g*Z=~O5Mv2mY z^q(5Tf0X`HwB!!u8)=#pYyAc%z7GwOUWN1iF41YtG`a8w&H%?Ojdok+Ykgfif7~>mns5Nu;jg_DN z+!+3&^v5c{Wva#x#i)PbboCF8G5^-fs~E7wy1&#!|Ed`E%e++cpN8WXn;NP$fBP=i zq^D!7uk(x5Z__*-^V9!kjQd-Ki!=*|S%>@$9!)wWM)^%u>gR314*8A6nlwE|{qpHw z8pGdAf4PR~5I=vZCh<0G2Y-nE$+6JuzZ%0urw(l>E!M`>Jf4v+9StQ%W(X$7;OCh z6<<{JOuD|)q*L^AMRl@v*q^F8UPnaLc_bcnSL3s}MTsZ3G}1>4!TC_*2jsrQ{qkd`T8A{c+|x!SNbC>Blt~&dC64ZO=+da;_u5hG_dRrl*&2`Q@2I+gSQ`z=QQdgV zndTPdJTo1-%*m>2p)A^YD+t|j>f+7!TcJDp3v_#-J49V|oN|vqmp?`8_i7wnFRV3t z9Nh%yeAL|+M^^&faq70m(8>CE9dx0oS}t!}wC<1m>h9~ht?#;_%T1WobUnRW z%Acls`TpG8to;&2e+2r5>8j^tN8I>*v8HXxQ#~*9iPYCYyUI5==MVQ_LZu8f$8DnZd!Gh4Hz+^I|5zEp*k6F=4Oo-nxgA< zl3~u4$3#I*hl7`t5{nzeja^E+A^W zgU}VqTa>WL^8w~&wRdW@c`QkLyPS-8KGl6iS-Agbi*7h{4OgpjTg=Qpe{BqSo&ibh%5kexJoDw=Wj=NlR6CK^$E+bbY8> z97pGY&PN@eH;7uljnEwmX}NsvAgXRRbVud2X4v@rK~&v`(B-aG9iKypsyn$S&aXG9 zj<*e?>c&8qR--!J7muo209|9P>iB#@RNWfr_ODkRpHqmc+X0<#gX;LaLR8)B(AC_m zIzG1$Rrft~wvDQLJkEX_m}nTgsJkPMZaQ=+n=~H3_J~?;5V}6MsV?4i>sILUH>+-5 z`}vafkmGVMbTwO4$LAcPmU{%cqxY(g-?v27^}=_V<-b#%ElztUKvzf|pMQuNuLQat z^2hkG@i~a7x^>Xm9#Y+RaoW2Ry5qn9dEG(inj2Ne=Odz)+XXj=xBpRfyxkd9HypaA zovP#4I#G3VB;KQ{<8u>Hbt|B=J+3-FKM_^84Z5@^RTpm^eE_-?>i9fG)Og3B>$6+q zeH3T^_Qm3~g}N)_=(3^f^R&j>6G!KPu8F$bIJ%9{9iooUT|{liZmHk1TJDzi@p7uo zb)p;}A3`^;Np%z3>u8Jaf-H>1rhQ1{Z4B;rnIh0)WL@jqZbj>eoxqO}@ zsxAm!k7m^^iBs-Y=nAPD7e}{O>PH=)^N3pR5$KLm_k5gqy-qibEw5_*_}oX-coU!t z{Z(~*{v)cc1iJknsE*HpMAfZ>&i1M5_&i8d-A?Fs9aUYtemMwTGj;ppw6{xd^xu~n z@4`5`;n3An7w>TYAWXzTIa(6vy<=TD->`w+UcK3Z;3oOmar?jh>zadcy#+d^GI9Nhxw znyH%;N4EyL9%pL(;>}k(pi81|Se$sTL)VA8Z{p~_hwdnK55>_9JQK&qSz5nEadgw6 zYoadR`YH%rZeNYJE>66y&^1yQ@A%yd-MoGp@47hgj!6BebCgl@|KjVI5=m|K*2;~;c~ykQa> zpO1;!-Yz(a_ZY4^J|`1ZHypa=5vt2(vC)ppInW)aZhIWv3g|*3H6EXziCXS9=*m-6 zR~9GU0q7d3i+leYx*n+-kI&UaEw?Ye01Q#b#}K0GvZ31|Z@t5|I!^sO&>8ZsO>FVz zmyOW%p^nepL@jqWbd6&*-otUq{SdmeajMIUqdU1D)*IAySg$dkjK49^ZMjh6#XH^> zKxd?>j?d?GXvc6!)X|7dLL^i^h+nHegNgs#^FKeLe#~Z zFT0$B^(=LKj;BLCrQO4!Ysl7e=f^2`4s>r*HzAI01$0M$fo>agJ#w^MTby_Ypfjk$ zC5~=ZKhl(T9E0vS%jI)FQQOa3KX_K{ng>iHq=zP>+38Gt+`fY@+ zoVvqtbi1KTnWE*!i}xXPL#X>SPP~(C*dNsKd7-HNG6uT0bG6)f=gkGs6;4$hpC5`E zZw++YFHs$zBZ{iqA@$2s9iJzPs(W4PH&b=*8Qh}u^Y_p-a#>6QDB|Xgofj6t&zE=z5f>j?XDY)vbfBNnU7#%@(KJozU%~j?XPc zjdu{bP?g5x^Gi{6T`-AmS*$uf#}rjJ9J=~zRhJs4esiGPPTll4x)snhQ@1pZZX0w% zLRxOT=Nk?{7m~M$VH*@D-ZAKEsGA%|*B6szBXxZKDQdrDL$_s}mb)NMJP&lu)Ww@O zHbOUVy~f)RC*E%8nyBORQBmvnA#~+8X}oyXQzxU-TBzgmQXS%z*CrTu7)J7mV6Oxt zxhsgTRZssUq`UGPuxE#D2oU=B; z7y*9<*ctIhft|n$$kWL0@$itO-wEP7*nT&HSabGU1^y27kq-JVCHsMruRHk!o?|-$ z<=qALNifnkgVMfRKxyCg5r_^^!q{4-wjH5gR)QfJle5SL73!Z0ivJQan>-VgaeV;KgWd_Q1$(1CPEh(S6_oZ3 z2PMCaJd=F#D)m1KivND{9@61f{}rJ4XOL6K(U=$|{s>U~=aFZV7nZ4i6e#||WPh@( zRQ*Mu_%9=8lG|MB{|zYqTgi1~9{strCy-;wZ%Q=(m!RbThQ)`5p+D(?ZWfqe@o{w_>kIYa$jL22jl zJgwK)pw#OVvW0vG6x}1B)PD!l8_3(q04TbCpw#28>015L7oBDLjO#L>Ye~a_Yip> zSq(~glR)YJ383`PS>R1bKWa}fuy#z|56bcIAb2BK2}*k=fkE*5bj|-hhN39H1`uI`m30}km+`&Ur2i}C~=+`ulXJ! z?jQ400qW@%qp{ev!tz zo4lR8nY@;qK~5&^WPi}CAMHbF8t)nMH=y`yXcv<6$V)&OkCQOa z2_GbvgA%tKl>Eh@D{@tL& zxek=^;AMId({%9s20i`~- zkO5HoZw~p=NIg&A21@xigA#u&xr)4){;{-&lIM|s8=?7M2POZ0au3;+ep#f8|5&o} zGx8}=%72XZ1LSYXsq|;lP9syvF7*F2T;qOC9w9e_%P|fvAqRrE7n3}0nD*NcP|6``|k2bZ{E%e-2dLpTS(%kAu>l zYe4Z&q(7Pd)961Lya;hW9iaK20C7rA-U&+n8$j_F(tioq8}>8jY5ChgKkPhE>e&;t zgSVZl{dzMfan_Qn$Y*T{h8w!|;ML#&unctePcVGo98mV#Oi=PqA}5efoReUj0NqYd z{C9yE`pILNp2GA;`z08q(ESdSc=v#!zm2?!Jf&}fQ4ZZfOfnMpEl_m72OY5Q0xL1j zt_8i|Qrd1%^d+F^^T9>1$AFS=An1YqKW8Nv72sE(*f)Yw-j$%_zZ{hOX`tlq4$6N1 z`LR4A?bTTN#6`gJywI#{uNC3k#2GvD7r6DsO0|? zl>9G)l3vdAVx~_3rJnyrp;E8kfmfkj4WQ@)QW^Z4M0+TC3iy3>WO1z!J~{ zN;g6L>M=TnEkv=Ydy%qsT;ZZ&#gPHjyj9h0ygSlbG)A zqH%ITiE|n#_54@o1Y-f%1(b5$?WF#v$jKlMrQ~tsVDhsB&A$h{9QjuKgy-6!TLMZy zEFw$D(~cX)RP^_C-{9V>lygjJ`%?3r4NAU5vIlwFQPn;7g>vxc5TTsxBWid4mto9B z+=uYRla#+5lsH?-P2@sQ_U}B}-yT-`D^T>0(SC&Xtzahft3ZjnjOi6*DOr37-_e7*pnfMP{sM9a`SE+|e-9M@8{{kG zTu|nXp`aZ1&$MX0mV?q?h5uCh5^xskmGZ7(T!wxdO!gs9Bn_|t{%`)F{1@3mz6s8O z{{Xp%e2m-y&W8UUax=M(ECZ!~$AMCxRR^`+XMO@8^dw(~Vm`uk;2`fCsQB-s_b6#2HjrM!rI`%Sg|f7Sh20ZRT-Q1id${WcG$U_IT9v^^`{~##!*b7Sk zJq$|x2k5_x+)SPW%DDLQCGFpTf>V(1ui#|xG4KTN5pX8<*B#_q(o0@Wjs`_P0+jlE z|7WewL*NXg+rd2WEJ?>a`O%*YV>;{y!Arn-;54v)zvi0*Vv0z9exJsD29&s~XfLBZ ziME~g2yg=Oef*;4dk^f6d@q10Xz#->X!--7q+dgOG40d9sc7%Xpp2(S_bN-l6JR?* z$v1}fNZRi|uj6q$D7xQ*qPv#%a@qrF_ow~e=T!djIwJ-6N5M&8Z*U@b>H8no^yfiIzaPw!c@MP1?*gTq!C)u&lgPIoQ~NLEjbxC#7?gF24Lk?& zdV&4HZywcrpOYa__Rlq-lph48yvxB%q@NAS@&B)#+U{3D@!trh!@v8FTF>R6#Hj)$ zP9-S1B69B^)c-6f{#~H>caUCC+B=Q>_z~5=2a5jhpy(e1GoZVc{^j%s=r1EL1SQ@X zw7+fC`o0ZH`Xcf&GK)O;uOZty_g6J2^;rcw*eHho^ zL*O9L58_ffIT=J%lmB_IVXix0C+oqn@YjL3rI~y^cp?XU;vEJ`HCai1(4hK1kq?ub$Pl>*#3f>cYty{-vqvb_AR6R>7ClXUEsO!H-P7ZUu?zs z7CZ<_y~;sc$|a|h-N0e6-?~HT1||MNP~yM&YmNH~`6BrY_zwJj+E-+ygbL+kS(_ zZy+xsQ^|L)SO1%&k1Qv9lRe2ltyTRVawvH&*|bLeyU22~kTl5S)vCLnyqk28bIDh( zQ{9WCgPcotA-`X(y4%PNu8S#Wn7$3 zo(;f+T=Yi6WQDhR>1p9T5 zmisg)iu@Rq`aKIuKW_u2eown~ z|Na(~`Z+;q*F172DEWqflJ68y^1WM*XHcQL5tMP|10_FR6m9N@^FgUsZ&31|2uj=! z%Gf`k#Muf;dJj;a|1XM=~ZASq*s9W3Ltp_cmX(*=~HNr0!43QdLK~q-Rb|XSmS&JO8yp5`r|fG z+WC2r)^|FYLiPb=e}3lFdVUN_J@?UWqCJE56x!oJX=iyM`^|ytKG=_wA#y4?3hacq zgUL6q)O>bO@^vSh7pnaPDEf!Ug`n)8yB8=^K*{%?`N|JK(LYOjJMFDxJ}CL$xy{_o|g`!EK{~+Mw;6>m!9@eqvW0Bjiisfg0z!^ z$$#eQ_0Aqp%6klyxOaf(!QKE${bnQqf_-p(S_VozJAo4C!^v8&mqD>_ASZ%SZW`DfafZ`Ak9Kd`-{q+PFev(WXe&mFe*Pp|>-8!q<*Wsze$P+R{J#UG-|he=|9&t9Ssw;_BHw*XUj~judLh&2GJP~S0_pvj-izryKsnAozF5nD2bA)6 zfU+Nd3w{Ux7VtQ@n07fR<6s^r`dm=zkwN?6i!}c|;Md4^4Ji7Bpy=~J(Pz^hLwgwQ z{vf`pP3{d!znsMM_tOmHFNpU5h_6tSZv!RH^`P|grJ%$g3JyV%eViUYJwZ8sx`UEl zJVxzlU?=FG9j)nCj8glhRJA9glg0lII#u#rhE5dwShCu;4Oe?CDE=wK)c)cEwNC>@ z|MXC`pMps2GEl}rfn>tJ=g-%1yaPn2hv$&Z4kfK^PN1&VGM?SY`^I)kTyFAUK98^IG`-vo9?Jp&+$PM!*)=;TvCiSzgK zRR33S5bRw-_&0+mf-AwnNS^^pzn=}tcuE96hX1Q`wVcmDDd#P)2hyLSy%j{&`mF#_ zWIqomhjz<3s#^t$|1wbg zgK75yCEj!WR5uHhc;|qk?*{$|dtYCSbI=LOyp#?~oKry2{r7B*b3Z8c9}h~Lo}l=@ zJ4^3V9|Aj}U;YlF=zjZY{{ci%{cZsfvfpx0;?D*p|8%f7;$?!e|4(Q7_h+i^4N!Ei zfTDX2l>K!t(*vOFr!w$Ur00UNU&e#7pUwhN)#RQaLML}+`msKmeh8HGcR>@ zgHrCVK`D0wDC5q>^vR&;`qAzUo(})#XK4K%1tot7l==n0U$Dx z`CAea_a#vB?*%39R#5t0nlt8)3ZU*olUzJC~=QKB=xu#l=@uNPcJ4Hki9@D?KFmw*!A2VzSuCNCr3Mn7GTp&;*- zt^xPcZUPaj=Puff;9A(*!8Kq5SPgCguLJAB)nE-60&QsDXs{1B3QPi1!Awlns82T= zDU-L@EttH8O=JTZA`8h((ncC&3npPRKiNQr$U-ucw2=ncf=SxUPd1PtvXIOqZKOfA zU~)9`lMQ5uEF?2Y8)=X&m`u(5WCIx@3&~88qA(=_qNP}#_$;r%5Hjp8*kjx})q(Qded}Zb*8^{n@NM@2Y(jZ%K-ZJx( z4P=NcBr{1HX^<^A&zbqj1~Nnzl9{B9G{_d57tQ=+0~sO<$xPBl8e|L3pJsltfeev_ zWF~1N4YCFEzL}qt^MlwSvXIOqZKOfA=y|qV6WKt9$U-ucw2=ncg7b@6J}Kv8vwX6U z%p`53LAL05wObR}K!(UdGLy8C2HAqb%<{b`_~c=b{g$X7{?M%jt|*hm;A7Ov=cB-id~Q6O}2;8Z)W+lAHaSz%V&AF ziY@VwPqsCTZ@oYCQJnWo|916%#r9b52W@72nXhEK0OwiJTkqdH5%m%~3G=UP>(Lgm zt@msCSzZ#_Dcc!VeNnD#!`PqJ`$A=1DEY1T_swN}toQZZgn8DCkB1m!8;tXo*z)C= zY@MY&=(BqEe@~p3#NJ4IIr>TLEwsyMZ>3#=^RUFr$9hP%6J-Cx_R;P`+j>9XeD1#q z+<&QubHg)-CNt z=qCEl=l-=lsQSIkZ@n)z&1%o1j7K~4xY~Vi9+G&CPpJI>+iSg#@>aIzXjg5I+)og_ z^}fk{te^G%(o0w$>wS~=vwfMnG=3+nJ0-vMzRfSJcnKPRsniGKWfza9t9blb?|)6@ zc(va5`YGdE?|1!z`^S2p>zUU6{+pKnZyBE`%6ebx$F!~Yv;INKL-|cCzd!xf`&SRJ zyu$Z1o>W`nwY;zPOFUk}?^DHbEdIui)&G$kzlh(=__*dY{nqR~ahi}pR+vIqZkDb((`yFC8(B4Da zdcW#Q+SdD2-=>|?Mf1n-+p=ZT3f#St!0sXZhCqIoFGg`Zlt@&u~0i z@8^73_6PjUf7JMOXp4ku!Iwj_4QD*-eVkjlzvSXxHu?M6qPO0+IfnJO-mh7~`dRPO zl=~CXUq{(rTR0x9_hmL&=c`*a{_~O_`Xt&9S^kacf5h_B?!^6Vy`S@Q*57*H=1ydj z`daV5bV_|-Tkn%hWB*w1kNgYsTknfZ;`zvWKja+i_`ySZvaO0u-+Fr z&DuX{8ZX58AVmA1b$+7#HqR&4`yQt-zV&{`qwFv1eU2CKd}_VF@oU!KdSBu{Ile;p zvPibgoZlK~XHnmft^T*zUh92_XVbRcZ+IX3+j^hjE6i`bpYTE2*82$W;e2MjpRSSd ztoPALsnUPe`vdE&@^8@k3}<_-_ahEveCvIN+1%gO`wOqP{KcBTgz>ER4<2QITkrEb zmHOtTs^87}TJIwq#QwM5Klq*WANn-J{lA6tL;hmTKZxzI-Y0k`lFji!zr5=}Z0mi1 z*D$~J{=W;jUa;QxceU(a)ZrNCi)~VW*hgtEm*Wq%AqN_^w-6uSM;Y?Rf@E8P&tezS z_CYIl=(p&-CA+{vMc*#ctfJ_UY&^v2BahE@J-1Thx94 z^*8k!)t39}rd_XgjaA=Yt9>W!qg&KogyU26EqAH?8}yIZp;>C*L_2e?+HbJDkW=mV zFkVIP+o1M^*neU-+^F_TI3CS-w6CPUrAGZX&@K$9{W)OjFHu|muAJB@rD|Wv{>Z;Z z?GND-f6^kgf1usM{+dZUv_$=zSpTET)P9b3{Zh53ustpF)b7mw$}CrVHv8A-R{Lbu zKi{jim*v@fYTK!AELQspoFAmVnQ3a*QJ+6e?GVRL!vwXzpg%KD?VcE)lE3~^wXdVy zJX7rp8NWGS?R_|wL|@4EOlSYeAN!H*LY9|wx7vBk?@L!(?(a)}8^=Ql%WGlzqiClv z{@plU%<{0`WZOVnEv(xt8}*RwRoW@2hiq4Hyw#tp_Fq}Qe9Tj_y+MBy)`_yUaD27U zcCr3)UqZIKn7@(n{=xBHI8gl;Fn{KGYA*n!{*43Fo@R|d)Kj)S%rEyxWjl@e>*=3_ zG|8Wj{Vv-P);C1`x70V#euBq)1M7P^`=b&4D%)`GzYykG+3vxQ86WeiY`>zv9_^N` zz^V_%wQO08C-4WN)UKvp9-@%#RMgX~|2Va;;PKxwTJ5K(Pa2_i4fdnxlLo2%8>{@`YRmVL z;%^zM_F|5|q+x0=!TccIYi*-&JVn~PPiDD|XOTbBUkD@8u0nkx?VdP4N7@g!%l`z% zf299}liJ#6w6k;3ACdYl*w2yna~N-t_BH5_NPA+t{L8U_BK@Iu?U(QSBK>l$9%>URFC+V#hOuxBIn zU$u+B1p_?c&XA*WMr6`JL_d&$4!Q7Uq@6@@BWQC$-z(^DrMo>i^Sj{{`CR z-_frABigkO|A(keyjAVu-_S1q-gfq+cKTb|`Oj@vpIz|Qao_76vxSjuu zcKOe4H+~F9AXwz~I~>lE5{Ik87hLA>yDQ5aMOCGxF2BQ78T2m;Ysy@~SYC%a;3zNg zJ4*fD3P**j!fR!7xGPJ&QIb7gXGv*{^jOKM<2rg!^=ouBE{oB;>iAfhxbtGEKi_SUUJcIvrhN`o-{hmxTM>RZ`}1 zEb%*ij)2EXb~t?4O=jn!v~V;0F6jr;B~5jhzHp@?%9tgY!VaksP5r37B6~FG3c#hd z#8unOImzqs`X_lYMx3o0$y4mDT3h>C7F7Ym@3^*%%9#<5l!%^z?cpPXgifG+a6aDV8@?a(U z%IYSwNs*n{rbcKZ26|Cd(CcrlYU{y_b<1k~OW zF$YC+>0}etW6eZuoj4|4evBYTncrD5qR1I=o4u3m@}N^@xhhLsel|5Cy){LTF>59& z#|&KItiV6;7S)3bHkmsWYQwyMyIcCdYD*yU0=El2$n? zz2(^ZIL+wU#@h3KmkwX^6cjG2!^tV^kx7CP+XRX%s*S^8PAlbAm5Ur&0juQVa#!&p zbM|bTjuQf!X~t{oFegaN8YS!#o(8RWNS8?kDs%K}pSnCAoUK|rky8$Ity59BZDvw< zUNTUUYpJi*>k3w>72cU1mmeuwlHY4O{lyi^N`8B`Mfx6gG;;}(w4jYNQ^k=<%=CY>6w-u0@AB;)M|*xkKvP^ z;lPq55WsBd@CPd?l>KUbE_J#+n3Avta0a|qqNB{wK7DEcV-=_0psOEL&j znTe$pZpJ`2M1Gc$qz8q=C)1as!s#y)t=}^ddBX*plTd}TH9_Z|_9@8TDk=5)TxI~j zM=ASF`UZsty^C7YmKRmIJtYp#7~zh`00~4-WqzhHU$s749I87D+F5x$#>D59Vn{arq*%k1ahqOgT)Q>>V zF2?@^j zTa}WeGG|4Fvo&dXiLQ(s*zIM(a!cuRx-0{O(44|rS4NH{?vi%iHp4Q)?Qkr&D$iL{ zR+T=dWS`@A7Q3c<%d9d>ymG{;g+i+^3zoZN72&AznadAcE41;N<-~Hf&x2)Dy9sxM z?45wS%s@Zsy1dC001< za_(16i#W{~j)F?*z%~mo=}bBGv`dVVF>QY!I!j>Gx#21I{8(tHAHcsce&= z<%a`k$zfB<3>(@yb6J7wE-e21Y#{nE+CpK3(^G+KAPhvScf%tyye|VhDThUzJ|Zvl zF)LL{{BR~*0Lv1sL%KC(wAZ(uY$C64teK!SE^jPgx#{cZ#E8^unurS~P8zKd!lLjJ zrh|l)lmQu5cM!GKn1$k~!xeKJU7MD*UV(-CEV6A;+~KN3v@V`3+`cHHXf2E)i_ymR zO7rB6rIef(IgTQ)s3McYcXJ{V<>=zQoOY>t2^Epp?j#)UI!JI~f!i-`>;$V47^h4( zmrp@Cs8~Hrz`kHPPo{LVUb0|`u*^KqQf(ej<}zJ#Fu8Sk-X_`M8O6v}Va4svLb`0_ zK|2|%C$ng4qM;$jH9wk1wcETQQ|fnxhcX6)T+3JCjz^j<{$+(-f#c39xZRoBDq)r@ z;H~l(L#7j!Wm$70*AFsBIx9t{4y+k)4!!YSUt%#D=`e3SNLWtj3%rW1=UI zj+R{I85J$rS<*2XRbkJY=XuQSsAKq&S5_pFfG!JPRLS+c)od9{GT>>;8nLPpt39lv zgKnQ^nZsKd>5uD_%yRt|z8dS8-I@g8F_mqjM^wbTG*TO5EL=adL$2w}l-P@^fUh|A zl544WbqGZ+E5cXrx?GB)Xyd>Rl~omni;EvHIhhGEIKx+5dP}NI?j5;VYS^a-N^BqQ z%CvJ@^G9)2kwlAF70hx;RXpas$uU($*51W}SK4Tqtrz~9f}zv)ENmrrIFuQ|x=+Z( zqIm-qd!tNC2oErvdP*>hnTsnVvNl}^%dFcRZ~n|VIu&JS&u+7xoH3(gkX*f6l|N&O z=E<5pXHv9o47Ux_R+?o*ezy7+yB(L2VTpAE4c!yIm7hA!3Sec@8@H|LSd?;2+L~rX zTIPsM(;L5OQf4?=j=R=#UAy$KiidzXwPEG!8$C*b$Sod3a~6#;>uB9Wtdu42=r&2E zMHRSb)*;#NmhT6mII!$4s=~-9ZsWy7&I=q&v06Zzq*3za?ts*hqf%_GTk6=<)N!N7 zjvalW%{DeA6%KW$rlgD;Gsb3vFD1>C7oJ!ZbbA6Libr_E-xA~h#(($OkMh+NzV0@^ zPs7(@M!gs|{9u#E5#;}<#o8L)R8J!{Hrj}3$Pc~-GdBmmpTJic;mzTglQVBl*bIND z{GEQ3cv6?LZw%zz1SGLTZZR2Tb>+f*?rDZ3I==QdH~G86kz4z=I~+y$`l5Af z-+$J)2(?Pu^q=hF$W7W?;d2(tNn92;4#)KDNdG+6FU046dc0)*KUHJPN9NzX6lt3- z#7)w2Oa%BEM5DBC@7phHdM+DW^Qy+vRP+D#mRp~N1My=%I&%`fxWy)g$)h@HpBVD~ z45R#WJTr~KkH-Y$?@gQAMEsT?Ii}|0NA&;GtsuAdqulBvnYrt8_UG2FJf2%yb+oqN zNNwJs?An|Ur`P7aom*FRJh!gkXm0JkLlQlA{mT7yRY&Ry4%Ov-IK3|CZB4D-o4N4$ z(t0x<D|=YM zfviP;?p*y|=i0oTxpga>>+%j{*X8W5E7*%V?8>ey*jby?xG3j9=gv7h6CcjmU)?mW zHfKj&&VkyT?aZ)FO$Vl9@C-h!I;$wRd(#8h0Z%>jL*vx%x4>N0R z&N1kdV(9-@kC({tpN8IVOh9e+*H-PVEoiFE+l`)WtX{dhQ_Wg=r*Yz%Q_xu0T@p7o zY0{0RV<4J{;lHDL~sC`{i}~HV%J)dAd3s@qRKA*M5o=^H@#&Q||iH zZ+igypibt7y*SXCvg=Uux`M{+x`jLH7H-QnlUE|ywLQDDYe&|e4?AbqRe&FLu6&&t26Ur${A9(R`TLgiaD*YrgeEu)rS*m^R`y6+=@LoOe&2@ ztS)bB;=_4+@v}R(_|@EmW*jN?`*Iqju)3Uv@i}`F*B`-9fVRFauc3`Dv~R7<4dx7# zvrYg7c4hVF2^W2txc+XW)a9(JZc3=lS%-cJ<<{lZBPJ3sr=qy#+=N$iiwkz=*1n>h zX@;wQT7qJfzJP!zHk4bt)`t|tuHMtBHg8L6Q_UVsuc%th`blsku9q%Zy>eX$NZg8X zFR3@0zqcnOuI-BC!*ZI;t$SJmX;ZdDG{vlg&KKs)GzelG4!L#fO}$pM)-=KmI*ez^ zw0S?Fd57`Do^cpINZMkyc*|iKpoce`NoaGY+MG5upBS~~l6vD>`5mr#J|bxE$sUMP z?X}?=NrxXcn;oTEOQc#-Q}b82w>L>K>mT*P`=q%mvF8pY4EhPlHG68-OS+8h+`0^$ z*7xVtW%kIeeL4-P(`)xluUjjhvVLmbmt&q^%-yptas7DYeg>YOa(HAE?5@k(Av+Z_ zz?N*;1$o7%^pPa;gPqbde8%=RXu!J~b?#ZuUNWdqziudw8_?!pD zmH2RK&W9K!((Xif_J5r?d{50Dq#UnFWcn2JM^fI0nr}E}7}Gm5!E&Q-qPRQN#B~e{#YuNS#z`|=abbdkA)&@cr>^8&D`qmT5H%@ zYq-4uH9Sdc*u8xXKZ#L~wpGU1J%o-y&CQirxPGgTNDXr3|40gCX@{$Zl`XYZ2Wt!7 z&aKUB#+qn<-RWQd8YlXKy>$f#SHCZBq1p3YkF1(kvupBRG?S!FYVWIFd9X*~I$1fb zUU|?6VF#>})yuw|-S{mhg7G;A6W70Hetx^U=?7UivCp}p&9*k!bL9XZT1kY?@RKPI6unorF+g58Rrl}+XlcoGXRjESly zjM^5=)EESS%+xFEafJr6{-X0_|FQLV~n9+|qUb2e$OaoF*(G z7Zn^dWC`&l+S^>y<-!|t_8=9zchCFn(x0=^6WZ#Z*C?GMQ(HUeUq9l!!#>58p>(E! zBMOisYG2MSbT`()ySgNa=gu1Go)h}YSyr>Cd5-$2GaqR`sL>O&tMCKV^7XgTlF}m~cM(pC& zvewD{3)E6P_@qO7XX1L9(V-fKD}bDBt5+cGw{y;R>k0}< zovU`&R_#9ghc@M`$0fNQ8M;>6iH6qX)g`V!59yI@H3ORMmS$!qZrqnyv$F2SoVxJp zr)_f{k`ap-;hJZfpS9)<)hipWwW{54Ej<4hdv606RdM|d?kE6p$z?8bU|_5S>4NJ5i7CSs--F|ZT*N!FeAzvU zWbwXCh)o0w(%&^?fOE4hoxe4y{0*ewH`nxafNO69y-h{V`^4FkxcVgA>vjIgF3f0`}P5XE^bRA{^lufP58Sx;HKk8AVj+LBPsjS;E<)^VEMt;mi&;rBGV zx6lbyTQZE1xY1j=x0?}AUB_N_NFHzH7N`e&6AwM;7Rz(k+XSu3y=Ang!&plB#PGGH zp2dX4G`%uox~tUu1-^DP^HuLgr#a!Ur>F_4!IsS_-4`91HecS0N87guwGcr*P|@lM zc4TjF%|Qe#m$qUtU zh)!FQ+ZB8h%$&9L3td#OW6O^yEEw~425({`<4DEw^NwjkzPu_?*jmEC<|f3_(ehC&DH~;F!lEwK_bpFR#a>U-$H^Y&{*V>=lvy{6k<7Qy2hk>S zfO_7mikEcKUlk!TebYkZLtOo&D_0Ql5bNM`^aQjKj{O_hK3+(*BQ&)pV;n}~v>Tp} zYhw{I9WK;JR;*hNn+LtkPV+X1^=r%^=JJi>t-erJQeK4&)S|3-M@mGccp!InI<_z! zi}Xw;L$>sY1I$BuXzeOJewDMh($k5d+?JlaD7+}?A)`uyyq|(&wVVSz9TRy95$|dZ ziGQ#k9Pwml4!K4cyDb*RU1&7aVIXs8Sruqm`_cK-dIs$`Td<(BxN;@A^9Qa%JmVg< z4pq+*#2n7=qwf;=Rr9$mTw;ryEq!wzQVNW`9pHsCkrYNjdWjqf8@iEUftyTOdG%KQ zPLYxQ#&dm3kfT0NO^%?Wq|qZz8d*%^3KEPgj&6E)v5`O-3F&FhCJ?Se5m;=tnO#o=eZp8T2~qF#=8NeIM$N)w!_W4y~l8%z4mER*v7KSX&RdxlR zV_IrN?BEn>@i$7O$HQOhFf!1)G1GioT9947M;B{$D@gcfh4ATRz@B>Bh`yGU|) zyuPMG_bBih?LJ@xxTp}7%>RcnLs1^qDedrxCETUec`J87LNb|kEnmYhfj^Qq1@74)4DRke%*2~Fvl>|SBIS72K>*}WVaD&e%5rTQ<> zb6R;TOy3B&%q_#-umZFl`~sWFR{nCcW!M|EFSqiSCg<remT_e_ej#i*qIL+SL3NoU1>E=!y; zhO?x#MO3fK*+x!CtV<7@%~Y;_ff8)zCP}uxZ>A0bXfwGkzs2L-+`&LhD%!>u_3@Yo zbM38aOfx**CWx*~S3Q_xFW$r1f*ROwK!C z=Izp3y9d+nGM9G)sbz~G-g+|cV<_$I4x7gGIeAIf3i{-_& z7P zGn`v+{s27`W&!894`_Q^x8#t$H6_BoPlW%EBK*6D{G;V7e9ouYEw!W8@Y+VZ_xbZa zF+@pOT-hc{E;d`;pDb~I5?Zbs#X>FOS&KXwskOb`SSRb4)zma1_e$GDF57}D(Y{bF z>Oe)*`3tl1uvyX3>^^{)=$1RoCT~-xnb#4LEhz}6m3P>?+nJ_H=5SL7W`c)z+TCLYMCmqbsFWCY zPiLhDx(z^~AUO#t>g)G7H+JrU5LUx)0`Qjf<@_41JiouMGl-8eQCt&*@`|L0P_;N; zJ-A|%th)<6%JrcAS^l?es#*Rq&fr_jS(t31h)v(diHlt;9wRBr15x(J~j`2`EFz!y0F`(PEXjiBk z2|9Xx{VhR_U|k41AxEeY>UI&CN>n3VtMd8;5o1!cD+qgRnu{?`=eJV9+1UNnBA4S& zaR#}&7LS!Eies=1)K${3v{aol*u4p+etc1*PAdlrr_-$A+H#IwK$Xg;N7u^7_ylkCg;rYWfROt$z~mOvuIhQPXs$|%3`XF{9$=ohtn6Ken-ZNyOCtLGl&qe!J&NQ z`Hc-@)W%M-bS$R)hN-@clr8ZaEuEebpt7WV)WV!4-IOVvoMK7!WnA081F?f={R=;c zgjnn%DgJ61`IT=V(`xZh9Zd7%FlZH)4UMNN>Y)V~Pi;nr4ux+ew82sA#AAbViyCvC z%^qluP!Ii~L7+u-_NMHiAda-Ss^IZV&#LsR&_GQ&xOpCJ2#tuO*GHvnE0&mngoh7r z8`F*?w&0yHTO3mJY~>3Gg`Wkkr_aBoz|tjr_VHK#dR}_bOw< z$ogMkQAdungj0hzr6J)T+%{Y$WhjC#6Dpq+IW;jFxLD(|C=90iL*x zL_*>=5($aQt74SpEW1DXwVtBmdARe!E!oD3rtGROFfH88Y2g z+@#`L5SV-p&hOAmjhq;`_YKAjOf5U%^$2mdhup20-i&tdHSXaGjo4d_d$`|*IgMT) z@#l30Ijms=X*7=O>Cgiaq3k*_lMMS9>)con;>q=h{o)L4*g;K}6K4=E%#6ojujhbg z5YG3$j)CSdrc7uLp)C@eL~3tp>nBvR{f($YL`lo>JH?ZD;5T}I8!uFFiF>D2u>(bo)e>}`d+l?gkcfIrj_NUz zsT1gjQ8JF;9Q;6<(tb{XsBBka$wg{eGxKrL8vga-uiqvJa>}Y__zXiyZ34e~PnRcN zal&59cO^94$L+}MFx0CE(=cs~I{#t0Gjap@h{^X5D%#Bay=ETwfOlb9iEX2;NTvZAUjVWg(X4VyrSg*seIBef`z!&DB>EK|S=U!@@#KaU&MOIb^GKj8QE^gf~I2D zjp1+2DEr}1_I!Kdw&3&MxhIn%n`_AcfD8_@<8@mi(%imc);wKHLa!sj1$N9lHk(3ah5Co^&|Fuirvq zQZ87&8?;3QS%RRbH2eDL%z7JW%Q6Bp!D&4iLdS_;sP;7su}0i$JXI(8+C1F!twkDU z`vX=TEeF3fed&^8{zm7xmdvn4EN);R3sz^ER@3)5!&Rmkt~@O9Hhqk2$?x-uBeplT zM}jPWb8eCFk1ec}?&jt!|N4=&(Dyw>b;5DVGdO7@95)W<+Pg19c;s(1k88p_GO!De zkA-<;xap&ZCBLSRkuCYv1?I;_zc2uyk3fOe~JQ0m`8BL_x z*Dl#*uw<7OOG3p-wBQhwvJA$S6oCYgcJSXEa#j7lz;%Poz6qe#x!E@npmDQr5&%4} z0_d~ZHyI!muL>Y0)K$J!kPjc_VGn76tHo@+<*(WV3H300s={%H+id zUl#b%?>?-AB&nASXv0eeFJz$vJb^k^WTHsRLy>6Xn+fb`G`94xHkHyNQ1OST(8i?u zsiax@iIT1gMWPLnbj4vq!ubOGwL}pYg(A`xj`#xmfkcr?Ly>4>MkA6?LrGvP;yXC; zmE`dfi7H)3F4pg)oX2B+*f2{dVRfO7wus~(IYRQ&Ldny{I zDfbgX$AZ_gSIjX^V&?CqNU(^QcfH+7M}2;|nrz)~EIB zI8uAeItM_r?=Wy!e$Bp)knKRo)*iC$(>66|CuN&2yNxT~%`qQpLxA=)uH0z)_QKul z+ojPhv5l6#!U&v<^@e6&YbcDi(LVMOM&M&i8WgrEol~=KX9&*)3@bpISZd(9

    Dc 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

    w`4lj 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
    $vpw=ZRr1#=`BOde5hXuQ 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%0AUL|RN()AB*QqA8Xm#&4 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
    6&8fUS;GKg+L2V4A=>-RYFJ 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 literal 0 HcmV?d00001 diff --git a/release/libs/osx/ADDLIBS b/release/libs/osx/ADDLIBS deleted file mode 100644 index e69de29b..00000000 diff --git a/release/libs/osx/libglfw.3.0.dylib b/release/libs/osx/libglfw.3.0.dylib deleted file mode 100644 index 15674573ccc9efbce8df1b54042dca0604158db2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 127856 zcmeFadw5jU)jvLgj0Pp0pkSj#8x<`oLbQ(M7ELgN2b*ZLL}{yX6AV@{0?}ZNW+bCI z9tIur8O#V-P7i6Q=~Qe^2+b?S$m(EGm{YD_kF(q ze4oto%-Q#~)?RzS9qd^*Jdioa7uf)fD`mceP`Z0eg1q_I2~T@Pz~>Dliv-yU{ZLA z$f;8k{9CZFvOE9g8hDRuus%0@aClX7@0c_9hN*Mr&c0RPr?&6FQ#7D!4FHDIX>wuH zojP?^#njpJ*tGIXuWyBcx7^Ujun`?yAnnP1)&&MnomyNpxyX~~_OE;s=Z5oinEi}! z13HNEb8ntHf8i}NZoPSG<$`$!g{ONr3IU#%F7}711{R&EQ*XRADJ9+M%Q5tnnKBHg z!<(K0@8;>f(KpS&>oUw|*b9&K{ZR_MnQ3yI%D-u+>jo$^Wf<;Vj%UvHcC_^NSZUxj z86XUM>GO~#UL(iSFK(VQe?dCDX~Q*r!(I9iPJ@?dDrPb8=G-#<##t2Qba?d!UY3E! zaPM-g`>o5wba)L0UM?ArAH!+%=>+pM^v$1j^SoKJp`O#>tsbT8TW^3c?1hIhqo?`` z{|GT1UjDZ=ywwIj!(MoZ?g`%fDyaFM;I$cexdtA?hXHTS?bA7Gbgyq`8a#&6;2BKX zG5ot>`hw{akzU`d3v_)OwBuvAcX%^zz2%l$=ekJJ;VlnpK+^`hIkY};Lk5i-M0?Jd zpB#0&*SBkuF5$`_3wr5Ghey3<;Xie1$)wA_8!DbOnI-TmGdY_i4*f%s3spJjD_XM<+= zMtyJL`~|aa8C5c8#=PnC7LJ<8A?uD?=ly8@s7r30dF%9%GKMi?)YY@*&7T83Fseu= zp?ptp$=zPzUQsz~?xiI?1J-Fh!aW{-X>b$u$jO65 zjmYSwJ$tXiC8Lt*2L5O-eBT~~K!4Tzd85!x_~*zlvM8n72!FlhGBTb6U8&`?$c>!f zE!j;zhx`lW&h4#TiYhA)(%_ej(rKn1Dedi>0`V{G4KCZ^(s|P>E9T6cfAFSoa{vc_ zXX4NPS5^*vfu=sogx6fn{^0YS;|W(wOy8rA1AQFm<3Jw=`Z&jf(w z$(jTk|AU}2+H!`R`I#iNS@!3a{jTMd!&ll0m@TN#r>`(Egu3{bNQvNqy^M*e*L6xe z5aVBt9KjBqWI3g+>bFdGN|7|=Iw?s06}&AuYMLzjJ(Ph{)u?g839SL%)v8JtY_XgH z0QoBxaLQM+fW1{sL1KOAm#FA8Ff@&y`5^M6k4YVP=@k6s-z*xuLQsa<)KE<@2xWDG z*JxsuU+`76Soummw^Tv=Q zb_aj=FT#tdO9gIB?VuYCUd7z@eavk++DXbr{&lZ3$j`_}eo`E&x}3YK)pi2ej8{VB zhgP2xQvKn#n}8`Bi6v3gi?x8TIn~up6>3?|P&+DIWVcLeZtqu;(Nv-%nm@|0cNEz> zCpCZEuQUTJZC2Ze0iuqQc4)U+G|%UYg*u4N33ZGMslcKqwBK$f*nGfKRebNU$ z-)DjEH-8ow(KOrMjx@CJakK3UE<-uH*=|91%jmMV67y$8DAmv{_f=UYJF?ne*juBS zm!%*{02hcF!&Nz^jJzmrhdScr2M!#NCLl+eQJF>Cz}DIFOYh(LR-?;H52rilT%IdT z-C@6J+1u6HCO`pClYD^mbdD>^4J`TvcwsdjFmKU+W(Ce}vSx-ln2z2N`2FCb&jM%f z{48*Ni-`uq1`P}+^GwR}W^&3=G}PI@EZ2V9Ze{08&z{pmcBeA8`L7undsE7QM+uf( zrddLPAb8|=g@S|@J4Lz0V080G{j7`@A}v8|2(d-Y?HM7vDP%WKLSjkA4s?I0o@TUR zn|h91q581jv_repQ(IhCQ-F>9=Ae5_-^YB}{n*W%;M4zrL$-!G)wwL<1eZ%xOr0V@ zFwPFI0b5l)9?-GyokCR6?5`7&9bSnjE4-c#e}M>Jnu>+?GZ4RoG1oK!Z=6cgXYw<01qh{;7{m;_&%oo3egcOmozQ;BP0n?%1io2|pik-(?#PFU+7RK zx>V;T`0a@LA4pwz6CLIcMDX&XFW!!aLpIO#tjSF=JBD`6_3U4E;u6sq@h zYW^+ipgdejK?palL^l2cb;I#Q{1_3C+La8UHXAoe?CFe+Nh}hWZxCaW+;XxjcO$|X z14+6XdP*AQ9Tw(r>ol%rDJOUdk~B<4$7&hPA97IGkmFS5_^DekR?BGqkfTwY;DNs* zM|Cm>qxnOQCOGN|B&pNz;;DLl8DhK1Pt-r^4~RGF-c|JpeP47<(bYxeMU%g0g*&>? zW>&Q7H3-{|KT#@o5m7AEs-4%g(?SQMTayj~JtTLu8t^g;7kq{nXYEj{8i=6S7r@*! zuCz4}`5N+Jm}_GGK;)a=P~AX=oKO?nU^Gg`8?y+l9Qqs7R5hvJgZBU%t`S-Sbt32w zBU89W=rN)nMogRtoSGJOo0QpDz;K{$wm_^}qlt3-|NHCA|%_>G35+0$Fi~5g~zFD(|ihCOJq0*~SR{VfJuMJ^M?2Cq665)zND(@PS)=|}MesGU&rqFIWH$g# z3bI-cvUiz1Tq7@2*GH}vWPDqhab#(rZm0=?TL>ixc^U=dzx;|?1cWRj7-%>BYy1-K zhU4%kY8=hydS2qO{vG zSLnFgmXO%9 zX05|e4&YE6tH#x=GClVC%oGMzBb}q2PikG%DDo-QZXAr*q7CFE{iU^~(Zw2fMfU!#}JY)4w?)ndGjbU9VaE$2eZxjhRa*=S1!5y@e%U5$Xf z9jqn=U{N<#lMuw`krcQIRv)Istpa?odZjp<9v5fraw1*vhy+$Nh_h@l9M!g#?Gsb) ziW{kbgjn{nN;*zNI+dUA*Q4i2l4FuKu@*4fkcrhi&}xSs3D=NvS9k6L-=NM;c%M%2 zLxiAK2&fz^I?i&gg27m`9HLPxkk(eiv7-wJ>}|_gru*|!jhopEL4uB4Cz0&V%xy<1 z4_c-SR*^2Vg=I=~jY^!Tjuf1zZ3O_7U>afXKn@1%$PIWF9e}wEMeM94iFRZfo@&}l zs6&eWAI(~A;EbHV_3&h2uv_ht8{Q6)6c%5>qEN8)k*S0R)Kq(( z>ql5Pva9x4HdaS$E`@OR{HCH7g8haiA+P;!@>{adRMVxhNiXK$YVYsJAxyQ$Y!5`J z@xk{_M0AlM4`sQqW_Md($}!WHaLs-e3q(aeqyBS0MHzn!AX+m^Ps) zIu&gL%u&n?Z-4w{HlP@sSaK;g^OZ#%WiqREYP!M~qkuar`3NkDh4wK96VZLBGz{hS zT4Yh1eQOX;MvQ3=L`N`_wxlJ)%&L9rLuNqDo=3Hv&^|-NzWDQ6t^iC6$0p?Kjz`OV zs9i1Ac-qtPNCx7$!{E8};CPrvfR&Ft7UW=UraZ zid=&Q&kAgrXiy~8;|PmMWo=-S@n@|ETjZztSSuP4vn8j{LR*4cqVH_jPj)$4xU`9? zj7?(eoLFR=lnYgi7_DOM_w3Nd18+$t`%MQ09Tap*o9s}d>Lig|sav$IjN)4-M7Z;D zyJo-2Cs9%Vjy-UCkTFoE1qmxA>FXtxNqLp-_Ta@>CjqRQ1T3>g(oJmJQTg^T#oLv_ zeH?RQp-x8W{=)vZ-iXIab<1xVU%FD7ZHdl=42_b3>$X#v!49>7iHNUiQ{Tx%L;>Li z>dwGZmWf;y(P7O5TdR|ZHnI#SK zz_85YBq7NITB<$p!1THX_1kAz?a~I}L4Od1@*uZSGLQ$4F#{yl@SssuQy{#f_2RFA zZq$A?G$>R%pTH;~xaet;x(2Nd%~_A9)Ex^&KYtY|Sdw-wcnBn{!2;D6@3fz~J^U4m z{9llbHI~blHSwFkm!A05hH*^KhdpZhrTwC|D-X6lnTNi0>PM)I^i#VA0~JOY=qz`t zm4VeVsM6~Q$J4=Nf5Tn%{uU~2m`@2+gMWh|6UJaj*;zW?s57cD{AJub*m`Ny|4{p( z>3Ln&g_0dUg`VOhJ?zV>?$?GMS3K;}-Rf3}#HyoHzB^;55SwF&W%os`U1GVon^nH-foAs9e4}t*G_2LxKKwRQUov< zouLh|BFeSqDCa|o7`rGp;U8C&7g&;(nkTZR1(8q|Z7T$yQuTSbL#h+?U;jEFyIW{( zozX{SziGQV@mEOpESg~7%;s!>`!CB?HdCWR#uA2G=H2?xPt?b&Q;T660wd;M7#kgO zPFnUy)r;xb+r-9TY`8`?IqE~p600JLdd;kgAer0`M8;5qP|ZNR7sUraNa``3)&}Yp zBU$spLDV9ZVcBAn1|s))Qh<=<#voDVRCbips6gG=WFDQcs0j>JS;$9=IdK2*WCn_5 ztr-Yf;~XSKK%82m7+d2fCgWr%!!V!?R>ZTat#ku*6_j#W{+9U7#KE8X7CEBzCWHg} z6AN9Veu=oK|36$_blYINn$B4703tQzazfM%YE9Fk*x$hfP@0U{P^XBZ2^0CgZ1YNP|fP|oFGag{pf@`2jPu}fc~z+h{UVsy2xa2rT# zQ~$jRuxX>jLM;NF?KCdb8i-a?G?4`*Th!Y++iFCtR(^CqZYKCqAbyd~wpyJ|u+f6X z9dNipCqIB*4(=?6Dyc=i0jpNML0H;=Gn+cAa*#QGG#;_gsysNlNKCC@R-*h17=`V{ z(nln;*@PM-v=O1bfe|fs>0+mJ)j6dvVQTj=3O2W&=&(S!I_DUtMtjBvo`2J+K{-U; zndww%-@MGg^Iv6rF`xzNnMvV0DYB3R_F^Zr7}BE7DH@CxegJS`mdB4pg7EvC&|-u| zoi_#U&6WI6?M-@L*$HhN7itVFGCcqiz#ZCcu>PIWjdp3HtF2lRrbSEqPELgryVFAe z5!`5_cs=+uEZWckUwn>^?8Hu=S|Ti>G>2;ut?JPp)QAvpXJNIP$>d~n=vXvEyB)a; z;-a2Lx>HlH6{Y%vG$wcd-c+Y*Y#D)dAkg<$PIgxnvr3y`X#+WJ2tUVk!01d*kgO zjGRM#+tf8rA%~eaT*T5*|Kij_oME7UjPztQ>_>b|YrnI6>B=Ucrlt|4bvj?5d zpB$^vk0ShOb3IzK-%PR8?*P>F1rmilcK_edT!CwLq}uqcvcKol?8hXavv2C5`*E`He`k5w5o>yz?h2YS&-y$p*?{`i%?SLp3oSr&iDt^RmiqCFeuc7M`=q+(u@5> zMO7hb1ZV$PFRDc8a%E$FPZ7<06NduiEI_L>ILuQS=uqf~PG+-RR!x<(H3RstfCacR z4dEe(+eG0*c>`b;2u~he5DIVdPzX>1cTyqTj(nyU1d$FoMv@N=smpShtF6 zV`)yu!#2ms96R&fID14Kf7U%g$OA%%f8g5$7<}~&I3VfUPtXmmNh9k{)Fc*qmM~!4 zK8t#;L80YRh(`u$)t5gfoYGp(Di^gfAI{&rB5`Z1ndK-Fyv@xn7M^Nh2|KhB^x_}< zp`qY+I(j*x@eh{hXsm%&Q};crQyYp=m14WeWq7euSgnH%D3g~!L~Bt^71E+&IfA;# z$)pZQ$vn*@XYjk0eQ!PDy}WwX@aow(ca>b>0ILV?#3={n<}VPj@T5pMReMzS+~mom zrOzd$O_y>8;iS^9uVQwsu#X~X?sV`>!0FaZ99oF|>)U>LHk-FK(1%42< zm{~NZa+K(^@G}kxdfpOBiK3j+#XmomWc#(_HSmtx)RgSWc-jUNu{{u_A_f~#AB?Zh6AtGgPEC{g7|Zf# z+q$cnBU-Z>Wjd{yq@mTC(?n!e1{No(kXu$mm+SMHvPo0A+@f^Sq~=_KbDyFd0w{KT zMd2pu!D3qrH)7k|<_)#QXNVd?(}J-xNDfaWJSiTT9GexG)bV6d$280CvTUy7^E4Y; z+^zvmZ0m&9s99hG4NvqrjApVST&kL!!$e4?id}gb;0F$ zU-%21>jXG^vBKB77promEqepkHvb~~ic3iNjfAX-p?222j4n!!A`0iKFsvs&H# z7;+dJ;v@jZynyCLEVM^Eys=&DBBW&L6zwQF;32@p)OiFWqXBDwG`#JWeJL9N{JfM6 zz}4ny-PRYl{}5%~_HDEl*jb%&VCT4l zQEdXTx4{MW8l^rIcs1?njpcwOE8lXgCh;)q-+9nCZ*k=zN|In#bRj>bzkI*_COICn z-=p*9-ayWfdTcxF#ri1Q0PKDYnmstTaEL|>d(f8zP5^GF|0mbF1_Q{95pjA`#A^HjW*pMqZIkzDc zPH^^idShzuqncGvlU<-0T7?q|Fdfpv;cG}x%47~g6xTJeROsQqoF7leh4a8H&AFKvoVt=s|_KmW|Uh3WY%+Smk8@PYb={v!Hyc8u2J^QdxH; zQvd8pZDVS?I{U|o)Ga1eO-z>fjl^YUg{#Z@7xsrbG!tLqdeF^(CNyD+!I8>uqmQGd zIo5`+WlFt$?5!|Khs=KoMWLx7%g4~v?hFiX#@Zhg6wMFp0`7l=LY-6ENqG(2cW*#gw-M>c&ehK;U+aY_d_b4$4Ohd@KPUrvX=wtz@Q#^-QN7rbQJ^ zL0xx@Zko$X%Up(rA;8OWk*f_dNClg|pJzp}7ZAnZL^q{2w&H~Zrr7-yg^txr0^_t^RC&FTCJuAVs(W;OFVf`p%Hs}>v4t4N662u_#goAcYI^AMDWUegfgd!fs}aZZ z`p^_K9mCtmFX~A5yl$S}QR~LR;BKtWP)TA@BzyG@??c;by6G5T|vVmZ2ZH3CDTRrR`@d>L_&k0XEf*UftUa&HGA&OepkORobi? zU3I>={#?eOD!=&Kfdev0nAC_E`B_fEaExFZ7=XAwi)JlxvY!)Yh`fzq*QgTgFjnm; zv9ay(3536`1PVl50i0y4eoN+Q3Yg4r_y$BPW-_Cgjv-i+(x}O0e<=i2we^Azi+4`2 zl11&U>Z=C@L>IbBedtZ~{(J<*+CPl;8X@8+?e!$f$tYBCf{q=lgV{$*aNse{ZDoqn z3f-z+`y`M2<#`#X8V4sQ{wtHme)nmO&S7Z_{yw$eP)Y;iD(uF|yHNTl|3^rI^<)Gl zwZB4MgzwUbJY4LLrf*E)JbF26x#S&5Z(R2JlH!Qu~sP(Tv!3V zx1-CnlUlu&iyF17cdN)6BspxE_W1jRm=pyKJCz?%fB2B_PXQJq%Rn+H4au$~+1=!s z^q+c2_!9tMlijG*S#ZTBw89%vE%aX_dW@{d1N2K5Kz|{SQqeUD8hWvh)TiG^DPe-k z-%2nRI*60Csus&BIJb##{bvF_Vpp=-8W0Hz>J5dYgY(i!qLBe`c_mp0(g;d&PI`8qE~Sm6(amJ?DO`Jvx(sNV)*AmXG_ z-j?IktrX*44(;)rQjCX#LaXtR1*Us|fk}wSK?GFl!;1x3BkFRKrsD4}GbW}MGKDh{ zCs-zgl{TPM2L6+>nEri9=R`G3!9lYy>#L^pIHYRkFWSZ_XS)3NX8(Slgc$qRfZOXZ z3OXZU|8i0SoKQMq{}xCYWB)qY7cv;j%p&KIs|%DpY(PCpP>hnn)NNnV)1K%&vU6SV zFNm_`T!2^c3jP7Lh*S*tpQDN4K1e?X_ptU{_XK z8L+u~u($tD(+^_rpD6Vi4`Urd;slS8;NbI}d1dM-@<{~VJwHVXq5q)ssDT2JvxSrX z5Cz@|{(=$#A(;Gt1o=J)gCPXt7-}iv-xG1F)v^(+F*#0W0hzY-(*F#Ba|D;ri)Idf zjGh3h+OaI5cH0`^DZqtlVAyiIJznhl{zSonnT$JLpf2w5Jm_;P{3*YQW`z&1q+VFU zX}D~HkTrS;#~J*qYDbpC7){%zUm#ZFTRN_AQ{!|kB#R5GO(A_ys&F@jT069=Cs?zeL zh1-H2yd2DIP)`9vkFyt9tBk3gLV*w*Av`c>CZb47BUNgXu3WH*+QAv058{}RLmho> zX_IO|`=W(<(tka*&q57`{gXV}yN)Qeym#EE(U1IJv`<3Rb^F|OiC__NPqfd$WT+GlZ&H@vR3S^7K!=f0`~& zb5h|S0^Wp5aH@6#>m?d1Rz`T@E4_XP<5!iy zmPSbD*A(J97{7Xe7krG;o#fZpBxp6zTc0mpO4MgxovzP?uq_iT)b*KPxpUE~ z)##-w6Z24*Gl+4@SE~Js4%$mw+1A6zqbOb4|cTKo@Lbj5&}{RIWg ztOPZ2t*1qOHHQ>#V{N?amuc%^x_(<(JUsp)XnJQ?9^!GB68wNaNQS)!j-k za#^G;q``$4s!q$tuA*TM5?LO1RDjPYyjf z$#u31gihhW(<1J!g(guAQYm3dsi|0hDS!c3&VBhWmqJ*acY^O=F&GMDx%z7u9(S|O zwcpCp#v_m%%n+FGspnB3@cS->FSKLu#nzvw*M|uYro=-8hvs+(+clzE#heohNwFhB z)-exdp%TacTPY-WM%YywOK_O6v{79l@LREk+71GnoT`mDa-}{Q$HLqg3f7{OI!o}- zROdgqKp@4`aXPvMZQV-AL2@g0mRbUfCM6^&d#WZROP4K&moZyx%-u#^OPm*Aq?HHqfy8gxOX6)IEaBP2ja)U56f-9Pi3pX-suc%uuJ#j zM1>eD=w|pC`>?PFeivc+fE>NJ7A~}vc{AtKR&E~Q%n!IjOMJ*flvpP-XI%ZXejwpK zO~RfGKsN`V_7Ib>Q{-ft6c{+j4zmD+kxV^Zu)V3?x<|L}>8JtjaWJWCpC>JEsuz(; z7XAC*OaH6JQEKVO8n1E{E3L?_UJHx0%ZUEpJ)uQoxa~f>k6Kn z(l$5L7SB)O{Pa1E^N%&!8gp^JXW}=R_%>XSKqv$?LhDL{~T(*hWS`e^6{8Z`<@DbTC3n#5)>&*R&wvN zx{{rD!99atn|0?S=Om~LUT13j2WHZW?J5)1h^Y9tm^I21jO=<)e9{U0Ux^&Ct%9c` zyIRWPV#_4RB}%hX2fqMerRv~ z1M9wgjJUFYOtEr;yMzLqQQ}q%-l4lnD4|B?y%d|7$_sIz#MF0?R3G|K*#QCYg1}*} zmB^(|L@JIFdQJ@{*BiqfIL<<4w8pZlR^vb{i4lV^e7CNzzS#k1C2FgWO9-Z9i=(SR zLRK9uMVKK6>^T-8C$uU%3oc&G)=N{-P_4DzG%(&{N0QvA;taW;GT{WdEm*pA$cp#~aC&cv%L7cwtrsAuy$5#33d&?xebDRPx}@qxv-L9%M6*Y6m|Lvpf8 zHz)*s*W;RA6V~!-0kj2fJ=|8f4RFy}N|$3;T2*XgOE8%AYto4$p62z_tb=WTnr%DF z(KT_TChEazsR4K$)~l+pBEz!4DjbOnh2!?Zf7grTUwAGXZ;LN}97VL-Q1T{}spVv6 zi8KTs`z6W4NrORhj2!HggWtJ=wtNjL@JnHIO!gSZ z6vzI@?P*k!V6(Cj{I>9Ft9rkuObuFf1uq0W>i6k6f(L-d5n9wwyCwb&iE5EV3vt5s z=Mg5`Nwj7=r9sp~Dj#2B=@4>5EZC>Fz(i*!*3<27^HXeWOJlG-XmfB`&e>wxWHqV( zqKZs_9iG@d8z7B`tzU2eN$~vhYIu@>Qh831|71>$TloEgUG6>fA)bUi5%RL%x1 zcEPWpO4J?6T#WYQGIVB<&MT9-7%jQFzn`4rsina&fu)Z}X^yOZl#7qYW3vEY2vO8 z+(~#&@LaG9tVZlsb)!asb({40KI|Ku$qwyTx04w#Hvr&MsFNu?N6p8zi4n=W z9*%2(jJ|KQt6s9H5-c5ZFUQnafG1 zQib4=D07}L(=S!=h?f~s0}a zR4$dlv0mmljJ@_>%ma&P=4yfSut;<+x%3BQ(Gi*nAwl zJ8}N!N#_4j+QZiOE+$reTA)*#&=niiQKYZuCIt6z{ztI7?U0(59@zr5d9XrY8wf{iAkf2C?nhOpx*Y3-fa5R-8Wfz;;7sO%LikmEsSGN-ws9euSb-_#Fy1QEA?#J+cG*|0~@6i^WYr%G@9bcyE zI?h~N349ebSAT&mZFHS0Z@rEu%US4G$wJ-u&HZ?cRViahcE1M^Aym?4y%sQN^x9i_ zB=TAUleGk65Cn^v4$D^+NfJ*Dbf^HwCt2z4cAm*}J0O)`f*tN4=zsbNSgO3RW4rpt zT*B4|5jK_!Nb32dz0CRL2K0OR6`2hJ|CLKvEPJdts6+N@_B@T&Cvr~*cix1w}L>yb40ho6J# z7ob3VI>@r3{s~lPiA(542ocyu9VA%&udQTi@Rk*D(7pfX775Na!43)HXqtWB8X}Wf zO=|re|CPkwjSbnCxnu=b0|$(?^`K1G|8tsX+_S|b7i`##4&1701y^aSX2V^~tl7}6 z*|1w(&m3fftZ29u{s6S9OOT{^S&t^syssVZXeHH9G1MFwP(&e6&4gN<$})BT$0)#I zAu*l1jQJUZLo!ZvH8l#yq0&Zs(`2wyErYlc7RD`X?K2rZ?CCo?c{9k+W_J7<2 zV($ORPY@HVzF8^q5-%QOnk)yX%pHIB_7eL!T9a&ent7P#>nWO;QYHGbyb?Q-i?k9unj?-} zj8|f>@JWFcUFh*8w%h_&VsBCisWEdvf)iY|oRq}W*$m3tIFT%t5j~0S9sJo((EtM_ zGrN26VT4ftmYgN|i`ktWjp1IZA~)^sz<&|Q=)*(r&_-q)pF$lhv^m}QMpg6!44$Qnd|z5S$k_N&bA z1n(1P8Pi<$;@!Z%%x0qS_8Fb;dKWyFiR@*o6R_#SDa=|>y%JuvN=gRrknH3J1z#{)!pU|~ek1!^tZWlno=>mk@VsBT|bpDkoGKWyG2>H|mDZ^vW<&1m%Q4Q)G z9gV1L?n5BuH#!ASMX@*$Di+mW^5HHhXGlMtZ;|99cgm0f+^I}(hd$Fbs7wVb^U4hb zF6BSaqXB%+jHe&u-5uf|CchXWFPMkHMgb<@vSo;YRt6lg%a#=i z!I9D8MDq#%lbI|Pe3V(8D6<;6cS=GC;IiMB#NcHDj&u_M_#^y+$%+!)f8sJwXLKfyp7|i=k~pHdw&{K*+=)HfJ2B~ z2wkGNJ6;o_juDi>pb7rZ3_%SU_V0{{w;kS?_9}SwNf&GrxckPqPo+Ot99YyyhKuRQ zGodA~qhRprrGydVE2mFt$W55WHL*z&cYQPg>P1A4?-WROuD-|AZOo5xjD12bY22!= zM^s>Qi+Pi;ZWIwl{WI>D8~_u%M>^0}6+}j^Ze=rvykmzq6fx~hoXc%Zyt&vKA4~Zk zqN!^Hb*u-d`;IP)n9(}oOo{M6ECf*r@=%4JMhd8XWjbA8;fer=DurdjFzPlV46nRU zF86m^_`pLTa*T$)8s_>mT;lx{io0)WY1izB<+z4e_@2QTJ{*XwJ6D(N3|9~CClNyt zv86v2vS2K2!0H4PR^SBLv}6vEjmWq}#88P?ayBBiWNM;MrAqv$z|=SpZ2ihS-MkOF0mhBDKIas#0pouEv&ZscEyikb#1Pehmo z^E3wvAEG&=GT!Du3EceVZH^y+u5Qh->3G9Bt{)`o8m>0Y;pI-Tu9xGMSd0>cS6iKj zhV$mUOy`{L=A7Ze_8=IJI260Y00~zQ&wx;SyTR~&65$1Wh6bGF0v_N3_H6v=73L<#ecQShsRU%94D^*X8J-oDP-crvvP|PGm&J+LcaiO+=xq(Xj^75?{ z+Qr+v7E#iOMhe59(4V~Rt0@pUPGIc8(FG^88#V*VVQso)OL!MnYMURq>4(EkSQ67?1a1zJngk}^EL zgb0EQHxdQ{5QI`Zu?+KXEOn_$^f_6ZwC`^d$iN(Kq?f-y%EtX$D1f221{@UF+&h%2 zX#}KKTPCj=NE)dgmTLfR%PIE~Ggh^$t^wa`I>Mh4k@qDEg4$k702#R5g(p|tYj)V% zbn5F&HOG<)u4OI8q873msZVKmv!RriNOD04dXVZ+6P}2RtV+a@&BCq44T#%v=0ifb zQX8)(;VS$o6J5eFHVLR$Z7YkxW|8Y7tLn&HucD9cPpmiZnsY`I$VcaItZGQ%}{u0l8vNh01w@-W24^N<_q(bEWl&3QHrBJD=CGkpG3iw?yuFT2)_j9WPhT)ZSb~hZ#%qy)?S4v z!0yS+ixowD;Di*V_Jh@Pq#slrLsH-L#s7vJ?g68jp;cD+u2);7RNYKCxSVN~KeQ_z|??!!3nJd&L$iE?s0e;=~)iX8hQY) zbhVv<>SABV|HB17-vgysPmozqee@m}R9g2v5E1`6ObyLdNNOo~iQTg9`~5kXTg|b_ zlA6w1euMCIP=Oa;G5euqDnC@=YakNVS{K9dB0SW<3lU@3C1v`hm-!&eQ${O%9BW&^ za>F6|$%vr$rdidk3iR0vZkvod(ik`ia$zt|l#N*f* zMUp0h)L{dGg9%Pa>kYN!{s;t5ZTYrg6tuNd&!K>W!Z<58uy~~4 zPmhj3ikJtv^;pc@LjzH8-M8iFbV)2b$_$nmp}dNXCty;}uju#jJE6%G>Z{Fs}{FYXcZam|+0}aq=7VK$~$tHq@e)GCNNoWWY8c`;bP{$GtnC4O5l_;V<$~ zE)dDrrCS5*AbS$!ildG~GIDXXK+g6XwxS_n}sx&8bb z0M@-RbDcy&+9sYfJ_oPd+blUq& zJvSYWV5H>M zw!gcc^^F;#C?8_sm0o z91})Cv$UfnvDfbxzYTQKnINhPw<(eLfyfC$1YfJdu?_!dhHye=oy|EJW1(>eI0!6C zeZQ3W*VhXEPOWQu-A})oa9z8_9WyNd6hRkL@8NwZjgCa<*zM{(AtD(g2Sm)adty;p z`ggdasmSN6YYLpTsdFquili{Dp7tt6ajmRRyu(OFZQ4=J)M59;TwG<e#YFM%mtvqEUw`000b}&`i5ibNnL9(cff->3p}6I*WdNmq{0mBQc0k_x)}$8Vlk}09K#Bf>~1V0fSfix&a5)=$FeTNd}a~fhEn!LyMPBb2uD-a;( z%oqCD8(qh6{KFjILkXETlC^i-~q~?iB~$F+B@)oG|(&X3dcw&JXRqLSsr(#2QRm|(Uu!+ z>92U{+=Ybz$VuZF0`Z%8ngWFuQ&d2<1q?2%KYMWvD)gclRA?DqHIpqHIaJ+whe=Lyf#$9}YI%;a^zgSN>x1S{J3e=tLjm?nQ)pP}O>TA@ba1w&r z%M7n|9|ji+7A{}1o87wZ!DRx0I!r>`y6!P`-5sc-nlK#LbFQvyTOe|i8w;F@GlV-B z!C0B#ab*nk#>RkI(_6OnKU*^b#m$&lJO>RMFFc%_$D{S*80LE5P!{R|Etv0FUlD!8 zTh#^~vcV+lbM24RKj2B+&U8-3j?GG3(6 zGv=`9ks;*4bb2O-zwD8o$%jYJ7();5D~oSob{57U=oO3a>NV0@oZdQY(#ohZz zSfBSRkEA~HJA1E>9>cx$x%Wz`&sa~v^!g;)C#^n{T~ohXeI_5gJ_B@pV0&W6n5Hj# zFWyw?MPvT_pAf=}$TC-#)zQkMQfJRCga>b@4PvrFJQR#KnFA;K8j_94X6$3RPcZ6V zi0wq0xya!)qhRXwLeW4{w45|V{e=YJ6jtg5Z7~~Y?}0LzYqVpeFD&%h08Bx(Ly}^p z*Z?7KL8=ofE1j7kR;4}cUcoJ>jwcaVl^1k)lqxm#HCK0}ujg}ow&zNH-DQ2cx~8WC zQuhJ+G~OiTt{IIKWU_@K_OTp6Bze4HIxJE8oljN|#u_bY{LO6*-R%$3^99rw`>WYz zI21ig|GQ^;#8ghDM_bR>X~4YY@adUzWc2hq2t8uGrqUx(N6er1VG|qyf97@c%pb83 zQ|Zx0vcowJYYz4_)_F`O$$TbK24rzi*DrYi+c)lki*x7FbBuC zXs{sS(FYjiy03@m@tfbkI}&=sUX({lZ?U(qm)<`d7QJk5z7Yj_rM-Jrp&u#_QzjiD zN1yT*9;i90UQeYCZJr{Hp7k5pznJ*)!>HlrT9$6$)8@)ZVYMhmY_Q$E6a+@I?~t5D z)kZc^w^@jBO81YeXQ4p!89dEU0JTo5JX(V&WE{_;{M0?6I^$bl+d%d6{+tV%)f12E zPX>+Gd2`b8s(WB314h@40t4l^<1z3}Yi5mxXAkW19yIAP#%Wjlj-+v#T&4@9t_70F zJWO{C-N4fTJTQdaN?oj}x>I8ZMw%q}cGpapC9KW3ftXjyP&))U#Yjix6EysWtAbJg zxKyB$|1k|YkC2_h3UIp}7D_u}VWEf(jL{q^`I>XUJ1%pl-bm*-Z^a7pnO9Is1eVOX z#r=DYvSl{lh8ydd2S0u17X2mFuCEdb2}LVW)YItO z06VSGuRs(sUP>H^M$bf}%L0U{2Dz0GgIH!Wf+^>Pk}P}%^>O7%7+0j>e>w{gx>Ybk zS8yj2oqE=ax|Rea7L?1t{?FQ^e2xCbX!jl{FpzR37nbwMo%RP zW}1fH)vWjddn6`iX}Cs3Qv@9Ek4oZ5-~Y}_?)_Tp8(2yFSZBS)3)1p4-Cx@gu zm05K9R|?_%D|61;i>n=%z^;||ZA+UR945mjVfk$0D>(2E3OtYNs1Up|Q^MjjIk)N1 zZ8-b=ZbmB@ZwZuk<_RwxELExF+L91s4JO`mtie#X-;|7P@oQV^Rz?UD}aRC61;o7CV zKG80H&Ge1L5&!rv(D{+Q5!s>e@OLlo=;3@^p0p=-3&Qv001cE5ha`7a%Lz2k(xR(% zsxc1%u2M9585YyXLm8#+01 z<7HKgj&ITNa1h^a4sX|e4K;%QoKQQAvp6ji(A$dJNbn3iZ)Ngk2AtcLh!!2u=9KOp z$2Ct~cK11LOW8D(9<>F8s;OhMz9O99xa!!rKM0^)E4=I7j(RhMG zhKz-WnqwrMn?6i*}8?l@?=LBXxs};+z;hNp(Zg_i(I~br@ zIa%Rm#?WtPAsHh$Fqz~|PjaW7he2*b}FBm3xF-QfX{<$b3P-VdN0`~ITtRIYFW)2&N zzn<~NU$AarO^_j2S76toJG zRCoqFNzU;pfBJplWIbn2Sn<=!jM#Q)DzvuN1XpP_|cw#!Zj)$dpwMZQx}G~ z#KdW=)E3`s+4^N-CtljX9oJ+jO&TOu_ae5AjAkh$rhiWY=l`zN{9*q&1pjAyDdNyU z8%Wx~Ka?Tt1RTEvM3X@#CNTzpJ)Sv5Vt*6s-^A~?Fu+;`lB}055cp7H3&L zoLFQ8o+K1!gcw1cE}s5;QOx+V?C5Z$g*WlZ%z;P%&zM|GNbMXa$8<6i0?}g<$qbu$ zfZXQczMiX(EXxt!XmBj72JBo_en5&!43hZtql7Gy8?M$bikkDn29kLNRn{8}q?0tH zGgBdbJq41e{3UZi7-~r9@&;xKK__Z3AL2Vq9)en7R+}Pt!&ARs>qUO0F7>O_Qa?qh zR1ORWYG^iZQQA%5z}(cLQ&H5BCc<``j9Ye;4Q4mlTVr+0%HTzgLuI*4YARReh4182 z9@c0k9=h1fLuc{9k~;)_>}ZY%ila$?BfOo$Zm*S!?7$~YbVYD400l67C+#v&$l1#w zU~9!J#heKP4+&qSIq_2HVZbLPhAd}7&f&tBo_|>M>!HoiKlt$AI~KIA>6b$jzPyBQ zm>uO+iQ!FrYED{*=A>9{5f(W-D)73ohJ6@Zq=rjyaroiEudN<|4#GvLLx=!6HoK%q zj=6ey$N2lPQSHQ71 z=DHuZe)l*^HPm@U!)M# zfa>`S6I_q3+k<>oOfFes5de{4BV5f&qiwVmpd+2a(O9vmBrbg|ljZmaOAUhON)2M_ zWsDFwNGXIk>oi%>T-M7eI8|z}$tSf$MIzd_wu|#SocDB=(Wj~fgxueYEgQj>s2M{- zSIV0(522Y+vlCNmrpG3ZGHhay`u;@_vnV6X(M~(cuY2l2&WXsEKEvBMqT-lm4yfpH ze5N6dHErBfscRSHNqhCmDMW!&{;~U9?n}_wtSb;4##}3sx!jtVk=>mS=D=V|uJ6cg z0Wf}m&0I5fJ2-DVIB7`+4Ba0X#_-px;1=?wg|704l%)gt{IO zO~V_T*@ahFPaD0fKJ?ZZ%AHgZ4!7NWMS3U;`PD19$7I^RyJiU-{=0HQ{I&wN> zRq|dBVAlYw<^_uM*ngz|o3&1Anedi&BEc_EXO_*N3~Cuk4(qd@?g=_h5z^-W-QlU8 z;4$)u;86wQj89hbOwDM}=sALe`31Ho!W*&@0^&Kb$4G9c^h?gdTs6iMeVs%%Itz!Y(>&1= zC3>T?Fi#!pi5?}Jz0FxTT>aS-oq=d*SXLDm*A#IiLU%NW6~8L1 z|FXXPHD_VI`W4Dp(M{82^vnLkcLA8CibOYH^&Vv}@RYSXivq<>^;_%9ck!I1+?EL) zWJhiQ0DSHXAAOEiz>8w%_Eb!6R7B#)9usfVB}es`I1ho9jJQ>PghW{M9J-P zJA20V2>Fm9Coz|?6h3y(bvMTZhC-nCqLEC|At#_H-aul`BD*lpxieF}<4OK}k~evn zb7z)%$&=icl04kGbF|zS>|&cR0y?CD*ZxUGit-;YmtqRO`mzBJEMvo%`qh_V-B?m$ zg=IXUswQniVsx#RFWhpdFB&$CQ7``_v5a>P8R~K=riwr!f}D2H7FzlWT(=cIPR)8d z($te1baSPF`BGmGsl^9+i(iYhExtmSKF)EZRhn8Y!~tjc ziBSD{EBtP2M@~ilz&dGLEsb^B7BhkoQ+MksYepNhEWC}%)T{4dtJ+lIy75 z7O7a8gNYpHY!jx8`^8v~y_gS07{3%Wx@Ix<33@TZ?!)V0@&5v}#5#9`3pw$(@z652 zp#on1EYJJ9Fk1aG#G|>w!V#_&WAzos&DDf`WDCAUGp1QjU92q{0@$|>XOcnT6{L`I zKF-3KW8qEIKbDaR6ASxa@t-ks!D);S$4CdQU&tu_`d#w697dW5?6<~06#1mNP54-} z#u%q9>`aoWkI|)$hp>NPlN~0%uHFuQi3Z)xPl9fB zwik}Xe^f@ymn8}E;pb2036j7YX z_rc_WeBztqfd|om?y--3=k|y7jjQqlbxT037@HVf&droq6{uV3jrB|Ho{5kh<5!Ebxu`Vai`e-GHri`3UBgf_Nu?;nKxAb%nq%A@<9Bk=hTe5i9DjodAE zXj|a^Pk;isjs1k97|FLHSAwB1sqCyc@6tggUa`msD>J@T$JDqnS@AVG=0|SK!1&K~ z%=g`xocLlLbEz9MIDV&&3A!=4@d_Ptx*IbzezlGn+7KB0BnDuXIT7vo#(&Z znBnm}9rGt0Q@^vmY=k@2iMhE(%Zmblv^JUR-1uK95jg*pj2k7I0ddh}+{ie^6LAY& zX!-GHbcc1U@)ZXNAl+^FZ{zh z-@dsCIG_!|AkThqS9Jo9yM9IZI|>v0;n(Uo3F@6i(+GWxVSiHVQ*XMH6Lq>wPA+6l zJ=WJKJ^5AVCu`d?KgSq)grA33-#51ORNv(gSi@Iuec!+M2tzDGMp;mm@5J*)2#UxSP=8syQ#u)mJr2d}X&Egmz3mG`{gzd&h-9ShWgnW-(kL=csfwJD(rp?MdtlPJ&4QuiQaL1xBtKaJu+uv zWX92%*8=xnfKot98vx?fni!dRJCt`EZ?Z!h1NR@La}U?Kn-aMJp>4cCXcx2dk*&2K z<3_r@cGdp)KQ%}Af@2n6X#6l49>DOM$?!1@)1ZZfF#oX(KX1ZL{YIc=%!))zlZkN> zF}z`lc@`#OT1?E1i5MCh%u{Y+0_*BuGf@~l4Dxzjn#f$E66IP=%*lx9e)jz*FDKeU zZ}OLMJ>3_=7N*~Xl z4|^ETP5=Rkxg7@`4rn;DkxzRTese2I^1cJ=>k~D6jx&cd-n@Y6p$us3!_-GS?B)(= z>GDkY>v7cNFzLS+y# zYonHJzz)dxC#lGXVbFtqB0W1Wlu3OLkDeI^p-0waQ|XbYBc^A}kc0iF^fF660l4EF zZPm3)d9_H|dV17+Eu?QSeLtb^ z82Wg1cHBqb2lV|17EQ%J=G71Oy7z0wb6GTeVoBpe2>0u^v$J@GyIBr`qt3* z0)2cHpyH48JxAQ)(&Gd0Sq2f>UT}@vneI@iA z3)K;yK%ZQ!Ihwu##*L)!D*A@e_apjFqK~)a#B=C-kUp+nRQ#O2{aDMWc$U7s^lhMz z7c5r9==%$OAJeyszW=3fCw&8tf{&L1R^-yRj=l@%dzQW{=zEI3o9J6k-+lBgq3;p; z>gao#zB}oAfxb%mn(3QOUn_mr($`MkRrLLnK8wDu9}V9{^i8Di0{X6}?`-<+pf8WU z$LTwPzD@KEr0*U2`qB3}eO>$EJ0T0cf6zCQzCHAn)As>=3+QX5?-Ba8)7MDfM*7~R z?*;lkqi;2RCt&Ut|2ci5=zD~|@6z`GeLteFmcIMxyPdwx^xaI~pXr-HUj`0Z#HY}A zB7K+BS43YieY5Br3*Yp4^QJGnX3m0&D`wm@YvzLaV|_QynmcRW^qb43&tEWW#;w!m z-Qc@n*36ry&zm)QVdbp(V{g3!$zy%<7tEV8_s0LPy)S`}<0$iONxou-L0B|;R)pRyO0_tgbUyE8oLn(irr5gNygQmM zBc2j|r32RqG9}k7QjC>i+3{4WJIcMqth;X$QaYZ?xLq!ka(+4I6E_5e0IhA6N z8!fuo-eTDubxS+b`HJgQ{46XuBc*h~RfZ{7J^7KnyK=>>w|A4XSNVfuUL~JRG>1MowtCAYAFj_RioLsOo7vzTXu9Not zd@hrwoa*FlcT0#_6__DII=AGqNLDm#M{%q{Xksi~9CZg(F(=bhC}p>VdVx9+1Y!9M zstnO-qSERuq(|LNV_tdC_sS?{RifKV>CA3al8zEi98Qfsvjs1k8_Bt)?tFSQa0*@} zaH+_$bn^1$^hMgc*g-8&`RXm|)8GtO%4M(ES1Am;CDeujNT!8N&M<03wwA&HROd~e zss&POVXM?z9Pv;P*=&@&+nq>wS=Y&oA}*>2y`<)YTwa@_e^c&Y?FzVe3SVP$ke>U?G^|)y27M z%yskVK8#8fDJrfN)V&aqVc-_Co5$TEDj|9gDo$jqg!1dJASgqPmjv5$LQFb{LKH_4zZV-`XosG6~RIA)Lnr824(WB0@p9;Lg z_tCZr>D|=oJBrzUN^ExtHqjt*K{;J4Q%~#^-F;=1v2E#cW(@3Y>0tLJbb+~i7d7`> zaT}`drmTx9RYBIWC3LqELw5x|5NeuN9LE{xL^rzKL)An-x(W5Lx7c0D=QXBC92e&_ z8l)}|+?2vDz$}=cJdt-*l7{u!MoLE1b;2$0LLP!nS5;;&U!l&b-*<~WTL&wpk#q)$ zRi&8E<1|3l>5iqxa~@q|!ot-j61YRR4OLB5x1q{}dMBJmv=XSG$&|fP8r>seKx=lh zC}Zg*NufiZ2bfBF2*+h%1pQbrwl!TTs-h*OZ79BNZn2`eir%tYpd!%KhR&l`+=NQE zc~1pr6#ay*ZiAKKf}+$ej;L0JG^DBys?$1%Q<}w9wFBK1PHmAYdEol!b&zT@M12$a zD*uCSiLPjYPKxfX>95os$rnlhiAEKwB?+feb+qcN;L1m|j(pxI43JP}a=nngoZAMX z(`|}vqwS6$GuzDT7KdHpc}OkYN#MeP+N5i5*&7|ryR~|>$zkS)C+nZ3mBb9+uR96T( zU7enX!p(+JsamXWbI{UIScpzln_41OBU0&-+RlxJI)m*VcV$QgU-&x8NCmD;xG@UD z_?)Y{r`pIqQ~+w>NMs52I1Ig!n=V;lBl$`&)>#=r+o8;;89NZ*me|#!GLC zb*FQAHybN^v672KxZ`e2-wnk^N?sx6*Y4lWX=`sgH>PN@zQLZYvCLRDSBg}H0%g)g-^mo0sy>hB~x}b=Uqfs4jj7a zb85=!mq-(yw>#%Ls6x)R^gd_(03AJabkgDU4eCyaukm&HL^I7I16nDDLWw1Mx^jV^ zPfx_w1rGn@B=ynVoLd~)G3YcXDRixhhMXh0#oa|*N}ct5sB}rvBz2U)x)h-gMduqc zZmVLri&1y13o7qbcauxi!vi*T6tQ)2NBRP13tBP-jOkyhF9;mm0Pc;Ufjcj% zmup*>TUgC6c_U~Dh61;*7)yefSIkeua8V1&s?u2TpVM}B3|(?8J&Zd_2aR_xdgmDK z!+qR;4(IZ@^28xyXg6YzJhGY1gA3-QE}^(s#fn}z7F2xSE1^tc!xOPEo(0mD3l`%@ zYBF>ev#%U0dBc^UTy%pVR=~C1D7Mjjk37BQs6Lb?V!oHdS>o;`osYrPaLL>47I9{W zItDt2vhHwYbO`m+uaqS$QgRYlGfN?xFWNq2gfwWMNGcxk==AGrX`?o5>!7AMVPUOL zY>Sy_tAS#TVv_=rYR7ihW!uz$r_T$|;|M)y#BxPc5?!bkrzc$~q+_V*6*pEuX~%}$ z*r@6$O0hDYu3|5BOCCj7@NgONN&%`RVsy5TxiQsb^10y>`dlh+st$Cq(N7IZ2bDw# zVt6E=>xm>IY(VMKXoY%XRol_Y)5U)+KEQ!uu@|H93Ev1G^K;N~uX*eIUjH&fjDWMu9&y#+^NfNVLG?zNQa6T^M*Zk|=?!o-(4|1tWx+K6HP-NiOJ>muV3zxQwzX(E z)H)#QV~~?kdNj396`x-2SNz;QH&1y(g*=2RSBS8|@nxSziyXSn2I~1Mrh|hRMggd) zqo?q_0L|UQC>6%P&Ev6G_LvZ3*y{WA7<;A_WDdr79eN>-aYP5Bfa-Yr+unw$B+dm4 z9ryOzJM{0lgyXc6+blBeQy3i-{@;_sHjYoR?fK7R$efN>s=x3lA%k#TaNTfQ;3$Ka zz+D7K3E2tvZn#dk7s2gYsJ4)O`(X!`a=%bO0CYw6ola!KY&utH0xzo1eVI zX_`qp4$UZ}qv@psPSd{Drq-iZu9}3wBjJDBa?oex|K8s@>cDaQiv0)Jf0X@I)M4W| zp8cn?e=7U!>~CVfi~T{r>pmi;%g{}1fn!v4qD|1A5rvOmlI581zm z{rlNJ$bK_jY;YXS{t4{I*gu2)bJ>3Z`&-x_VE@JJkFf8v|5Em^X8#TB-^BjS?0=B` zPq073{@2+5F8g<}e=qyLXaCRaub>MEj#l z``zp(*}sJSEc-?F_p$#f_OD}K8N;6$x|rjbV_#j^RfzuMK0(U^_OE2$P*Fc`Td70d zeXQ1(dr8p~`6pRUE2zvvG z!hY@$_V*mZe!y~i_A(E#|I$O)zv>Y2znbL>)$eOrzR>x97t4<`6NlfDzK2bM3?K7MtAt{EaveQox{)I@Yc(<{#{o1 zd|rqD#ttv)@D_Tw!Xfdrdpi6nR``^!!#7yrsXaP829IKzr-w@%3D$cKr;qwM$|se# z`1lzfQf>$6fzmjp=)tnVu~7M+`B#)bwUOl_zhNg>r1u%lojrC__P&1&*5LR!s9Q~@qF6~pW*PktZ?V$ zTK_%{m-7u3I{aiSy!}cYe!3Mt$Kf%E>AC#i zA^HV1AO*eiIG%$I`i+|)zXi@bq+a`0z1~lQObw2O`i;TAqTe732~Mxn_x7u_QFUD* z1uGe1XOafTmT)YT-pl^V^t#r0N*d{%M0&`XhuFa?elvK%-*4gPid)$KH2dFVUw^jT zaUN#;7xo{=*Qckl|19>`vwt@G7qH*Men0y=*w3;*&i>Wxzm5GV_Fu^DVTS!%+5ay4 z(q5#WTgm-}^c&A$d>Z>3*pIWnjr}zHW9+}4{eNKpJ?wv!{r&8Jjr||8|10))^7*@z zeL0`fPx~A`!Twe3zn1+svHwB#zs&yk*#A%Vf6sms4Z`AhD*I=%{{r@l?3dYp75i^x z|NZQLmHmg*#A8Hcd$Rl{yh85$7p*ev41-I8` z|4H_5XaA?{Kg#}b{G7Rt{j=CtnO?#lxzAllRqlu7{#f)Dx-S;_QhkY6(joWRa-T$f zJ{?o)FW$lMeL2HA@3zx*`PT`ofXUOArq_Cg*1PBsc4t^`_7Hkb+tTcwcIMLbws3q0 z4`Fwj^?d6&#wr#kwZwk@;1cs;$A1JLDS;y;aHIr|l)#Y^I8p*fO5jKd94UdNl)!P% zNTr5420I25)pcwARXe);_SD*r!LET0|1`h-#fgE$oEv?n$hAL{RXVPYt; z6*EJJPJvzrEqisU*PL1}qUBUhHQ7KAE+lcPr`3z~N)|BxO=R0PZ||s?6!{cQexjpk z@?R!D_i@r58cK9yUXxnwrDv+D#V!N1gvu>ukepk7tT~T0&8%As#_mKn=I_%INw36t zMsDUsY4QXrj7u=hI7w5uo$4G*V6?t0Du_g{u1#XaOyg4FwK>&PJ)f6rR9DrDc-n21 zwmncs)8vzoU93~d47mlrJTa6>XU34f*`}GJ=rk!wAs8LRIzEKr%jHa4OQnPY%IqG> zjO`v8t?@Y$C6ZtGSmEoabthvC7n(8#ihhlg#l@KPGIV#=i z=Y_fQPQB=WvxEfo4MrCSq15#Pi9m=tk4d#uTCIMmF9u^Sn^V2%jCuvE0>a`>r#guh z*_`3J)1=neI#oHxjm{*k)WF9>>f~cK_30+`&ginJ*TpG7 z<5nx%NVGpH%1?A-6(-GpCgF@B)Ct?hON$`9%@86*3H3n$gwIC9sZI8FQEUgI0+j?_ z)J@_!Lp-3?m!q*OrGUiuYO(GJ6P`a2u9xe|mDGa9i5&x5Nps%RM9MUURv-3eu`ENa z$|SvmmY(EX_1Rbj?3L8QDri=lRr%?NROyGSB_X{=OKbH28ns+cHjsv;f73$3-VrQe z$7*U-d8V{hB-&eanC>Yd38S3Wf&qO+p?vPwA-c*ZXkir=BO`n!60RBm6;h(sHf}RD zV8js3TB5CbwLYRfU`epnFjuG)Xn{70baOF-g|Wp^O2C}f#A&1RxfN|AnTCC&5Yz8< z*6$5fV7?m*%?2mXf(iq!uZu^0qk!U?XT=@8U6fG1n(qLlJatZBi72TZjHr<~6jfWE zh(@xL+xOO7aksAWs!U{|BgJt|ogysud9;u>k2O44i?tIg1U=k7AdO>5x0Lg;#G9<+ z87Jwc7In`ci*vCouuwY>Q!Th`N3P9??iM?6u!0`rY_c?Mi*OmnGBOhFZ=p*$W3iJb~&mhzhtZp@?X`x;s?PVU;LE*MuSp8OA#L zAzG|VqDduEsV8_7LEqa;zo*pi@)#<3c4*Ws%c>`m-D1kH9%(3}ngNNXZ4s?3#jPns z`%Mwb%Zzb`WP5Nop-THULP3DlB_l+fRj^#j6nugQ7-lO9&N0M-c9P!9u*ll;jBzSS zd~n%`sIEO787zV?xm;_z(^-5%A;7Bjuwhh}YrP=wGWZkt9NsUh9pd}oqHSVZ;+xfWz{OSsI z`nk9b?llpCz8j=Inv70HW%v$|Uazel=pesI%hksp2Gyc<-Bl8Is!lfOmbc=(@?tV`w&v0x8lx-Vx11foD|%n76Uw=bxx=nK|1@j4xM3E z()S%RI-K*)q6RJHHm!%`E^K2~>+DLG@N|oYRM&toUjcWaBYUw1>~Vw6KQ$pk&fU$M zWj!tB9(@BAm)*Q<8-0^NFJVPAw3O7jWm&KD+U48js}Rn6mcP)$1uvJ`Ew=+#uav72 zeH_Vo@2W1>`OvCe&fTlf?&(32Z;Y>7L(9||+^`0p+Tikcez?YIL83m}v^VWLw=cu8 zb=JbiuvRCWk2kA!=FBfsD>oD9!RebK&JULN7IA4)Rp4jK@%4sK^63@ZJm=OGs6sFj zhCaGtJ9XRdUd6G$<0$pzmSOdA1*&MF=68{xe9l)-aD2_XvspipUB3cf5D67$R97+3aScuNGD{0M-JZ;^$N+t0f zlEj-=TS;`P^+|i6g}(p5nfhZ(rR02gS&K8j7YhKZAHYPNW-rr`%~B0_-nmSDyJ4GN zX6)R)a+x!Apc#tO|3QDNbEIy5lHx1N(0I`sJFi=@%$ZkW{V|Hbxo26}T7I=`nKScK zied6@`a6fE3aSkL0>SLP6g2xwiW=*dovGy+m>-c3^t@&btp83~{{yM$=WXW;%ju3q zo!jav#QR`#6Q7B1FGorqRD_3=u}4+>)fO`R_n4H}j8@R8z76HPdWBj~?R)|moqjE8 zR9{CLl%w~p*i4UA;ki7B98O->(i8^#9s$)i5NYy_k!VAW`*idneuT<%k{Hw1)8CmJ z=C=(&7Wje3`R6t2 z^J-xMe|8ODs=|;jtm*bLl_12ot?AX(D-8K25>oq8oAZ{{bV>Q`YUJViwv(b6_Fwzci}LG=gV;MZwd*HiADv!S|`)-_YNw z`|0oGZ|QG!Uj4>~TqqRvclJU0J^c{YwTF!;%+2+`E(_G6`)7;AWrfO3vKHD;lc;}juaX(pYo@$zJiKpg|nQ56{F@4n3 zirJP)giJQgHu=e<5B>R;D%59}RgrWgqP2ax*-y?OH_3V6IhDv+sDlP){+n)^M&71Z zAQGR9w$A|isnlc>k~xL6%rv#nACvN9?eSLRDLL5!i^*6#Ik%dOOgGK0Na29`6k_oG z$z=+eCgKhqkKA=MEuElQvE~$bnbd*KOC5A7=#XjpvfM(J1<3LSnGPe%QSbpqb;$CC zaGE?toMj<->n%)cnrY3}y6e5|B&P(?R1R7%NymHPPBAdaPk~Fp(LuNme^LZ+5GMXS z^FI$ve8D6q{$+4<5GKBfvlPgOo&Fyn+|17}fg7biNsBviyaaKPeZdqp*`FsN4#H&L z#FYLxE%?SkJ7W=FFn%gNPwxr&CSEN4|A+|8^nVDrQTlyaX^-P+C;+lASnQ|h2M+Qm z{U)aL&+Q8%zir)Da+ZRms$o{Mr zhxScO=~s*N;o+7*70qu<(84iw@zNnE1ZxO&w=D^92ik zQqx1eiIx2wTA?KN84G{P;+vTGQ>_0c<_i{n+~S*<_;bwvDDwpif8OGonE12wu?-ww zV7_4C@3+cN@b{sADz0|PCzGZw-^JR~gV4_^P5oy%u9(!Go@Mn%lk_1F9D5@&)cK%oj}hr@&R==n#HYA&pgeGM_$? zP3fOyEPUV4C;KKQetbwP%rIZD@KYAw#KfOs{tuWhSomiBSN4tbOZ?W1Ht;*<3l=^v z9}V+wV&cd6BsZaMQ2s-VXsP_#b@UJ zRQ@Jjto-^ApILq{0jBah&FX(-{pL3%{k(2d?E6;wO-$*Rb)E;AFIf0-i*I7$%X-jf ztkUOCu<(8QfrC8Czln)o-L1sV7Ul~keX74^dnLY!i9gBfPA_A=VBx29^r3wd6JOS? z=9w>8_%jyY#KfO2Xoc&UFIf18YJc;*KK6rRpK-{y?8gmE_GKOI0p<%9zInd;5NKlJ zPw_h36}a!C_9s~Qs^DOgF!4>S_#EL=gwI&`DNyJTeo7&YiSO|G*Uiiqyi|UQ`Dx}0 z7JkyON9i{)*_ZXVuVcPo;hX6tzKMz7%Ij{wzzrFK(nIG@u<%oseG?OZmhC@-`GSQ% zW${g{?DM+mv&24Q;U_J=iHSeM`UA`tEc}$kH!<;LeRh%gf`uQaA2`VC!ygk9U)FKI zp80}FpXz@Kjt=3c6w+9wpVxa&OZpiL-^?%BH!<;LUHJEzFIf1dJ>r{~__BWdVde`K ze$_}X@l8zpd0uCJB1R)sf5ce$W_pQlV&cns^f>bc3*WTY$iA#wPcvVz@Z(ncO-%M> zefyQn7ra!ytb@N<($DMSg+FK6H!<0l_440kzF^@`(hnTuQT|O#d|6ljC*}(#eX4)$ z^aBTZ#5XbV=U%DA&XbPO=T9){6F;uSA>YKrk5#q8I_3)&ek=XJK_1yRG4b24RAQ%_ z`GQHG>`!ZP$TzV{Kl4+Pe#XL2(hnTuk$n>@`&TKkQx*G+g&))6kZ)q*Ct3g9%oi+t zGreTr#Kf12?&p~=Som}F0|$A;H!<<&UaiE=4<-MMNuSDZN{d6jiHTo*jaImi`GSQ% z*P`Wwm3;#fKXt8^Kf-*$!k^dT(7uU@pM0HGIN?}b{{#!aYVl1>{8{Fo$$Y`WPg#5u z6TkgBt+0jpf`uQq_$DU4&;0Go7cBf)`hkPIKKwB;@#Ak$V#i~?VA5Yo{hw$4>zFTC z_>(&N(7uVue)Wx7;l0ckEc`i(Z(`!7IKtbQFIf0Vi*I7$Pc#1><_i{n+~S*<`18!C z4*;p_4`bo`7T?4w{nu-SCo@0ASolecZ(@~x)<2v1(-vP9JmR4E`sfci_7wjHjV}~F zW3fM_#UbCs#819SD`c53SorgXJ+g0N;>T~){8utx@O8jfvu*MuzBq>wrua-u@l`p# z=NzZchhX8SEWU|}KgaxD<_i|Sk8uk+2$Ovi6F>PbC3Y@izF^^hjDFxCkNARJ=+k&{ zD}Ce`#{_Up{nCG?Ec_)4-*4e#kB{=tweV#YzS_b!Tlh;B{;7o@vGCf*N9|LtvN~%j zL(PPB*3{ok&^K`xaHH|N)_>HbX~?O)38tv2zdF?TZS`i&|2p#p3x9fB!Z-V8;+vTGu@7qg(NEC%7cBfqEp`YK-^9e9 zW`2zMf`xCkPvV=H_){O&1~xKZu<%WLjqJC7MDw>XU$F3Jt@N9i?8^{l)OCRXMDF|E+ee21~{Qx@OE#80vQivyu6NNuT=flop446BB=)`CFJTSop0L-^9dsKBE;bW4>VFKilF9E<-=YGV)$y z;nxG7`eb|$u9src`CqKQyc_yveR&^nqx#a$>3#f@^!XMn>225M!tydP_8SHR4ZdamY6@@snTF3SXD>GhQlxj`i9^A)Xd zD)R*k-?Z1r{v`7^F<PUMhc@`Ma4fc&YsOSGE0DGhgsh`LoP_H}eGx z|0*4QSbt5tSpT~p@tOVa7lEn&J>7oa{WWc%9ew*LFq&d4_78Rb=2?F;^92ik+DgBP zss2oTT`OF|e8EfQC%>WjCFTnj{`Ho96E9YNe~R{?H?b-|=AX&@DaOK2S$q={-}$yy=wQBJ;rkZf#KiZR zzk~ULg+EI_aFExBKPD!A{0=2{b~9fv=~Mqbt;HeV#KfOx{wtU-SorN0-^9d^eOD{I zh53SoKV$JtO#C_KzmNHXg+FESO-%gi_q4)(<_i|SZ}Cm6^3VLQO8yxOKV|VvO#I~c zwZa_p1uvC9&HO(wU$F2eE&C=W`|%%Wg=3$h>%U;(o9XRCpoxh;#r$V7U$F42I{L8w zn3(vn16tvE%oi;DDT{An;?FR@kNJXyU$OWmUabE~AwIMJ@qnrSIm7C|Z6Z(>Tn^FyuhAoB$azun@SnE36?KlZ8m{0SDmIeyrOKob*x>ZjVkGnp?~_$kZ2 ziB(n`OHDgCi~w89n47cBfO7T?5+rT34okQpb7XNjm?6NkrFAGrz<)G4YekKZE&#m&%`Few_J&h3`}1a1bW@ zCMNr>zffZ5V&)4LzM0-e=}$4g%zVMZkLl<``z9v)Rpw7JU$F4w7T?6gpJDzj%oi;D zL#4mh~eg#KfOu{)5aHyi~q(P}^S~4I-e4qL4%on^={w(uf$b7*|<+uMyCos!=!NQ-^;xPRtru5G+ z{}s#^yi|Vj&)UG-m@jy#{5j_TEAs^}mGA#W+rNYPf|ts79@YHcGGFjg`IF3l+%t6j z6TDP@>@jVBJ@W+%Kd!~$`7<${zZCP&XTD(JpJ(w+Y~H_Z1OFtDWc_iGv8*S4BV$?L z`+mlh#Ha#AgCidSrd!xr}AK;1<@G z^?H}GT-M)>GM4ppR|x+yZSQ*K%X+t47|Z&#FR;F>NBa)TV_D6=pRueLTaB9!I-j!s z>r`M$zpUqqvs~6^UCLP2OYLTTS^u<`<+7gX^`bwf?f(<&%le_)8O!>ghZxIxo~NzT z>5=t0=P;J_HXV#*{mclk%1=StyHeyujX%U#)~o!8v8+Ft7t9x+6HnFg$@-AtY5f-v8+e9N#s00@^Qvh#s?UO z^Z!rN@ymSvlNrnW{IeL#eEWXJGJk$Z2~s*GiR`#TxSeD%*Tmigy*iT;GTNulH?jmEEkNrl*GQavGjAg#`tmwa7$KQO0wkPwMPiHLilQ%P#`No5y zU)B6FW0?>92GPG#%Remgt2F)=W0`;Z8(^xBGKp=~nL0f(U-m@CGT-$yVA7ZQt6eOY z`KTAOT;`XKvs~tjzKZ2C|MOjpWj^Pp7|Z<3?=hD7mJcyb@eRQ7c=4^;6XQ0 zvCLOYiT?GvJSGI+pz#fiWq#m?fT=yjZ`ATnGnV;wUu7)w=f2N;neX*G#xj3v#d@7y znU8fcFvTzPtIlS*%vb6WeV&ixGM4!U{D0grBfn-X}cFa(O?ndV@~CjQ2m8v5ddAF_!VvEsSM+ z^u>&2ymOD}-_7-jv5ZH4jIoR_euJ@$7yd%{KhykG?OeW$*D;pyrROu2@uC+omhqoa z#xkB$Wh~<}?_iwzg|_!e#xj2LEygk)@*7|(Um2hHJ>eCozx@4xr0Gf-=?1vUW@h0ypPjC##4+R13m`t5M_SN$a&pnl~yq|p@W0^0}!&u(`T*_G9C+!vf_jUTNWi0Q@-XZ#5((;cmmhtE> zGM@jQmj95k%rCv4v5X)8iLuPzTJs#8ADNH!494=l=N!iJ{-~R=JfC06xRsxG_b`_6 znyVPg_{m!s%k%IwV;LWqVLZ*}=MKU9b^h*TEbsGw&sbilu0BuaN1nG%6wKoh>lw>@ zj84JN)A3)zSmry7GnV-y*D#j(6gM-L`DptY%k$y^#xh^>=Zt0k<3YhQ+WzXl)9IJ_ zCMPkL_kZUxmiZt9jAedBPUQFK_{JH_^ZN~q<$3zUjOF?G8;oVV>@LPK{&0}7JkOu7 zk=w%`w7qu5GTxP7EaMNCF?Jr%`X$Cb*PrVc%XsTMg+HzJKg3w(-+rF4%xC;2V|iY_ zi?NKK-p@GB>0SO@H3qy)$L=^!w(tfEZ?^DG3y)d2YT=tK{22@X*usxl_=HW-^scvX z!otHA_AGp*g|D;lyDYrl!r!p)Pb}Pwc7^UfEZ>tX9Jg@F!exzD%lWy{!k@G7H!VD8 z;YTgJ_W3G(Vf@dsaF>N&Y~g~1UvJ_6W#NCb@Q*C~dke2RKbpQ%EPS4YFSKyh!V?yL zpN0S3!gpEtw-#=FK{S2qExbkJ<#PTmx9~eG{85ctME|=M{)2^EE>QME{o^cru7w9I z>}q_J*vnh^DviVX`!-AduNvcyPaj{m7KW5>tSa?q3(Eh_3hv_?}L!~#g|7;8QSvY6ms>WgbZ?)tfxA0djJZE7Vhio$X zm#1hPrte$}_iMb$;bX|+UuntTXyJET_~RD-vc@YV{sWf$P7D9W!Vg;b&lYY;sQiZM zKT6|fv3IQErX+PzO8^;3AYOFD7ddJbDXckeFN@x zxNpLJ3vL$f+i>53y94gKaNmQY@6P=I?f~3>!2J;JM{qxeyA$p%xSzny!Tl8OZn&Sp zIk43P*9>wxQoOTcx( zZHDWH>w((>*9-STxC`O#f&Kr4`#Ib%;O>R{CETyzehqgY+;8CShx;wuJlyZ#eh>Et zxCh|q`*{z+Jq&jc?vHSf!2JpC&v1W%dlc?5xUH~>Bfc8`8n~n39tU?UTr1pqxU=A% z3rFQ}@1|)8!H5tWokK3Jd0AG+ij94^Nq^ zJZO7%`jNca#shU(tBG{k=kQVdw!>HK%AB3zUfK!(yY!@sqwaR>Ocbb1JA!cMEb9c- zHlT>+4jJbi`ncBV9A3_QR2;@!h9)JaltbAoBXEXFw1HTMG!tBfRAHs-)~L;1V}>a9*J21-xlYGZ=BvK6W9SFoUh+Qz`h zlHUAlD4oqp6r5M5L8{uY2NU*7!~QFQqt9PKZ%}a3QfP~-!`Ra)b8(x?L`|tuwUIvXD&Lb2Y$LXl_x})y1RebTeMT z#cn&4`AC}SIQ< z^1FfcgAHBoxSOY4K{v>aRIp)NI@3RRQJc?qR))@C*M%ZJtG(^HZ9#VT2EBRWhON2b zQo1y;LG5<5*DLJ~HgwZQZ>n6|MkvJ;x?u};%%eME+AR>L7+aLKjd9(xGqFIkGS#xK z+6+)yoGHo${eF5+1%;qby(!D2i(w6;GHaxh&SYG_9CYVO0oq-F?IV%yMv56#9e4Q1 zs%l~Zc2cFS-^^xd8ZXcuU-TG2bsKvd7XuWutG9QnPpZ}~rAJ5IY*@kSqTAswETg91 zm|CJO=hT*CoSb^|hRPyosA(;b5U)JumKL{Us4QZsrnP`2RbHF-<**&v!bPICjaooq z9Q6SWS~ocEYHJ(kHmU#>b?VIxj)O*OyWNSpvrhYo)ff6mK0O-f1T@YBqFNyP=wWfo zxNFRH^I`UNA0IO-y$+I88l6N8`@?3{ohInfo;R{b95%_!m31!zHg?&@)rfa{ReQ)q zsa@DcuC^uB5VlhucdhF|lz?7dCsA)KrJD&o=3Q(hDpYKE*QDc6dqOP`e*+oro9r#y zqGaBlN=I&`hwl{|%5Zg&ZSkTJ8oTO61;!40QNga-E?rSUczIOik?2v|aM7lKf7?qz z0-Ff-U>oG zqlwCmO9OjL(=sx-fVD$wNCl5<;$F+m;%QsJs*!p;MB<)tU->XStY}-|lS+VRUt9rr z8%?h`lEclms+Nf{&kNk{PRMG3vZ0;U*IUowF%4T{2X4<+9^BA_Y^c__mV}!*syG|$ zDXl(;-8yA2NTo*s;g*nxZ(J-o zB8IJgy^I?0QhUqG!*Dkq9U`HWVRUyYjPny2LnArLTglZ{mUPKFEEP%_3TqSXaH_UF zMItd^R4RETb9}WIsnW?0pF1=}+U>d%9VpYMjH3)UOXRu}UY;@Dp%mGRZorzO#2uzG zAxn`$p_?B`Erht?k%2R{E3Dr8)znZokQj`{&aozs9|!3Hu0CAd>V*Yb+iq40&j<-3 zkCsD#gS1QT1k#C07($hba5#-?naT_QHWWg``e{I2l)2v4haisHSrjdEuUbj7VW6I% zN&|)#kf`#glj*V!gD;oC*TeB9A~c4|LAjRU#&8gni&et)IHwh8pAS)1cL*{vcsOz+ zwjwp1NA~nBJ=ambCuUK@KEY`DY?N|7!s1b0cSsCK~18LBM$W&c$gP?%E z;Xf=_IyP0S9k{mX+hw)Sv3ZHo!K&G))1od$I?#A9HA4B((~P6>v#P<_nG15mIkfD^ z)mB^SN*B_jcwDlrt38_sTnwKDd~*_g`rnq`r~3r!$zBz?@t8}v%dOjiTA9-+P#a7e z*cczz7H|f+M2sz<6(N-HAOUv|T088ELai_a6@+7?eWasN>0;-Y>WY@at*3tqvL5;= z$b6*d*tAXFnOa#56T+RJl@@cy>ZpF5#LQ&03k@Zdvjs%a9lE0hA`dqhXC20~u9d{- z&fQU_y^FUzr=kH7Vn zCV1qHbE7xTQg>>X{{P=!=+^2BUElutm#TX7S@%scvUKF7W>^w?)j%QM2ON2+S$jCSIX)fyHDk}Uq{`@-dMx4c`X4>O$Vopka3;gF#(>TLtHVTU zP^f;!vN<=nHs1-2>&Ux$o^~kr(+%F58#f~hyfr_xhJLtf5cz@v^G&>-BVkWkh-ie3 zSx*RB^o^s^jSeQ#IL|_Zgbl_Q8x2hJ5L?}VkA$03NhHh~F|P#&UdbFQth>CkrZGaq zA*v1Qnb;g6uc7|y@2pfgVGJw!ViC_dUa9up1o9=kXE8Iw>a{mI+vtfwzdh4qdx+B< z!k2U`@aCt{8-UvAJK|cxD{RsVC#s9RFr=1LU0n}7fQtCEs+n;e5*gmrL3LxP_Ry_$ z14n1J_Rd~TaO7oWqZc+rvj;b=+dopl$RoW6j}D4bpgqRjcaPu~ZWXhlH&L0lw8B5Yp%!x7@tgL(E3itg~#ru$BbZsvd0V^SjvK_Fpr6 zZB?z%4k}w+Dz)z7L+FdV@M!#cVgW10OOP;4b#>c(s8BU%(HTIhRKpjU`aGKh@)U#4 z;-YVHcx@Ce8JJtj%Zh4Y`HAjIQ7s*EhB%bpcUO2WABUn@CorQN@1tq~+b4Xtx62Gs z@pqu+WnH|YV$A_sx#i*!K}pf0B)U5>H$CqrJbwbM&|0~+V_<7d1!lD_4KVd)-C{X6 zlA{4vi319f12x+cOC6+-HdMByb448wF}rdq$Cxk=b}bW;;IO3XLwiTU{wC2KiJ`Aj z7e!^VW1wPNrc4=Di|{k?4?t+nvk1dKtlh>z73>m`G>TJKNAkZ~vfM8qa0iq*tQS6WhH3RW2hyEkA(CWNx3EH%^5RNRBew;?n$o zi-+*ue!Uo>W`POZkqw~W>RG#TSyd%WBel9$3mxZj-tMW^VnkH0jb0w>h4e)`%r1I2 zt1Q)g^+DB$b=N_W8i8PJ^)l(a3JL}>p8=IDz&Q@*Izk^A??9s*muj;$N3XtBIGe)^ z|6(xWmO3ZY86qJSJWEwK)Wdn;um)AHmih+K?Mj#Y##M1A$GA0D+%0#{XiHM8NQ?Pe&jut^i2w~Cp_UqV_`O0XoE}xNfhMF|jJ!h!5pVOi> zdy6Apt%o9UFP0{y=|0unhZ5}V--ed&;+C2!ZEybo7GDNf_Jezt(u9s8(Op|$K`Lwt zx!9I2XU5Qva0uE|C>4=2)HjGr3wv0Jz;~RwC!}D0wiu`sw|XARms(ukAgw>p^@~E# zb~S*BzQIBCnHl7OmRL%ch)^}tHaYC2OIhl(N%Io7B=tBl6-&_@^x~#d{{KyZPjUasa9&~nkUK<_3D`*Rw&K5uZx-jagqyl0x5GV68!~& zI_-Yk5A@*Lpk_`jAXQx$YF{CZ%40>Fq!Mx98X%lcrRD{V!DmblO?{=Pw4A66HU zzU$#&^Vzu3d5_8?g%K4QrlJBdhYE*AfyOdg#Ckf6^WhRIS4Les6Zv!ypryN*4VFV%4o@H9}B{%ZKH?9%x(B%SPhOf8hOtn4_!FjIwo)%La(Xw$N}}cqqvqa zlqR+tw`&vybspSkouL9Ol07e9DZ4{uyzJ&M`Zv8{hKGjn>IFBOeEe@_O>)@) diff --git a/release/libs/osx/libglfw.3.dylib b/release/libs/osx/libglfw.3.dylib deleted file mode 100644 index cd20112e..00000000 --- a/release/libs/osx/libglfw.3.dylib +++ /dev/null @@ -1 +0,0 @@ -libglfw.3.0.dylib \ No newline at end of file diff --git a/release/libs/osx/libglfw.dylib b/release/libs/osx/libglfw.dylib deleted file mode 100644 index d4bd51e1..00000000 --- a/release/libs/osx/libglfw.dylib +++ /dev/null @@ -1 +0,0 @@ -libglfw.3.dylib \ No newline at end of file diff --git a/release/libs/osx/libraylib.a b/release/libs/osx/libraylib.a new file mode 100644 index 0000000000000000000000000000000000000000..8520bf7bf4300690370a90ffbe3db6f0b44df34a GIT binary patch literal 1088584 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 btAge^2IMoH-0=UMgJSxWew)!W{NMiplQ^Cv diff --git a/release/libs/linux/ADDLIBS b/release/libs/linux/ADDLIBS deleted file mode 100644 index e69de29b..00000000 diff --git a/release/libs/linux/libglfw3.a b/release/libs/linux/libglfw3.a deleted file mode 100644 index 84cc1d2025c79298bc4b221b245e1445f48d117b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176482 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\a%@ZwaLcOmjCkGW&c%+K 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 OhwHragC4H)lD`9F5LQtD diff --git a/release/libs/linux/libraylib.a b/release/libs/linux/libraylib.a new file mode 100644 index 0000000000000000000000000000000000000000..5a14e1d35633bc2a553dcff02571786d3473ead2 GIT binary patch literal 1413590 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

  • n`stCE5dSFVkRQby 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%0Ao1(^?e2v0XZu_ZV7R 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%0A*18Z21UxOrZM<+g;JW6HqB$~*y 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ů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